Commit | Line | Data |
---|---|---|
e0594022 | 1 | #ifndef lint |
ad8e96ea | 2 | static char *sccsid = "@(#)qv.c 1.4 (Berkeley) %G%"; |
3e5a489f | 3 | static char *osccsid = "@(#)qv.c 1.8 (ULTRIX) 8/21/85"; |
e0594022 MK |
4 | #endif lint |
5 | ||
6 | /************************************************************************ | |
7 | * * | |
8 | * Copyright (c) 1985 by * | |
9 | * Digital Equipment Corporation, Maynard, MA * | |
10 | * All rights reserved. * | |
11 | * * | |
12 | * This software is furnished under a license and may be used and * | |
13 | * copied only in accordance with the terms of such license and * | |
14 | * with the inclusion of the above copyright notice. This * | |
15 | * software or any other copies thereof may not be provided or * | |
16 | * otherwise made available to any other person. No title to and * | |
17 | * ownership of the software is hereby transferred. * | |
18 | * * | |
19 | * This software is derived from software received from the * | |
20 | * University of California, Berkeley, and from Bell * | |
21 | * Laboratories. Use, duplication, or disclosure is subject to * | |
22 | * restrictions under license agreements with University of * | |
23 | * California and with AT&T. * | |
24 | * * | |
25 | * The information in this software is subject to change without * | |
26 | * notice and should not be construed as a commitment by Digital * | |
27 | * Equipment Corporation. * | |
28 | * * | |
29 | * Digital assumes no responsibility for the use or reliability * | |
30 | * of its software on equipment which is not supplied by Digital. * | |
31 | * * | |
32 | ************************************************************************ | |
33 | * | |
34 | * This driver provides glass tty functionality to the qvss. It is a strange | |
35 | * device in that it supports three subchannels. The first being the asr, | |
36 | * the second being a channel that intercepts the chars headed for the screen | |
37 | * ( like a pseudo tty ) and the third being a source of mouse state changes. | |
341dce35 MK |
38 | * NOTE: the second is conditional on #ifdef CONS_HACK in this version |
39 | * of the driver, as it's a total crock. | |
e0594022 MK |
40 | * |
41 | * There may be one and only one qvss in the system. This restriction is based | |
42 | * on the inability to map more than one at a time. This restriction will | |
43 | * exist until the kernel has shared memory services. This driver therefore | |
44 | * support a single unit. No attempt was made to have it service more. | |
45 | * | |
46 | * 02 Aug 85 -- rjl | |
47 | * Changed the names of the special setup routines so that the system | |
48 | * can have a qvss or a qdss system console. | |
49 | * | |
50 | * 03 Jul 85 -- rjl | |
51 | * Added a check for virtual mode in qvputc so that the driver | |
52 | * doesn't crash while in a dump which is done in physical mode. | |
53 | * | |
54 | * 10 Apr 85 -- jg | |
55 | * Well, our theory about keyboard handling was wrong; most of the | |
56 | * keyboard is in autorepeat, down mode. These changes are to make | |
57 | * the qvss work the same as the Vs100, which is not necessarily | |
58 | * completely correct, as some chord usage may fail. But since we | |
59 | * can't easily change the Vs100, we might as well propagate the | |
60 | * problem to another device. There are also changes for screen and | |
61 | * mouse accellaration. | |
62 | * | |
63 | * 27 Mar 85 -- rjl | |
64 | * MicroVAX-II systems have interval timers that interrupt at ipl4. | |
65 | * Everything else is higher and thus causes us to miss clock ticks. The | |
66 | * problem isn't severe except in the case of a device like this one that | |
67 | * generates lots of interrupts. We aren't willing to make this change to | |
68 | * all device drivers but it seems acceptable in this case. | |
69 | * | |
70 | * 3 Dec 84 -- jg | |
71 | * To continue the tradition of building a better mouse trap, this | |
72 | * driver has been extended to form Vs100 style event queues. If the | |
73 | * mouse device is open, the keyboard events are intercepted and put | |
74 | * into the shared memory queue. Unfortunately, we are ending up with | |
75 | * one of the longest Unix device drivers. Sigh.... | |
76 | * | |
77 | * 20 Nov 84 -- rjl | |
78 | * As a further complication this driver is required to function as the | |
79 | * virtual system console. This code runs before and during auto- | |
80 | * configuration and therefore is require to have a second path for setup. | |
81 | * It is futher constrained to have a character output routine that | |
82 | * is not dependant on the interrupt system. | |
83 | * | |
84 | */ | |
85 | ||
86 | ||
87 | #include "qv.h" | |
3e5a489f | 88 | #if NQV > 0 |
e0594022 MK |
89 | |
90 | #include "../machine/pte.h" | |
91 | ||
3e5a489f MK |
92 | #include "param.h" |
93 | #include "conf.h" | |
94 | #include "dir.h" | |
95 | #include "user.h" | |
96 | #include "qvioctl.h" | |
97 | #include "tty.h" | |
98 | #include "map.h" | |
99 | #include "buf.h" | |
100 | #include "vm.h" | |
101 | #include "bk.h" | |
102 | #include "clist.h" | |
103 | #include "file.h" | |
104 | #include "uio.h" | |
105 | #include "kernel.h" | |
106 | #include "syslog.h" | |
e0594022 MK |
107 | |
108 | #include "../vax/cpu.h" | |
109 | #include "../vax/mtpr.h" | |
110 | ||
111 | #include "../vaxuba/ubareg.h" | |
112 | #include "../vaxuba/ubavar.h" | |
113 | ||
341dce35 MK |
114 | #define CONS_HACK |
115 | ||
e0594022 MK |
116 | struct uba_device *qvinfo[NQV]; |
117 | ||
118 | struct tty qv_tty[NQV*4]; | |
119 | ||
341dce35 | 120 | #define nNQV NQV |
e0594022 MK |
121 | int nqv = NQV*4; |
122 | ||
123 | /* | |
124 | * Definition of the driver for the auto-configuration program. | |
125 | */ | |
126 | int qvprobe(), qvattach(), qvkint(), qvvint(); | |
127 | u_short qvstd[] = { 0 }; | |
128 | struct uba_driver qvdriver = | |
129 | { qvprobe, 0, qvattach, 0, qvstd, "qv", qvinfo }; | |
130 | ||
3e5a489f MK |
131 | extern char qvmem[][512*NBPG]; |
132 | extern struct pte QVmap[][512]; | |
133 | ||
e0594022 MK |
134 | /* |
135 | * Local variables for the driver. Initialized for 15' screen | |
136 | * so that it can be used during the boot process. | |
137 | */ | |
138 | ||
139 | #define QVWAITPRI (PZERO+1) | |
3e5a489f | 140 | #define QVSSMAJOR 40 |
341dce35 MK |
141 | |
142 | #define QVKEYBOARD 0 /* minor 0, keyboard/glass tty */ | |
143 | #define QVPCONS 1 /* minor 1, console interceptor XXX */ | |
144 | #define QVMOUSECHAN 2 /* minor 2, mouse */ | |
145 | #define QVSPARE 3 /* unused */ | |
146 | #define QVCHAN(unit) ((unit) & 03) | |
e0594022 | 147 | /* |
341dce35 MK |
148 | * v_putc is the switch that is used to redirect the console cnputc to the |
149 | * virtual console vputc. consops is used to redirect the console | |
150 | * device to the qvss console. | |
e0594022 | 151 | */ |
341dce35 MK |
152 | extern (*v_putc)(); |
153 | extern struct cdevsw *consops; | |
e0594022 MK |
154 | /* |
155 | * qv_def_scrn is used to select the appropriate tables. 0=15 inch 1=19 inch, | |
341dce35 | 156 | * 2 = uVAXII. |
e0594022 | 157 | */ |
3e5a489f | 158 | int qv_def_scrn = 2; |
e0594022 MK |
159 | |
160 | #define QVMAXEVQ 64 /* must be power of 2 */ | |
161 | #define EVROUND(x) ((x) & (QVMAXEVQ - 1)) | |
162 | ||
163 | /* | |
164 | * Screen parameters 15 & 19 inch monitors. These determine the max size in | |
165 | * pixel and character units for the display and cursor positions. | |
166 | * Notice that the mouse defaults to original square algorithm, but X | |
167 | * will change to its defaults once implemented. | |
168 | */ | |
169 | struct qv_info *qv_scn; | |
170 | struct qv_info qv_scn_defaults[] = { | |
171 | {0, {0, 0}, 0, {0, 0}, 0, 0, 30, 80, 768, 480, 768-16, 480-16, | |
172 | 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}, | |
173 | {0, {0, 0}, 0, {0, 0}, 0, 0, 55, 120, 960, 864, 960-16, 864-16, | |
174 | 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4}, | |
175 | {0, {0, 0}, 0, {0, 0}, 0, 0, 56, 120,1024, 864,1024-16, 864-16, | |
176 | 0, 0, 0, 0, 0, QVMAXEVQ, 0, 0, {0, 0}, {0, 0, 0, 0}, 2, 4} | |
177 | }; | |
178 | ||
179 | /* | |
180 | * Screen controller initialization parameters. The definations and use | |
181 | * of these parameters can be found in the Motorola 68045 crtc specs. In | |
182 | * essence they set the display parameters for the chip. The first set is | |
183 | * for the 15" screen and the second is for the 19" seperate sync. There | |
184 | * is also a third set for a 19" composite sync monitor which we have not | |
185 | * tested and which is not supported. | |
186 | */ | |
187 | static short qv_crt_parms[][16] = { | |
188 | { 31, 25, 27, 0142, 31, 13, 30, 31, 4, 15, 040, 0, 0, 0, 0, 0 }, | |
189 | /* VR100*/ { 39, 30, 32, 0262, 55, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0 }, | |
190 | /* VR260*/ { 39, 32, 33, 0264, 56, 5, 54, 54, 4, 15, 040, 0, 0, 0, 0, 0}, | |
191 | }; | |
e0594022 MK |
192 | |
193 | /* | |
194 | * Screen parameters | |
195 | */ | |
196 | struct qv_info *qv_scn; | |
197 | int maxqvmem = 254*1024 - sizeof(struct qv_info) - QVMAXEVQ*sizeof(vsEvent); | |
198 | ||
199 | /* | |
200 | * Keyboard state | |
201 | */ | |
202 | struct qv_keyboard { | |
203 | int shift; /* state variables */ | |
204 | int cntrl; | |
205 | int lock; | |
206 | char last; /* last character */ | |
207 | } qv_keyboard; | |
208 | ||
209 | short divdefaults[15] = { LK_DOWN, /* 0 doesn't exist */ | |
210 | LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_DOWN, | |
211 | LK_UPDOWN, LK_UPDOWN, LK_AUTODOWN, LK_AUTODOWN, | |
212 | LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, LK_AUTODOWN, | |
213 | LK_DOWN, LK_AUTODOWN }; | |
214 | ||
215 | short kbdinitstring[] = { /* reset any random keyboard stuff */ | |
216 | LK_AR_ENABLE, /* we want autorepeat by default */ | |
217 | LK_CL_ENABLE, /* keyclick */ | |
218 | 0x84, /* keyclick volume */ | |
219 | LK_KBD_ENABLE, /* the keyboard itself */ | |
220 | LK_BELL_ENABLE, /* keyboard bell */ | |
221 | 0x84, /* bell volume */ | |
222 | LK_LED_DISABLE, /* keyboard leds */ | |
223 | LED_ALL }; | |
224 | #define KBD_INIT_LENGTH sizeof(kbdinitstring)/sizeof(short) | |
225 | ||
226 | #define TOY ((time.tv_sec * 100) + (time.tv_usec / 10000)) | |
227 | ||
228 | int qv_events; | |
229 | int qv_ipl_lo = 1; /* IPL low flag */ | |
230 | int mouseon = 0; /* mouse channel is enabled when 1*/ | |
231 | struct proc *rsel; /* process waiting for select */ | |
232 | ||
233 | int qvstart(), qvputc(), ttrstrt(); | |
234 | ||
235 | /* | |
236 | * Keyboard translation and font tables | |
237 | */ | |
238 | extern char q_key[],q_shift_key[],*q_special[],q_font[]; | |
239 | extern short q_cursor[]; | |
240 | ||
241 | /* | |
242 | * See if the qvss will interrupt. | |
243 | */ | |
244 | ||
245 | /*ARGSUSED*/ | |
246 | qvprobe(reg, ctlr) | |
247 | caddr_t reg; | |
248 | int ctlr; | |
249 | { | |
250 | register int br, cvec; /* these are ``value-result'' */ | |
251 | register struct qvdevice *qvaddr = (struct qvdevice *)reg; | |
252 | static int tvec, ovec; | |
253 | ||
254 | #ifdef lint | |
255 | br = 0; cvec = br; br = cvec; | |
256 | #endif | |
257 | /* | |
258 | * Allocate the next two vectors | |
259 | */ | |
260 | tvec = 0360; | |
261 | ovec = cvec; | |
262 | /* | |
263 | * Turn on the keyboard and vertical interrupt vectors. | |
264 | */ | |
265 | qvaddr->qv_intcsr = 0; /* init the interrupt controler */ | |
266 | qvaddr->qv_intcsr = 0x40; /* reset irr */ | |
267 | qvaddr->qv_intcsr = 0x80; /* specify individual vectors */ | |
268 | qvaddr->qv_intcsr = 0xc0; /* preset autoclear data */ | |
269 | qvaddr->qv_intdata = 0xff; /* all setup as autoclear */ | |
270 | ||
271 | qvaddr->qv_intcsr = 0xe0; /* preset vector address 1 */ | |
272 | qvaddr->qv_intdata = tvec; /* give it the keyboard vector */ | |
273 | qvaddr->qv_intcsr = 0x28; /* enable tx/rx interrupt */ | |
274 | ||
275 | qvaddr->qv_intcsr = 0xe1; /* preset vector address 2 */ | |
276 | qvaddr->qv_intdata = tvec+4; /* give it the vertical sysnc */ | |
277 | qvaddr->qv_intcsr = 0x29; /* enable */ | |
278 | ||
279 | qvaddr->qv_intcsr = 0xa1; /* arm the interrupt ctrl */ | |
280 | ||
281 | qvaddr->qv_uartcmd = 0x15; /* set mode pntr/enable rx/tx */ | |
282 | qvaddr->qv_uartmode = 0x17; /* noparity, 8-bit */ | |
283 | qvaddr->qv_uartmode = 0x07; /* 1 stop bit */ | |
284 | qvaddr->qv_uartstatus = 0x99; /* 4800 baud xmit/recv */ | |
285 | qvaddr->qv_uartintstatus = 2; /* enable recv interrupts */ | |
286 | ||
287 | qvaddr->qv_csr |= QV_INT_ENABLE | QV_CUR_MODE; | |
288 | ||
289 | DELAY(10000); | |
290 | ||
291 | qvaddr->qv_csr &= ~QV_INT_ENABLE; | |
292 | ||
293 | /* | |
294 | * If the qvss did interrupt it was the second vector not | |
295 | * the first so we have to return the first so that they | |
296 | * will be setup properly | |
297 | */ | |
298 | if( ovec == cvec ) { | |
299 | return 0; | |
300 | } else | |
3e5a489f | 301 | cvec -= 4; |
e0594022 MK |
302 | return (sizeof (struct qvdevice)); |
303 | } | |
304 | ||
305 | /* | |
306 | * Routine called to attach a qv. | |
307 | */ | |
308 | qvattach(ui) | |
309 | struct uba_device *ui; | |
310 | { | |
e0594022 MK |
311 | |
312 | /* | |
313 | * If not the console then we have to setup the screen | |
314 | */ | |
341dce35 | 315 | if( v_putc != qvputc || ui->ui_unit != 0) |
3e5a489f MK |
316 | qv_setup((struct qvdevice *)ui->ui_addr, ui->ui_unit, 1); |
317 | else | |
318 | qv_scn->qvaddr = (struct qvdevice *)ui->ui_addr; | |
e0594022 MK |
319 | } |
320 | ||
321 | ||
322 | /*ARGSUSED*/ | |
323 | qvopen(dev, flag) | |
324 | dev_t dev; | |
325 | { | |
326 | register struct tty *tp; | |
327 | register int unit, qv; | |
328 | register struct qvdevice *qvaddr; | |
329 | register struct uba_device *ui; | |
330 | register struct qv_info *qp = qv_scn; | |
331 | ||
332 | unit = minor(dev); | |
333 | qv = unit >> 2; | |
334 | if (unit >= nqv || (ui = qvinfo[qv])== 0 || ui->ui_alive == 0) | |
335 | return (ENXIO); | |
341dce35 | 336 | if (QVCHAN(unit) == QVSPARE |
ad8e96ea | 337 | #ifndef CONS_HACK |
341dce35 MK |
338 | || QVCHAN(unit) == QVPCONS |
339 | #endif | |
340 | ) | |
341 | return (ENODEV); | |
e0594022 MK |
342 | tp = &qv_tty[unit]; |
343 | if (tp->t_state&TS_XCLUDE && u.u_uid!=0) | |
344 | return (EBUSY); | |
345 | qvaddr = (struct qvdevice *)ui->ui_addr; | |
346 | qv_scn->qvaddr = qvaddr; | |
347 | tp->t_addr = (caddr_t)qvaddr; | |
348 | tp->t_oproc = qvstart; | |
349 | ||
350 | if ((tp->t_state&TS_ISOPEN) == 0) { | |
351 | ttychars(tp); | |
352 | tp->t_state = TS_ISOPEN|TS_CARR_ON; | |
353 | tp->t_ispeed = B9600; | |
354 | tp->t_ospeed = B9600; | |
341dce35 | 355 | if( QVCHAN(unit) == QVKEYBOARD ) { |
e0594022 MK |
356 | /* make sure keyboard is always back to default */ |
357 | qvkbdreset(); | |
358 | qvaddr->qv_csr |= QV_INT_ENABLE; | |
359 | tp->t_flags = XTABS|EVENP|ECHO|CRMOD; | |
360 | } else | |
361 | tp->t_flags = RAW; | |
362 | } | |
363 | /* | |
364 | * Process line discipline specific open if its not the | |
365 | * mouse channel. For the mouse we init the ring ptr's. | |
366 | */ | |
341dce35 | 367 | if( QVCHAN(unit) != QVMOUSECHAN ) |
e0594022 MK |
368 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
369 | else { | |
370 | mouseon = 1; | |
371 | /* set up event queue for later */ | |
372 | qp->ibuff = (vsEvent *)qp - QVMAXEVQ; | |
373 | qp->iqsize = QVMAXEVQ; | |
374 | qp->ihead = qp->itail = 0; | |
375 | return 0; | |
376 | } | |
377 | } | |
378 | ||
379 | /* | |
380 | * Close a QVSS line. | |
381 | */ | |
382 | /*ARGSUSED*/ | |
383 | qvclose(dev, flag) | |
384 | dev_t dev; | |
385 | int flag; | |
386 | { | |
387 | register struct tty *tp; | |
388 | register unit; | |
389 | register struct qvdevice *qvaddr; | |
390 | ||
391 | unit = minor(dev); | |
392 | tp = &qv_tty[unit]; | |
393 | ||
394 | /* | |
395 | * If this is the keyboard unit (0) shutdown the | |
396 | * interface. | |
397 | */ | |
398 | qvaddr = (struct qvdevice *)tp->t_addr; | |
341dce35 | 399 | if (QVCHAN(unit) == QVKEYBOARD ) |
e0594022 MK |
400 | qvaddr->qv_csr &= ~QV_INT_ENABLE; |
401 | ||
402 | /* | |
403 | * If unit is not the mouse channel call the line disc. | |
404 | * otherwise clear the state flag, and put the keyboard into down/up. | |
405 | */ | |
341dce35 | 406 | if (QVCHAN(unit) != QVMOUSECHAN) { |
e0594022 MK |
407 | (*linesw[tp->t_line].l_close)(tp); |
408 | ttyclose(tp); | |
409 | } else { | |
410 | mouseon = 0; | |
411 | qv_init( qvaddr ); | |
412 | } | |
413 | tp->t_state = 0; | |
414 | } | |
415 | ||
416 | qvread(dev, uio) | |
417 | dev_t dev; | |
418 | struct uio *uio; | |
419 | { | |
420 | register struct tty *tp; | |
421 | int unit = minor( dev ); | |
422 | ||
341dce35 | 423 | if (QVCHAN(unit) != QVMOUSECHAN) { |
e0594022 MK |
424 | tp = &qv_tty[unit]; |
425 | return ((*linesw[tp->t_line].l_read)(tp, uio)); | |
426 | } | |
427 | return (ENXIO); | |
428 | } | |
429 | ||
430 | qvwrite(dev, uio) | |
431 | dev_t dev; | |
432 | struct uio *uio; | |
433 | { | |
434 | register struct tty *tp; | |
435 | int unit = minor( dev ); | |
436 | ||
437 | /* | |
438 | * If this is the mouse we simply fake the i/o, otherwise | |
439 | * we let the line disp. handle it. | |
440 | */ | |
341dce35 | 441 | if (QVCHAN(unit) == QVMOUSECHAN) { |
e0594022 MK |
442 | uio->uio_offset = uio->uio_resid; |
443 | uio->uio_resid = 0; | |
444 | return 0; | |
445 | } | |
446 | tp = &qv_tty[unit]; | |
447 | return ((*linesw[tp->t_line].l_write)(tp, uio)); | |
448 | } | |
449 | ||
450 | ||
451 | /* | |
452 | * Mouse activity select routine | |
453 | */ | |
454 | qvselect(dev, rw) | |
455 | dev_t dev; | |
456 | { | |
457 | register int s = spl5(); | |
e0594022 MK |
458 | register struct qv_info *qp = qv_scn; |
459 | ||
341dce35 | 460 | if( QVCHAN(minor(dev)) == QVMOUSECHAN ) |
e0594022 MK |
461 | switch(rw) { |
462 | case FREAD: /* if events okay */ | |
463 | if(qp->ihead != qp->itail) { | |
464 | splx(s); | |
465 | return(1); | |
466 | } | |
467 | rsel = u.u_procp; | |
468 | splx(s); | |
469 | return(0); | |
470 | case FWRITE: /* can never write */ | |
471 | splx(s); | |
472 | return(EACCES); | |
473 | } | |
474 | else | |
475 | return( ttselect(dev, rw) ); | |
476 | } | |
477 | ||
478 | /* | |
479 | * QVSS keyboard interrupt. | |
480 | */ | |
481 | qvkint(qv) | |
482 | int qv; | |
483 | { | |
484 | struct tty *tp; | |
485 | register c; | |
486 | struct uba_device *ui; | |
487 | register int key; | |
488 | register int i,j; | |
489 | int k,l; | |
490 | ||
491 | ui = qvinfo[qv]; | |
492 | if (ui == 0 || ui->ui_alive == 0) | |
493 | return; | |
494 | tp = &qv_tty[qv<<2]; | |
495 | /* | |
496 | * Get a character from the keyboard. | |
497 | */ | |
498 | key = ((struct qvdevice *)ui->ui_addr)->qv_uartdata & 0xff; | |
499 | if( mouseon == 0) { | |
500 | /* | |
501 | * Check for various keyboard errors | |
502 | */ | |
503 | if( key == LK_POWER_ERROR || key == LK_KDOWN_ERROR || | |
504 | key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) { | |
3e5a489f MK |
505 | log(LOG_ERR, |
506 | "qv%d: Keyboard error, code = %x\n",qv,key); | |
507 | return; | |
e0594022 MK |
508 | } |
509 | if( key < LK_LOWEST ) return; | |
510 | /* | |
511 | * See if its a state change key | |
512 | */ | |
513 | switch ( key ) { | |
514 | case LOCK: | |
515 | qv_keyboard.lock ^= 0xffff; /* toggle */ | |
516 | if( qv_keyboard.lock ) | |
517 | qv_key_out( LK_LED_ENABLE ); | |
518 | else | |
519 | qv_key_out( LK_LED_DISABLE ); | |
520 | qv_key_out( LED_3 ); | |
521 | return; | |
522 | case SHIFT: | |
523 | qv_keyboard.shift ^= 0xffff; | |
524 | return; | |
525 | case CNTRL: | |
526 | qv_keyboard.cntrl ^= 0xffff; | |
527 | return; | |
528 | case ALLUP: | |
529 | qv_keyboard.cntrl = qv_keyboard.shift = 0; | |
530 | return; | |
531 | case REPEAT: | |
532 | c = qv_keyboard.last; | |
533 | break; | |
534 | default: | |
535 | /* | |
536 | * Test for control characters. If set, see if the character | |
537 | * is elligible to become a control character. | |
538 | */ | |
539 | if( qv_keyboard.cntrl ) { | |
540 | c = q_key[ key ]; | |
541 | if( c >= ' ' && c <= '~' ) | |
542 | c &= 0x1f; | |
543 | } else if( qv_keyboard.lock || qv_keyboard.shift ) | |
544 | c = q_shift_key[ key ]; | |
545 | else | |
546 | c = q_key[ key ]; | |
547 | break; | |
548 | } | |
549 | ||
550 | qv_keyboard.last = c; | |
551 | ||
552 | /* | |
553 | * Check for special function keys | |
554 | */ | |
555 | if( c & 0x80 ) { | |
556 | register char *string; | |
557 | string = q_special[ c & 0x7f ]; | |
558 | while( *string ) | |
559 | (*linesw[tp->t_line].l_rint)(*string++, tp); | |
560 | } else | |
561 | (*linesw[tp->t_line].l_rint)(c, tp); | |
562 | } else { | |
563 | /* | |
564 | * Mouse channel is open put it into the event queue | |
565 | * instead. | |
566 | */ | |
567 | register struct qv_info *qp = qv_scn; | |
568 | register vsEvent *vep; | |
569 | ||
570 | if ((i = EVROUND(qp->itail+1)) == qp->ihead) return; | |
571 | vep = &qp->ibuff[qp->itail]; | |
572 | vep->vse_direction = VSE_KBTRAW; | |
573 | vep->vse_type = VSE_BUTTON; | |
574 | vep->vse_device = VSE_DKB; | |
575 | vep->vse_x = qp->mouse.x; | |
576 | vep->vse_y = qp->mouse.y; | |
577 | vep->vse_time = TOY; | |
578 | vep->vse_key = key; | |
579 | qp->itail = i; | |
580 | if(rsel) { | |
581 | selwakeup(rsel,0); | |
582 | rsel = 0; | |
583 | } | |
584 | } | |
585 | } | |
586 | ||
587 | /* | |
588 | * Ioctl for QVSS. | |
589 | */ | |
590 | /*ARGSUSED*/ | |
591 | qvioctl(dev, cmd, data, flag) | |
592 | dev_t dev; | |
593 | register caddr_t data; | |
594 | { | |
595 | register struct tty *tp; | |
596 | register int unit = minor(dev); | |
597 | register struct qv_info *qp = qv_scn; | |
598 | register struct qv_kpcmd *qk; | |
599 | register unsigned char *cp; | |
600 | int error; | |
601 | ||
602 | /* | |
603 | * Check for and process qvss specific ioctl's | |
604 | */ | |
605 | switch( cmd ) { | |
606 | case QIOCGINFO: /* return screen info */ | |
607 | bcopy(qp, data, sizeof (struct qv_info)); | |
608 | break; | |
609 | ||
610 | case QIOCSMSTATE: /* set mouse state */ | |
611 | qp->mouse = *((vsCursor *)data); | |
612 | qv_pos_cur( qp->mouse.x, qp->mouse.y ); | |
613 | break; | |
614 | ||
615 | case QIOCINIT: /* init screen */ | |
616 | qv_init( qp->qvaddr ); | |
617 | break; | |
618 | ||
619 | case QIOCKPCMD: | |
620 | qk = (struct qv_kpcmd *)data; | |
621 | if(qk->nbytes == 0) qk->cmd |= 0200; | |
622 | if(mouseon == 0) qk->cmd |= 1; /* no mode changes */ | |
623 | qv_key_out(qk->cmd); | |
624 | cp = &qk->par[0]; | |
625 | while(qk->nbytes-- > 0) { /* terminate parameters */ | |
626 | if(qk->nbytes <= 0) *cp |= 0200; | |
627 | qv_key_out(*cp++); | |
628 | } | |
629 | break; | |
630 | case QIOCADDR: /* get struct addr */ | |
631 | *(struct qv_info **) data = qp; | |
632 | break; | |
633 | default: /* not ours ?? */ | |
634 | tp = &qv_tty[unit]; | |
635 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); | |
636 | if (error >= 0) | |
637 | return (error); | |
638 | error = ttioctl(tp, cmd, data, flag); | |
639 | if (error >= 0) { | |
640 | return (error); | |
641 | } | |
642 | break; | |
643 | } | |
644 | return (0); | |
645 | } | |
646 | /* | |
647 | * Initialize the screen and the scanmap | |
648 | */ | |
649 | qv_init(qvaddr) | |
650 | struct qvdevice *qvaddr; | |
651 | { | |
652 | register short *scanline; | |
653 | register int i; | |
654 | register short scan; | |
655 | register char *ptr; | |
656 | register struct qv_info *qp = qv_scn; | |
657 | ||
658 | /* | |
659 | * Clear the bit map | |
660 | */ | |
661 | for( i=0 , ptr = qp->bitmap ; i<240 ; i += 2 , ptr += 2048) | |
662 | bzero( ptr, 2048 ); | |
663 | /* | |
664 | * Reinitialize the scanmap | |
665 | */ | |
666 | scan = qvaddr->qv_csr & QV_MEM_BANK; | |
667 | scanline = qp->scanmap; | |
668 | for(i = 0 ; i < qp->max_y ; i++ ) | |
669 | *scanline++ = scan++; | |
670 | ||
671 | /* | |
672 | * Home the cursor | |
673 | */ | |
674 | qp->row = qp->col = 0; | |
675 | ||
676 | /* | |
677 | * Reset the cursor to the default type. | |
678 | */ | |
679 | for( i=0 ; i<16 ; i++ ) | |
680 | qp->cursorbits[i] = q_cursor[i]; | |
681 | qvaddr->qv_csr |= QV_CUR_MODE; | |
682 | /* | |
683 | * Reset keyboard to default state. | |
684 | */ | |
685 | qvkbdreset(); | |
686 | } | |
687 | ||
688 | qvreset() | |
689 | { | |
690 | } | |
691 | qvkbdreset() | |
692 | { | |
693 | register int i; | |
694 | qv_key_out(LK_DEFAULTS); | |
695 | for( i=1 ; i < 15 ; i++ ) | |
696 | qv_key_out( divdefaults[i] | (i<<3)); | |
697 | for (i = 0; i < KBD_INIT_LENGTH; i++) | |
698 | qv_key_out(kbdinitstring[i]); | |
699 | } | |
700 | ||
701 | #define abs(x) (((x) > 0) ? (x) : (-(x))) | |
702 | /* | |
703 | * QVSS vertical sync interrupt | |
704 | */ | |
705 | qvvint(qv) | |
706 | int qv; | |
707 | { | |
708 | extern int selwait; | |
709 | register struct qvdevice *qvaddr; | |
710 | struct uba_device *ui; | |
711 | register struct qv_info *qp = qv_scn; | |
712 | int unit; | |
713 | struct tty *tp0; | |
714 | int i; | |
715 | register int j; | |
716 | /* | |
717 | * Mouse state info | |
718 | */ | |
719 | static ushort omouse = 0, nmouse = 0; | |
720 | static char omx=0, omy=0, mx=0, my=0, om_switch=0, m_switch=0; | |
721 | register int dx, dy; | |
722 | ||
723 | /* | |
724 | * Test and set the qv_ipl_lo flag. If the result is not zero then | |
725 | * someone else must have already gotten here. | |
726 | */ | |
727 | if( --qv_ipl_lo ) | |
728 | return; | |
729 | spl4(); | |
730 | ui = qvinfo[qv]; | |
731 | unit = qv<<2; | |
732 | qvaddr = (struct qvdevice *)ui->ui_addr; | |
341dce35 | 733 | tp0 = &qv_tty[QVCHAN(unit) + QVMOUSECHAN]; |
e0594022 MK |
734 | /* |
735 | * See if the mouse has moved. | |
736 | */ | |
737 | if( omouse != (nmouse = qvaddr->qv_mouse) ) { | |
738 | omouse = nmouse; | |
739 | mx = nmouse & 0xff; | |
740 | my = nmouse >> 8; | |
741 | dy = my - omy; omy = my; | |
742 | dx = mx - omx; omx = mx; | |
743 | if( dy < 50 && dy > -50 && dx < 50 && dx > -50 ) { | |
744 | register vsEvent *vep; | |
745 | if( qp->mscale < 0 ) { /* Ray Lanza's original */ | |
746 | if( dy < 0 ) | |
747 | dy = -( dy * dy ); | |
748 | else | |
749 | dy *= dy; | |
750 | if( dx < 0 ) | |
751 | dx = -( dx * dx ); | |
752 | else | |
753 | dx *= dx; | |
754 | } | |
755 | else { /* Vs100 style, see WGA spec */ | |
756 | int thresh = qp->mthreshold; | |
757 | int scale = qp->mscale; | |
758 | if( abs(dx) > thresh ) { | |
759 | if ( dx < 0 ) | |
760 | dx = (dx + thresh)*scale - thresh; | |
761 | else | |
762 | dx = (dx - thresh)*scale + thresh; | |
763 | } | |
764 | if( abs(dy) > thresh ) { | |
765 | if ( dy < 0 ) | |
766 | dy = (dy + thresh)*scale - thresh; | |
767 | else | |
768 | dy = (dy - thresh)*scale + thresh; | |
769 | } | |
770 | } | |
771 | qp->mouse.x += dx; | |
772 | qp->mouse.y -= dy; | |
773 | if( qp->mouse.x < 0 ) | |
774 | qp->mouse.x = 0; | |
775 | if( qp->mouse.y < 0 ) | |
776 | qp->mouse.y = 0; | |
777 | if( qp->mouse.x > qp->max_cur_x ) | |
778 | qp->mouse.x = qp->max_cur_x; | |
779 | if( qp->mouse.y > qp->max_cur_y ) | |
780 | qp->mouse.y = qp->max_cur_y; | |
781 | if( tp0->t_state & TS_ISOPEN ) | |
782 | qv_pos_cur( qp->mouse.x, qp->mouse.y ); | |
783 | if (qp->mouse.y < qp->mbox.bottom && | |
784 | qp->mouse.y >= qp->mbox.top && | |
785 | qp->mouse.x < qp->mbox.right && | |
786 | qp->mouse.x >= qp->mbox.left) goto switches; | |
787 | qp->mbox.bottom = 0; /* trash box */ | |
788 | if (EVROUND(qp->itail+1) == qp->ihead) | |
789 | goto switches; | |
790 | i = EVROUND(qp->itail - 1); | |
791 | if ((qp->itail != qp->ihead) && (i != qp->ihead)) { | |
792 | vep = & qp->ibuff[i]; | |
793 | if(vep->vse_type == VSE_MMOTION) { | |
794 | vep->vse_x = qp->mouse.x; | |
795 | vep->vse_y = qp->mouse.y; | |
796 | goto switches; | |
797 | } | |
798 | } | |
799 | /* put event into queue and do select */ | |
800 | vep = & qp->ibuff[qp->itail]; | |
801 | vep->vse_type = VSE_MMOTION; | |
802 | vep->vse_time = TOY; | |
803 | vep->vse_x = qp->mouse.x; | |
804 | vep->vse_y = qp->mouse.y; | |
805 | qp->itail = EVROUND(qp->itail+1); | |
806 | } | |
807 | } | |
808 | /* | |
809 | * See if mouse switches have changed. | |
810 | */ | |
811 | switches:if( om_switch != ( m_switch = (qvaddr->qv_csr & QV_MOUSE_ANY) >> 8 ) ) { | |
812 | qp->mswitches = ~m_switch & 0x7; | |
813 | for (j = 0; j < 3; j++) { /* check each switch */ | |
814 | register vsEvent *vep; | |
815 | if ( ((om_switch>>j) & 1) == ((m_switch>>j) & 1) ) | |
816 | continue; | |
817 | /* check for room in the queue */ | |
818 | if ((i = EVROUND(qp->itail+1)) == qp->ihead) return; | |
819 | /* put event into queue and do select */ | |
820 | vep = &qp->ibuff[qp->itail]; | |
821 | vep->vse_type = VSE_BUTTON; | |
822 | vep->vse_key = 2 - j; | |
823 | vep->vse_direction = VSE_KBTDOWN; | |
824 | if ( (m_switch >> j) & 1) | |
825 | vep->vse_direction = VSE_KBTUP; | |
826 | vep->vse_device = VSE_MOUSE; | |
827 | vep->vse_time = TOY; | |
828 | vep->vse_x = qp->mouse.x; | |
829 | vep->vse_y = qp->mouse.y; | |
830 | } | |
831 | qp->itail = i; | |
832 | om_switch = m_switch; | |
833 | qp->mswitches = m_switch; | |
834 | } | |
835 | /* if we have proc waiting, and event has happened, wake him up */ | |
836 | if(rsel && (qp->ihead != qp->itail)) { | |
837 | selwakeup(rsel,0); | |
838 | rsel = 0; | |
839 | } | |
840 | /* | |
841 | * Okay we can take another hit now | |
842 | */ | |
843 | qv_ipl_lo = 1; | |
844 | } | |
845 | ||
846 | /* | |
847 | * Start transmission | |
848 | */ | |
849 | qvstart(tp) | |
850 | register struct tty *tp; | |
851 | { | |
852 | register int unit, c; | |
853 | register struct tty *tp0; | |
854 | int s; | |
855 | ||
856 | unit = minor(tp->t_dev); | |
341dce35 MK |
857 | #ifdef CONS_HACK |
858 | tp0 = &qv_tty[(unit&0xfc)+QVPCONS]; | |
859 | #endif | |
860 | unit = QVCHAN(unit); | |
e0594022 MK |
861 | |
862 | s = spl5(); | |
863 | /* | |
864 | * If it's currently active, or delaying, no need to do anything. | |
865 | */ | |
866 | if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) | |
867 | goto out; | |
868 | /* | |
869 | * Display chars until the queue is empty, if the second subchannel | |
870 | * is open direct them there. Drop characters from subchannels other | |
871 | * than 0 on the floor. | |
872 | */ | |
873 | ||
874 | while( tp->t_outq.c_cc ) { | |
875 | c = getc(&tp->t_outq); | |
341dce35 MK |
876 | if (unit == QVKEYBOARD) |
877 | #ifdef CONS_HACK | |
e0594022 MK |
878 | if( tp0->t_state & TS_ISOPEN ){ |
879 | (*linesw[tp0->t_line].l_rint)(c, tp0); | |
880 | } else | |
341dce35 MK |
881 | #endif |
882 | qvputchar( c & 0xff ); | |
e0594022 MK |
883 | } |
884 | /* | |
885 | * Position the cursor to the next character location. | |
886 | */ | |
887 | qv_pos_cur( qv_scn->col*8, qv_scn->row*15 ); | |
888 | ||
889 | /* | |
890 | * If there are sleepers, and output has drained below low | |
891 | * water mark, wake up the sleepers. | |
892 | */ | |
893 | if ( tp->t_outq.c_cc<=TTLOWAT(tp) ) { | |
894 | if (tp->t_state&TS_ASLEEP){ | |
895 | tp->t_state &= ~TS_ASLEEP; | |
896 | wakeup((caddr_t)&tp->t_outq); | |
897 | } | |
898 | } | |
899 | tp->t_state &= ~TS_BUSY; | |
900 | out: | |
901 | splx(s); | |
902 | } | |
903 | ||
904 | /* | |
905 | * Stop output on a line, e.g. for ^S/^Q or output flush. | |
906 | */ | |
907 | /*ARGSUSED*/ | |
908 | qvstop(tp, flag) | |
909 | register struct tty *tp; | |
910 | { | |
911 | register int s; | |
912 | ||
913 | /* | |
914 | * Block input/output interrupts while messing with state. | |
915 | */ | |
916 | s = spl5(); | |
917 | if (tp->t_state & TS_BUSY) { | |
918 | if ((tp->t_state&TS_TTSTOP)==0) { | |
919 | tp->t_state |= TS_FLUSH; | |
920 | } else | |
921 | tp->t_state &= ~TS_BUSY; | |
922 | } | |
923 | splx(s); | |
924 | } | |
925 | ||
341dce35 MK |
926 | qvputc(c) |
927 | char c; | |
928 | { | |
929 | qvputchar(c); | |
930 | if (c == '\n') | |
931 | qvputchar('\r'); | |
932 | } | |
933 | ||
e0594022 MK |
934 | /* |
935 | * Routine to display a character on the screen. The model used is a | |
936 | * glass tty. It is assummed that the user will only use this emulation | |
937 | * during system boot and that the screen will be eventually controlled | |
938 | * by a window manager. | |
939 | * | |
940 | */ | |
341dce35 | 941 | qvputchar( c ) |
e0594022 MK |
942 | register char c; |
943 | { | |
944 | ||
945 | register char *b_row, *f_row; | |
946 | register int i; | |
947 | register short *scanline; | |
948 | register int ote = 128; | |
949 | register struct qv_info *qp = qv_scn; | |
950 | ||
951 | /* | |
952 | * This routine may be called in physical mode by the dump code | |
953 | * so we check and punt if that's the case. | |
954 | */ | |
955 | if( (mfpr(MAPEN) & 1) == 0 ) | |
956 | return; | |
957 | ||
958 | c &= 0x7f; | |
959 | ||
960 | switch ( c ) { | |
961 | case '\t': /* tab */ | |
962 | for( i = 8 - (qp->col & 0x7) ; i > 0 ; i-- ) | |
341dce35 | 963 | qvputchar( ' ' ); |
e0594022 MK |
964 | break; |
965 | ||
966 | case '\r': /* return */ | |
967 | qp->col = 0; | |
968 | break; | |
969 | ||
970 | case '\010': /* backspace */ | |
971 | if( --qp->col < 0 ) | |
972 | qp->col = 0; | |
973 | break; | |
974 | ||
975 | case '\n': /* linefeed */ | |
976 | if( qp->row+1 >= qp->max_row ) | |
977 | qvscroll(); | |
978 | else | |
979 | qp->row++; | |
980 | /* | |
981 | * Position the cursor to the next character location. | |
982 | */ | |
983 | qv_pos_cur( qp->col*8, qp->row*15 ); | |
984 | break; | |
985 | ||
986 | case '\007': /* bell */ | |
987 | /* | |
988 | * We don't do anything to the keyboard until after | |
989 | * autoconfigure. | |
990 | */ | |
991 | if( qp->qvaddr ) | |
992 | qv_key_out( LK_RING_BELL ); | |
993 | return; | |
994 | ||
995 | default: | |
996 | if( c >= ' ' && c <= '~' ) { | |
997 | scanline = qp->scanmap; | |
998 | b_row = qp->bitmap+(scanline[qp->row*15]&0x3ff)*128+qp->col; | |
999 | i = c - ' '; | |
1000 | if( i < 0 || i > 95 ) | |
1001 | i = 0; | |
1002 | else | |
1003 | i *= 15; | |
1004 | f_row = (char *)((int)q_font + i); | |
1005 | ||
1006 | /* for( i=0 ; i<15 ; i++ , b_row += 128, f_row++ ) | |
1007 | *b_row = *f_row;*/ | |
1008 | /* inline expansion for speed */ | |
1009 | *b_row = *f_row++; b_row += ote; | |
1010 | *b_row = *f_row++; b_row += ote; | |
1011 | *b_row = *f_row++; b_row += ote; | |
1012 | *b_row = *f_row++; b_row += ote; | |
1013 | *b_row = *f_row++; b_row += ote; | |
1014 | *b_row = *f_row++; b_row += ote; | |
1015 | *b_row = *f_row++; b_row += ote; | |
1016 | *b_row = *f_row++; b_row += ote; | |
1017 | *b_row = *f_row++; b_row += ote; | |
1018 | *b_row = *f_row++; b_row += ote; | |
1019 | *b_row = *f_row++; b_row += ote; | |
1020 | *b_row = *f_row++; b_row += ote; | |
1021 | *b_row = *f_row++; b_row += ote; | |
1022 | *b_row = *f_row++; b_row += ote; | |
1023 | *b_row = *f_row++; b_row += ote; | |
1024 | ||
1025 | if( ++qp->col >= qp->max_col ) { | |
1026 | qp->col = 0 ; | |
1027 | if( qp->row+1 >= qp->max_row ) | |
1028 | qvscroll(); | |
1029 | else | |
1030 | qp->row++; | |
1031 | } | |
1032 | } | |
1033 | break; | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | /* | |
1038 | * Position the cursor to a particular spot. | |
1039 | */ | |
1040 | qv_pos_cur( x, y) | |
1041 | register int x,y; | |
1042 | { | |
1043 | register struct qvdevice *qvaddr; | |
1044 | register struct qv_info *qp = qv_scn; | |
1045 | register index; | |
1046 | ||
1047 | if( qvaddr = qp->qvaddr ) { | |
1048 | if( y < 0 || y > qp->max_cur_y ) | |
1049 | y = qp->max_cur_y; | |
1050 | if( x < 0 || x > qp->max_cur_x ) | |
1051 | x = qp->max_cur_x; | |
1052 | qp->cursor.x = x; /* keep track of real cursor*/ | |
1053 | qp->cursor.y = y; /* position, indep. of mouse*/ | |
1054 | ||
1055 | qvaddr->qv_crtaddr = 10; /* select cursor start reg */ | |
1056 | qvaddr->qv_crtdata = y & 0xf; | |
1057 | qvaddr->qv_crtaddr = 11; /* select cursor end reg */ | |
1058 | qvaddr->qv_crtdata = y & 0xf; | |
1059 | qvaddr->qv_crtaddr = 14; /* select cursor y pos. */ | |
1060 | qvaddr->qv_crtdata = y >> 4; | |
1061 | qvaddr->qv_xcur = x; /* pos x axis */ | |
1062 | /* | |
1063 | * If the mouse is being used then we change the mode of | |
1064 | * cursor display based on the pixels under the cursor | |
1065 | */ | |
1066 | if( mouseon ) { | |
1067 | index = y*128 + x/8; | |
1068 | if( qp->bitmap[ index ] && qp->bitmap[ index+128 ] ) | |
1069 | qvaddr->qv_csr &= ~QV_CUR_MODE; | |
1070 | else | |
1071 | qvaddr->qv_csr |= QV_CUR_MODE; | |
1072 | } | |
1073 | } | |
1074 | } | |
1075 | /* | |
1076 | * Scroll the bitmap by moving the scanline map words. This could | |
1077 | * be done by moving the bitmap but it's much too slow for a full screen. | |
1078 | * The only drawback is that the scanline map must be reset when the user | |
1079 | * wants to do graphics. | |
1080 | */ | |
1081 | qvscroll() | |
1082 | { | |
1083 | short tmpscanlines[15]; | |
1084 | register char *b_row; | |
1085 | register short *scanline; | |
1086 | register struct qv_info *qp = qv_scn; | |
1087 | ||
1088 | /* | |
1089 | * If the mouse is on we don't scroll so that the bit map | |
1090 | * remains sane. | |
1091 | */ | |
1092 | if( mouseon ) { | |
1093 | qp->row = 0; | |
1094 | return; | |
1095 | } | |
1096 | /* | |
1097 | * Save the first 15 scanlines so that we can put them at | |
1098 | * the bottom when done. | |
1099 | */ | |
1100 | bcopy( qp->scanmap, tmpscanlines, sizeof tmpscanlines ); | |
1101 | ||
1102 | /* | |
1103 | * Clear the wrapping line so that it won't flash on the bottom | |
1104 | * of the screen. | |
1105 | */ | |
1106 | scanline = qp->scanmap; | |
1107 | b_row = qp->bitmap+(*scanline&0x3ff)*128; | |
1108 | bzero( b_row, 1920 ); | |
1109 | ||
1110 | /* | |
1111 | * Now move the scanlines down | |
1112 | */ | |
1113 | bcopy( qp->scanmap+15, qp->scanmap, (qp->row * 15) * sizeof (short) ); | |
1114 | ||
1115 | /* | |
1116 | * Now put the other lines back | |
1117 | */ | |
1118 | bcopy( tmpscanlines, qp->scanmap+(qp->row * 15), sizeof tmpscanlines ); | |
1119 | ||
1120 | } | |
1121 | ||
1122 | /* | |
1123 | * Output to the keyboard. This routine status polls the transmitter on the | |
1124 | * keyboard to output a code. The timer is to avoid hanging on a bad device. | |
1125 | */ | |
1126 | qv_key_out( c ) | |
1127 | char c; | |
1128 | { | |
1129 | int timer = 30000; | |
1130 | register struct qv_info *qp = qv_scn; | |
1131 | ||
1132 | if( qp->qvaddr ) { | |
1133 | while( (qp->qvaddr->qv_uartstatus & 0x4) == 0 && timer-- ) | |
1134 | ; | |
1135 | qp->qvaddr->qv_uartdata = c; | |
1136 | } | |
1137 | } | |
1138 | /* | |
1139 | * Virtual console initialization. This routine sets up the qvss so that it can | |
1140 | * be used as the system console. It is invoked before autoconfig and has to do | |
1141 | * everything necessary to allow the device to serve as the system console. | |
1142 | * In this case it must map the q-bus and device areas and initialize the qvss | |
1143 | * screen. | |
1144 | */ | |
1145 | qvcons_init() | |
1146 | { | |
1147 | struct percpu *pcpu; /* pointer to percpu structure */ | |
3e5a489f | 1148 | register struct qbus *qb; |
e0594022 | 1149 | struct qvdevice *qvaddr; /* device pointer */ |
341dce35 MK |
1150 | short *devptr; /* virtual device space */ |
1151 | extern cnputc(); /* standard serial console putc */ | |
e0594022 MK |
1152 | #define QVSSCSR 017200 |
1153 | ||
341dce35 MK |
1154 | /* |
1155 | * If secondary console already configured, | |
1156 | * don't override the previous one. | |
1157 | */ | |
1158 | if (v_putc != cnputc) | |
1159 | return; | |
e0594022 MK |
1160 | /* |
1161 | * find the percpu entry that matches this machine. | |
1162 | */ | |
1163 | for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ ) | |
1164 | ; | |
1165 | if( pcpu == NULL ) | |
341dce35 | 1166 | return; |
e0594022 MK |
1167 | |
1168 | /* | |
1169 | * Found an entry for this cpu. Because this device is Microvax specific | |
1170 | * we assume that there is a single q-bus and don't have to worry about | |
1171 | * multiple adapters. | |
1172 | * | |
3e5a489f | 1173 | * Map the device registers. |
e0594022 | 1174 | */ |
3e5a489f MK |
1175 | qb = (struct qbus *)pcpu->pc_io->io_details; |
1176 | ioaccess(qb->qb_iopage, UMEMmap[0] + qb->qb_memsize, | |
1177 | UBAIOPAGES * NBPG); | |
1178 | ||
e0594022 MK |
1179 | /* |
1180 | * See if the qvss is there. | |
1181 | */ | |
3e5a489f | 1182 | devptr = (short *)((char *)umem[0] + (qb->qb_memsize * NBPG)); |
e0594022 MK |
1183 | qvaddr = (struct qvdevice *)((u_int)devptr + ubdevreg(QVSSCSR)); |
1184 | if( badaddr( qvaddr, sizeof(short) ) ) | |
341dce35 | 1185 | return; |
e0594022 MK |
1186 | /* |
1187 | * Okay the device is there lets set it up | |
1188 | */ | |
3e5a489f | 1189 | qv_setup(qvaddr, 0, 0); |
341dce35 MK |
1190 | v_putc = qvputc; |
1191 | consops = &cdevsw[QVSSMAJOR]; | |
e0594022 MK |
1192 | } |
1193 | /* | |
1194 | * Do the board specific setup | |
1195 | */ | |
3e5a489f | 1196 | qv_setup(qvaddr, unit, probed) |
e0594022 | 1197 | struct qvdevice *qvaddr; |
3e5a489f MK |
1198 | int unit; |
1199 | int probed; | |
e0594022 | 1200 | { |
3e5a489f MK |
1201 | caddr_t qvssmem; /* pointer to the display mem */ |
1202 | register i; /* simple index */ | |
e0594022 | 1203 | register struct qv_info *qp; |
3e5a489f MK |
1204 | register int *pte; |
1205 | struct percpu *pcpu; /* pointer to percpu structure */ | |
1206 | register struct qbus *qb; | |
1207 | ||
1208 | /* | |
1209 | * find the percpu entry that matches this machine. | |
1210 | */ | |
1211 | for( pcpu = percpu ; pcpu && pcpu->pc_cputype != cpu ; pcpu++ ) | |
1212 | ; | |
1213 | if( pcpu == NULL ) | |
1214 | return(0); | |
1215 | ||
1216 | /* | |
1217 | * Found an entry for this cpu. Because this device is Microvax specific | |
1218 | * we assume that there is a single q-bus and don't have to worry about | |
1219 | * multiple adapters. | |
1220 | * | |
1221 | * Map the device memory. | |
1222 | */ | |
1223 | qb = (struct qbus *)pcpu->pc_io->io_details; | |
1224 | ||
1225 | i = (u_int)(qvaddr->qv_csr & QV_MEM_BANK) << 7; | |
1226 | ioaccess(qb->qb_maddr + i, QVmap[unit], 512 * NBPG); | |
1227 | qvssmem = qvmem[unit]; | |
1228 | pte = (int *)(QVmap[unit]); | |
1229 | for (i=0; i < 512; i++, pte++) | |
1230 | *pte = (*pte & ~PG_PROT) | PG_UW | PG_V; | |
e0594022 | 1231 | |
3e5a489f | 1232 | qv_scn = (struct qv_info *)((u_int)qvssmem + 251*1024); |
e0594022 MK |
1233 | qp = qv_scn; |
1234 | if( (qvaddr->qv_csr & QV_19INCH) && qv_def_scrn == 0) | |
1235 | qv_def_scrn = 1; | |
1236 | *qv_scn = qv_scn_defaults[ qv_def_scrn ]; | |
3e5a489f MK |
1237 | if (probed) |
1238 | qp->qvaddr = qvaddr; | |
e0594022 MK |
1239 | qp->bitmap = qvssmem; |
1240 | qp->scanmap = (short *)((u_int)qvssmem + 254*1024); | |
1241 | qp->cursorbits = (short *)((u_int)qvssmem + 256*1024-32); | |
1242 | /* set up event queue for later */ | |
1243 | qp->ibuff = (vsEvent *)qp - QVMAXEVQ; | |
1244 | qp->iqsize = QVMAXEVQ; | |
1245 | qp->ihead = qp->itail = 0; | |
1246 | ||
1247 | /* | |
1248 | * Setup the crt controller chip. | |
1249 | */ | |
1250 | for( i=0 ; i<16 ; i++ ) { | |
1251 | qvaddr->qv_crtaddr = i; | |
1252 | qvaddr->qv_crtdata = qv_crt_parms[ qv_def_scrn ][ i ]; | |
1253 | } | |
1254 | /* | |
1255 | * Setup the display. | |
1256 | */ | |
1257 | qv_init( qvaddr ); | |
1258 | ||
1259 | /* | |
1260 | * Turn on the video | |
1261 | */ | |
1262 | qvaddr->qv_csr |= QV_VIDEO_ENA ; | |
1263 | } | |
1264 | #endif |