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