xref: /original-bsd/sys/vax/uba/vs.c (revision 492c862f)
1 /* @(#)vs.c	7.5 (MIT) 02/17/90 */
2  /****************************************************************************
3  *									    *
4  *  Copyright (c) 1983, 1984 by						    *
5  *  DIGITAL EQUIPMENT CORPORATION, Maynard, Massachusetts.		    *
6  *  All rights reserved.						    *
7  * 									    *
8  *  This software is furnished on an as-is basis and may be used and copied *
9  *  only with inclusion of the above copyright notice. This software or any *
10  *  other copies thereof may be provided or otherwise made available to     *
11  *  others only for non-commercial purposes.  No title to or ownership of   *
12  *  the software is hereby transferred.					    *
13  * 									    *
14  *  The information in this software is  subject to change without notice   *
15  *  and  should  not  be  construed as  a commitment by DIGITAL EQUIPMENT   *
16  *  CORPORATION.							    *
17  * 									    *
18  *  DIGITAL assumes no responsibility for the use  or  reliability of its   *
19  *  software on equipment which is not supplied by DIGITAL.		    *
20  * 									    *
21  *									    *
22  ****************************************************************************/
23 
24 #include "vs.h"
25 #if NVS > 0
26 
27 #include "machine/pte.h"
28 
29 #include "param.h"
30 #include "user.h"
31 #include "buf.h"
32 #include "systm.h"
33 #include "map.h"
34 #include "kernel.h"
35 #include "ioctl.h"
36 #include "tsleep.h"
37 
38 #include "vsio.h"
39 
40 #include "proc.h"
41 #include "uio.h"
42 #include "vmmac.h"
43 #include "file.h"
44 
45 #include "ubareg.h"
46 #include "ubavar.h"
47 #include "vsreg.h"
48 
49 #include "../vax/mtpr.h"
50 
51 #define	VSWAITPRI	(PZERO+1)
52 #define	VSMAXEVQ	64	/* must be power of 2 */
53 #define EVROUND(x)	((x) & (VSMAXEVQ - 1))
54 
55 
56 #define VSBUFFSIZE	3072
57 struct vsBuffArea {
58 	vsIoAddr vsioa;
59 	char	obuff[VSBUFFSIZE];
60 	vsEvent ibuff[VSMAXEVQ];
61 };
62 struct vsBuffArea vsBuff[NVS];
63 
64 
65 int vsprobe(), vsattach();
66 struct uba_device *vsdinfo[NVS];
67 u_short vsstd[] = { 0 };
68 struct uba_driver vsdriver =
69 	{ vsprobe, 0, vsattach, 0, vsstd, "vs", vsdinfo, 0, 0 };
70 
71 #define	VSUNIT(dev)	(minor(dev))
72 
73 struct vs_softc {
74 	unsigned inited : 1;		/* has this ever been inited? */
75 	unsigned open : 1;		/* only one open, please */
76 	unsigned linkAvail : 1;		/* link is up */
77 	short	pgrp;			/* process group for SIGHUP */
78 	int	romVersion;		/* rom version */
79 	struct vs_fparm	offset;		/* address base */
80 	struct vs_csr	csr;		/* saved csr0 */
81 	struct vs_intr	irr;		/* saved interrupt reason */
82 	struct vs_kbd	krr;		/* saved keyboard */
83 	struct vs_fparm	pr;		/* saved parameter regs */
84 	struct proc *rsel;		/* process waiting for select */
85 	struct vs_fparm vs_nextgo;	/* next packet to go */
86 	short vs_status;		/* status from previous packet */
87 	vsStats stats;			/* statistics */
88 	int vsBuff_ubinfo;		/* ubinfo for vsBuff */
89 }vs_softc[NVS];
90 
91 #define	TRUE	1
92 #define	FALSE	0
93 
94 #define	printI	if (vsIntrPrintfs)printf
95 #define	printD	if (vsDebugPrintfs)printf
96 #define	printM	if (vsMlpPrintfs) vsMlpPrintfs--,printf
97 int	vsIntrPrintfs = 0;
98 int	vsDebugPrintfs = 0;
99 int	vsMlpPrintfs = 0;
100 
101 /*
102  * Tell the system that it's out there, and set up the device's interrupt
103  * vector. Since we are supporting vs100s and vs125s,
104  * this is a bit kludgey. The vs100 works much
105  * as one expects, but the vs125 tries to set all the fiber link
106  * related bits when you hit VS_IE, ignoring the way the 100 works.
107  * Also, the vs100 will let you set the interrupt vector, but
108  * the vs125 ignores this and uses its hard-wired value.
109  * And there's no sure fire to tell which variant it is.
110  * Ugh. Ugh. Ugh.
111  */
112 
113 vsprobe(reg)
114 caddr_t reg;
115 {
116 	register int br, cvec;		/* value-result */
117 	register struct vsdevice *vsaddr = (struct vsdevice *)reg;
118 
119 #ifdef	lint
120 	br = 0; cvec = br; br = cvec;
121 	vsintr(0);
122 #endif
123 	br = 0x15;
124 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
125 	/*
126 	 * uh_lastiv is the last free interrupt vector in the
127 	 * unibus addapter header (uba_hd).
128 	 */
129 
130 	vsaddr->vs_csr0 = cvec >> 2;	/* Save the vector for use on next device */
131 	vsaddr->vs_irr = 0;		/* Csr will only be read if irr == 0 */
132 	vsaddr->vs_irr = 0;		/* Clear interrupt reason register */
133 	vsaddr->vs_pr1  = 0;		/* Clear function parameter */
134 	vsaddr->vs_pr2  = 0;		/* Clear function parameter */
135 	vsaddr->vs_ivr = cvec;		/* set up vector (no-op for vs125) */
136 
137 	DELAY(100000);
138 	if (vsaddr->vs_csr0 & VS_LNK_AVL)
139 		return(0);	/* light won't go off! */
140 	vsaddr->vs_csr0 &= ~VS_LNK_TRNS;
141 	vsaddr->vs_csr0 |= VS_IE;	/* enable interrupts */
142 	DELAY(200000);
143 
144 	return sizeof(struct vsdevice);
145 }
146 
147 vsattach(uip)
148 struct uba_device *uip;
149 {
150 	register struct vs_softc *vsp;
151 	register struct vsdevice *vsaddr;
152 
153 	vsp = &vs_softc[VSUNIT(uip->ui_unit)];
154 	vsp->inited  = FALSE;
155 	vsp->open = FALSE;
156 	vsBuff[VSUNIT(uip->ui_unit)].vsioa.mbox.bottom = 0;
157 	vsp->linkAvail = FALSE;
158 	vsp->romVersion = 0;
159 	vsp->vs_nextgo.fparm_all = NULL;
160 
161 	vsaddr = (struct vsdevice *) uip->ui_addr;
162 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
163 }
164 
165 vsopen(dev, flag)
166 dev_t dev;
167 int flag;
168 {
169 	register struct vs_softc *vsp;
170 	register struct uba_device *uip;
171 	register struct vsdevice *vsaddr;
172 	int s;
173 	int ret;
174 	struct buf vsbuf;
175 	struct vsBuffArea *vsb;
176 	caddr_t vsBuffpage;
177 	int vsBuffnpages;
178 
179 	if (VSUNIT(dev) >= NVS || (vsp = &vs_softc[VSUNIT(dev)])->open ||
180 	    (uip = vsdinfo[VSUNIT(dev)]) == 0 || uip->ui_alive == 0)
181 		return (ENXIO);
182 
183 	vsaddr = (struct vsdevice *) uip->ui_addr;
184 	vsb = &vsBuff[VSUNIT(dev)];
185 	printM("vsopen csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
186 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
187 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
188 
189 	/*
190 	 * Finally! We can now set up the device.
191 	 */
192 
193 	if (!vsp->inited && !(flag & FNDELAY)) {
194 		vsInitDev(dev, TRUE);
195 		if (ret = vsError(vsp))
196 			return(ret);
197 	}
198 
199 	vsp->open = TRUE;		/* we're open */
200 	vsp->pgrp = u.u_procp->p_pgrp;
201 
202 	/* reset statistics */
203 	bzero((caddr_t) &vsp->stats, sizeof(vsStats));
204 
205 	/* initialize user I/O addresses */
206 	vsb->vsioa.ioreg = (short *)vsaddr;
207 	vsb->vsioa.status = 0;
208 	vsb->vsioa.obuff = vsb->obuff;
209 	vsb->vsioa.obufflen = VSBUFFSIZE;
210 	vsb->vsioa.ibuff = vsb->ibuff;
211 	vsb->vsioa.ihead = 0;
212 	vsb->vsioa.itail = 0;
213 	vsb->vsioa.iqsize = VSMAXEVQ;
214 	/* map io regs into user address space (assume they don't cross a page) */
215 	maptouser(vsaddr);
216 	/* map vsBuff into user address space */
217 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
218 	vsBuffnpages = (((int)vsb & PGOFSET) +
219 			 (NBPG-1) + sizeof(struct vsBuffArea)) >> PGSHIFT;
220 	while (vsBuffnpages>0) {
221 	    maptouser(vsBuffpage);
222 	    vsBuffpage += NBPG;
223 	    vsBuffnpages--;
224 	}
225 	/* lock in the buffer */
226 	vsbuf.b_error = 0;
227 	vsbuf.b_proc = u.u_procp;
228 	vsbuf.b_un.b_addr = vsb->obuff;
229 	vsbuf.b_flags = B_BUSY;
230 	vsbuf.b_bcount = VSBUFFSIZE;
231 	vsp->vsBuff_ubinfo = ubasetup(uip->ui_ubanum, &vsbuf, UBA_CANTWAIT);
232 
233 	vsb->vsioa.reloc = (int) (vsp->offset.fparm_all
234 			+ UBAI_ADDR(vsp->vsBuff_ubinfo));
235 	return(0);
236 }
237 
238 vsclose(dev)
239 dev_t dev;
240 {
241 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
242 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
243 	int s, i;
244 	struct vsdevice *vsaddr;
245 	struct vsBuffArea *vsb;
246 	caddr_t vsBuffpage;
247 	int vsBuffnpages;
248 
249 	vsaddr = (struct vsdevice *) uip->ui_addr;
250 	printM("vsclose csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
251 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
252 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
253 		vsb = &vsBuff[VSUNIT(dev)];
254 	if (vsDebugPrintfs) {
255 		printf("vs%d: %d errors, %d unsolicited interrupts",
256 			VSUNIT(dev), vsp->stats.errors, vsp->stats.unsolIntr);
257 		printf(", %d link errors", vsp->stats.linkErrors);
258 		printf(", %d overruns", vsp->stats.overruns);
259 		printf(", csr0 %x, csr1 %x", vsaddr->vs_csr0, vsaddr->vs_csr1);
260 		printf("\n");
261 	}
262 
263 	vsp->open = FALSE;
264 	vsp->inited = FALSE;		/* init on every open */
265 	vsp->vs_nextgo.fparm_all = NULL;
266 	vsb->vsioa.mbox.bottom = 0;
267 	/* release the buffer */
268 	if (vsp->vsBuff_ubinfo!=0) {
269 		ubarelse(uip->ui_ubanum, &vsp->vsBuff_ubinfo);
270 	}
271 
272 #ifdef notdef
273 	/* unmap io regs into user address space (assume they don't cross a page) */
274 	unmaptouser(vsaddr);
275 	/* unmap vsBuff into user address space */
276 	vsBuffpage = (caddr_t)((int)vsb & ~PGOFSET);
277 	vsBuffnpages = (((int)vsb&PGOFSET) +
278 			 (NBPG-1)+ sizeof(struct vsBuffArea)) >> PGSHIFT;
279 	while (vsBuffnpages>0) {
280 	    unmaptouser(vsBuffpage);
281 	    vsBuffpage += NBPG;
282 	    vsBuffnpages--;
283 	}
284 #endif
285 }
286 
287 vsread(dev,uio)
288 dev_t   dev;
289 struct uio      *uio;
290 {
291         return(-1);
292 }
293 
294 vswrite(dev, uio)
295 dev_t   dev;
296 struct uio      *uio;
297 {
298         return(-1);
299 }
300 
301 /*ARGSUSED*/
302 vsioctl(dev, cmd, addr, flag)
303 dev_t dev;
304 register caddr_t addr;
305 {
306 	register struct uba_device *uip = vsdinfo[VSUNIT(dev)];
307 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
308 	register struct vsdevice *vsaddr = (struct vsdevice *) uip->ui_addr;
309 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
310 	struct vs_fparm vsAddr;
311 	int s;
312 	int func;
313 	int ret;
314 
315 	switch(cmd) {			/* things that don't need the device */
316 	case VSIOWAITGO:
317 		/* wait for user I/O operation to complete, then go */
318 		s = spl5();
319 		if ((ret = vsb->vsioa.status) == 0) {
320 			vsp->vs_nextgo.fparm_all = ((struct vs_fparm *) addr)->fparm_all;
321 			do {
322 				tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_WAIT, 0);
323 			} while (vsp->vs_nextgo.fparm_all);
324 			ret = vsp->vs_status;
325 		} else {
326 			vsaddr->vs_pr1 = ((struct vs_fparm *)addr)->fparm_low;
327 			vsaddr->vs_pr2 = ((struct vs_fparm *)addr)->fparm_high;
328 			vsb->vsioa.status = 0;
329 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
330 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
331 		}
332 		splx(s);
333 		if (ret & VS_ERROR)
334 			return ((ret & VS_REASON) + 128);
335 		return(0);
336 
337 	case VSIOUSERWAIT:
338 		/* wait for user I/O operation to complete */
339 		s = spl5();
340 		while (vsb->vsioa.status == 0) {
341 			tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_USRWAIT, 0);
342 		}
343 		splx(s);
344 		return (0);
345 
346 	case VSIOGETVER:		/* get ROM version */
347 		if (!vsp->inited)
348 			return(ENODEV);
349 		*(int *) addr = vsp->romVersion;
350 		return(0);
351 
352 	case VSIOGETSTATS:		/* get statistics block */
353 		*(vsStats *)addr = vsp->stats;
354 		return(0);
355 
356 	case VSIOGETIOA:		/* get io addresses */
357 		if (vsp->vsBuff_ubinfo==0) {
358 		    return(EIO);
359 		}
360 		*((vsIoAddrAddr *)addr) = &vsb->vsioa;
361 		return(0);
362 
363 	default:			/* a command that could block */
364 		if (ret = vsError(vsp))
365 			return(ret);
366 		break;
367 	}
368 
369 	switch(cmd) {			/* Commands that cause an interrupt */
370 	case VSIOINIT:			/* initialize device */
371 		vsInitDev(dev, FALSE);
372 		return(vsError(vsp));
373 
374 	case VSIOSTART:			/* start microcode */
375 		vsAddr.fparm_all = *(caddr_t *)addr;
376 		s = spl5();
377 		vsaddr->vs_pr1 = vsAddr.fparm_low;
378 		vsaddr->vs_pr2 = vsAddr.fparm_high;
379 		vsaddr->vs_irr = 0;
380 		vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
381 		vsaddr->vs_csr0 |= (VS_IE | (VS_START << VS_FCSHIFT) | VS_GO);
382 		/* synchronous */
383 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_START, 0);
384 		splx(s);
385 		return(vsError(vsp));
386 
387 	case VSIOABORT:			/* abort a command chain */
388 		s = spl5();
389 		vsaddr->vs_irr = 0;
390 		vsaddr->vs_csr0 &= ~VS_FCN;
391 		vsaddr->vs_csr0 |= (VS_IE | (VS_ABORT << VS_FCSHIFT) | VS_GO);
392 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_ABORT, 0);
393 		splx(s);
394 		return(vsError(vsp));
395 
396 	case VSIOPWRUP:			/* power-up reset */
397 		s = spl5();
398 		vsaddr->vs_irr = 0;
399 		vsaddr->vs_csr0 &= ~VS_FCN;
400 		vsaddr->vs_csr0 |= (VS_IE | (VS_PWRUP << VS_FCSHIFT) | VS_GO);
401 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_PWRUP, 0);
402 		splx(s);
403 		return(vsError(vsp));
404 
405 	case VSIOBBACTL:		/* enable/disable BBA */
406 		s = spl5();
407 		vsaddr->vs_irr = 0;
408 		vsaddr->vs_csr0 &= ~VS_FCN;
409 		func = *(int *)addr == VSIO_ON ? VS_ENABBA : VS_DISBBA;
410 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
411 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_IOBCTL, 0);
412 		splx(s);
413 		return(vsError(vsp));
414 
415 	case VSIOFIBCTL:		/* turn the fiber lamp on/off */
416 		s = spl5();
417 		if (*(int *)addr == VSIO_OFF)
418 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
419 		else
420 			vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);
421 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_FIB, 0);
422 		splx(s);
423 		return(vsError(vsp));
424 
425 	case VSIOFIBRETRY:		/* set fiber retries */
426 		s = spl5();
427 		vsaddr->vs_irr = 0;
428 		vsaddr->vs_csr0 &= ~VS_FCN;
429 		func = *(int *)addr == VS_FIB_FINITE ? VS_FINITE : VS_INFINITE;
430 		vsaddr->vs_csr0 |= (VS_IE | (func << VS_FCSHIFT) | VS_GO);
431 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_FIBRET, 0);
432 		splx(s);
433 		return(vsError(vsp));
434 
435 	case VSIOSYNC:			/* get synchronized with device */
436 		break;
437 
438 	default:
439 		return(ENOTTY);
440 	}
441 
442 	return(0);
443 }
444 
445 vsintr(dev)
446 dev_t dev;
447 {
448 	register struct vsdevice *vsaddr;
449 	register struct vs_softc *vsp;
450 	register vsEvent *vep;
451 	struct uba_device *uip;
452 	register struct vsBuffArea *vsb;
453 	int i;
454 	vsCursor cur;
455 
456 	if (VSUNIT(dev) >= NVS || (uip = vsdinfo[VSUNIT(dev)]) == 0
457 	    || uip->ui_alive == 0) {
458 		printI("vs%d stray interrupt\n", VSUNIT(dev));
459 		return;
460 	}
461 
462 	vsaddr = (struct vsdevice *) uip->ui_addr;
463 	vsp = &vs_softc[VSUNIT(dev)];
464 	vsb = &vsBuff[VSUNIT(dev)];
465 #ifdef notdef
466 	printM("vsintr csr0=%x, csr1=%x, csr2=%x, csr3=%x, csr4=%x, csr5=%x, csr6=%x, csr7=%x\n",
467 		vsaddr->vs_csr0, vsaddr->vs_csr1, vsaddr->vs_csr2, vsaddr->vs_csr3,
468 		vsaddr->vs_csr4, vsaddr->vs_csr5, vsaddr->vs_csr6, vsaddr->vs_csr7);
469 
470 	printI("vs%dintr ", VSUNIT(dev));
471 #endif
472 
473 	/*
474 	 * get the information out of the soft registers
475 	 */
476 
477 	vsp->irr.intr_reg = vsaddr->vs_irr;
478 	vsp->krr.kbd_reg = vsaddr->vs_krr;
479 	vsp->pr.fparm_low = vsaddr->vs_pr1;
480 	vsp->pr.fparm_high = vsaddr->vs_pr2;
481 	cur.x = vsaddr->vs_cxr;
482 	cur.y = vsaddr->vs_cyr;
483 	vsp->csr.csr_reg = vsaddr->vs_csr0;
484 
485 	if (vsp->irr.intr_reason)
486 		vsaddr->vs_irr = 0;	/* clear int reason, if any */
487 
488 	vsaddr->vs_csr0 &= ~VS_OWN;	/* clear owner bit */
489 
490 	if (vsp->csr.csr_linkTran) {
491 		vsaddr->vs_csr0 &= ~VS_LNK_TRNS;	/* clear the bit */
492 		printI("link transition: ");
493 		if (vsp->csr.csr_linkErr)
494 			vsp->stats.linkErrors++;
495 
496 		if (vsp->csr.csr_linkAvail == vsp->linkAvail) {	/* flash */
497 			vsp->stats.flashes++;
498 			printI("flash\n");
499 		} else if (!vsp->csr.csr_linkAvail && vsp->linkAvail) { /* on -> off */
500 			vsp->stats.douses++;
501 			printI("douse\n");
502 			vsp->inited = FALSE;
503 			if (vsp->open && vsp->pgrp)
504 				gsignal(vsp->pgrp, SIGHUP);
505 			wakeup((caddr_t) vsp);
506 		} else {						/* off -> on */
507 			vsp->stats.ignites++;
508 			printI("ignite\n");
509 			wakeup((caddr_t) vsp);
510 		}
511 
512 		i = 200;
513 		while ((vsaddr->vs_csr0 & VS_LNK_TRNS) && i)
514 			i--;
515 		if (i == 0) {		/* bit stuck */
516 			printI("vs%d: Link Transition bit stuck\n", VSUNIT(dev));
517 			vsp->inited = FALSE;
518 			if (vsp->open && vsp->pgrp)
519 				gsignal(vsp->pgrp, SIGHUP);
520 			vsaddr->vs_csr0 &= ~VS_XMIT_ON;
521 			vsp->csr.csr_linkAvail = FALSE;
522 		}
523 
524 		vsp->linkAvail = vsp->csr.csr_linkAvail;
525 
526 		return;
527 	}
528 
529 	if (vsp->irr.intr_error) {
530 		printI("error 0x%x\n", vsp->irr.intr_reg&0xffff);
531 		vsp->stats.errors++;
532 		/* set status and wake up user if necessary */
533 		if (vsp->vs_nextgo.fparm_all) {
534 			vsp->vs_status = vsp->irr.intr_reg;
535 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
536 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
537 			vsp->vs_nextgo.fparm_all = NULL;
538 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
539 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
540 		} else
541 			vsb->vsioa.status = vsp->irr.intr_reg;
542 		wakeup((caddr_t) vsp);
543 		return;
544 	}
545 
546 #ifdef notdef
547 	printI("reason is %b\n", vsp->irr.intr_reason, VSIRR_BITS);
548 #endif
549 	switch(vsp->irr.intr_reason) {
550 	case VS_INT_CD:			/* command done */
551 		/* set status and start a new command if necessary */
552 		if (vsp->vs_nextgo.fparm_all) {
553 			vsp->vs_status = vsp->irr.intr_reg;
554 			vsaddr->vs_pr1 = vsp->vs_nextgo.fparm_low;
555 			vsaddr->vs_pr2 = vsp->vs_nextgo.fparm_high;
556 			vsp->vs_nextgo.fparm_all = NULL;
557 			vsaddr->vs_csr0 &= ~VS_FCN;	/* clear bits */
558 			vsaddr->vs_csr0 |= (VS_IE | (VS_SEND << VS_FCSHIFT) | VS_GO);
559 		} else
560 			vsb->vsioa.status = vsp->irr.intr_reg;
561 		break;
562 
563 	case VS_INT_MM:			/* mouse moved */
564 
565 		vsb->vsioa.mouse = cur;
566 
567                 if (!vsp->open)
568                         return;         /* ignore on closed device */
569 
570 		/* no event if inside box */
571 		if (cur.y < vsb->vsioa.mbox.bottom &&
572 		    cur.y >= vsb->vsioa.mbox.top &&
573 		    cur.x < vsb->vsioa.mbox.right &&
574 		    cur.x >= vsb->vsioa.mbox.left)
575 		    return;
576 
577 		/* trash box */
578 		vsb->vsioa.mbox.bottom = 0;
579 
580 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
581 		    return;
582 		i = EVROUND(vsb->vsioa.itail-1);
583 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
584 		    (i != vsb->vsioa.ihead)) {
585 		    vep = &vsb->ibuff[i];
586 		    if (vep->vse_type == VSE_MMOTION) {
587 			vep->vse_x = cur.x;
588 			vep->vse_y = cur.y;
589 			vep->vse_time = mfpr(TODR);
590 			return;
591 		    }
592 		}
593 		/* put event into queue and do select */
594 		vep = &vsb->ibuff[vsb->vsioa.itail];
595 		vep->vse_type = VSE_MMOTION;
596 		vep->vse_x = cur.x;
597 		vep->vse_y = cur.y;
598 		vep->vse_time = mfpr(TODR);
599 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
600 		if (vsp->rsel) {
601 			selwakeup(vsp->rsel, 0);
602 			vsp->rsel = 0;
603 		}
604 		break;
605 
606 	case VS_INT_BE:			/* button event */
607 		if (!vsp->open)
608 			return;		/* ignore on closed device */
609 
610 		if (vsp->krr.kbd_device == VSE_MOUSE) {
611 		    vsb->vsioa.mouse.x = cur.x;
612 		    vsb->vsioa.mouse.y = cur.y;
613 		}
614 		/* check for room in the queue */
615 		if ((i = EVROUND(vsb->vsioa.itail+1)) == vsb->vsioa.ihead)
616 		    return;
617 		/* put event into queue and do select */
618 		vep = &vsb->ibuff[vsb->vsioa.itail];
619 		vep->vse_type = VSE_BUTTON;
620 		vep->vse_key = vsp->krr.kbd_key;
621 		vep->vse_direction = vsp->krr.kbd_transition;
622 		vep->vse_device = vsp->krr.kbd_device;
623 	        vep->vse_time = mfpr(TODR);
624 		vep->vse_x = vsb->vsioa.mouse.x;
625 		vep->vse_y = vsb->vsioa.mouse.y;
626 		vsb->vsioa.itail = i;
627 		if (vsp->rsel) {
628 			selwakeup(vsp->rsel, 0);
629 			vsp->rsel = 0;
630 		}
631 		break;
632 
633 	case VS_INT_TM:			/* tablet moved */
634 		if (!vsp->open)
635 			return;		/* ignore on closed device */
636 
637 		if (EVROUND(vsb->vsioa.itail+1) == vsb->vsioa.ihead)
638 		    return;
639 		i = EVROUND(vsb->vsioa.itail-1);
640 		if ((vsb->vsioa.itail != vsb->vsioa.ihead) &&
641 		    (i != vsb->vsioa.ihead)) {
642 		    vep = &vsb->ibuff[i];
643 		    if (vep->vse_type == VSE_TMOTION) {
644 			vep->vse_x = cur.x;
645 			vep->vse_y = cur.y;
646 			vep->vse_time = mfpr(TODR);
647 			return;
648 		    }
649 		}
650 		/* put event into queue and do select */
651 		vep = &vsb->ibuff[vsb->vsioa.itail];
652 		vep->vse_type = VSE_TMOTION;
653 		vep->vse_x = cur.x;
654 		vep->vse_y = cur.y;
655 		vep->vse_time = mfpr(TODR);
656 		vsb->vsioa.itail = EVROUND(vsb->vsioa.itail+1);
657 		if (vsp->rsel) {
658 			selwakeup(vsp->rsel, 0);
659 			vsp->rsel = 0;
660 		}
661 		break;
662 
663 	case VS_INT_US:			/* unsolicited */
664 		vsp->stats.unsolIntr++;
665 		return;
666 
667 	case VS_INT_ID:			/* Initialization done */
668 					/* save offset from device */
669 		vsp->offset.fparm_all = vsp->pr.fparm_all;
670 					/* save rom version */
671 		vsp->romVersion = cur.x;
672 		vsp->inited = TRUE;
673 		break;
674 
675 	case VS_INT_SE:			/* ucode started */
676 		break;
677 
678 	case VS_INT_PWR:		/* power up complete */
679 					/* save rom version */
680 		vsp->romVersion = cur.x;
681 		vsp->inited = FALSE;
682 		if (vsp->open && vsp->pgrp)
683 			gsignal(vsp->pgrp, SIGHUP);
684 		break;
685 
686 	default:
687 		printI("vs%d: unknown interrupt %b\n", VSUNIT(dev),
688 			vsp->irr.intr_reason, VSIRR_BITS);
689 		return;
690 	}
691 	wakeup((caddr_t) vsp);
692 }
693 
694 vsreset(uban)
695 int uban;
696 {
697 	register int i;
698 	register struct uba_device *uip;
699 	register struct vs_softc *vsp = vs_softc;
700 
701 	for (i = 0; i < NVS; i++, vsp++) {
702 		if ((uip = vsdinfo[i]) == 0 || uip->ui_alive == 0 ||
703 		    uip->ui_ubanum != uban || vsp->open == 0)
704 			continue;
705 		printf(" vs%d", i);
706 		vsp->inited = FALSE;
707 		if (vsp->open && vsp->pgrp)
708 			gsignal(vsp->pgrp, SIGHUP);
709 	}
710 }
711 
712 vsselect(dev, rw)
713 dev_t dev;
714 {
715 	register struct vsBuffArea *vsb = &vsBuff[VSUNIT(dev)];
716 	int s = spl5();
717 
718 	switch(rw) {
719 	case FREAD:
720 		if (vsb->vsioa.ihead != vsb->vsioa.itail) {
721 		    splx(s);
722 		    return(1);
723 		}
724 		vs_softc[VSUNIT(dev)].rsel = u.u_procp;
725 		splx(s);
726 		return(0);
727 
728 	case FWRITE:
729 		splx(s);
730 		return(EACCES);
731 	}
732 }
733 
734 /*
735  * Initialize VS100 or SBO.
736  * Set XMITON.  VS100 will respond with link available.  SBO won't, so
737  * don't wait forever; assume everything is OK and warn user.
738  */
739 
740 vsInitFiber(dev)
741 dev_t dev;
742 {
743 	struct vsdevice *vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
744 	register struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
745 	int s;
746 #ifdef VSSBO
747 	int vsFiberNudge();
748 
749 	timeout(vsFiberNudge, (caddr_t) dev, 2*hz);
750 #endif
751 	s = spl5();
752 	vsaddr->vs_csr0 |= (VS_IE | VS_XMIT_ON);	/* turn link on */
753 	tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_INITF, 0);
754 	splx(s);
755 #ifdef VSSBO
756 	if (!vsp->linkAvail) {
757 		uprintf("\007This had better be a vs125!\n");
758 		printf("vs%d must be a vs125\n", VSUNIT(dev));
759 		vsp->linkAvail = TRUE;
760 	}
761 #endif
762 }
763 
764 #ifdef VSSBO
765 vsFiberNudge(dev)
766 dev_t dev;
767 {
768 	struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
769 
770 	if (!vsp->linkAvail)
771 		wakeup((caddr_t) vsp);
772 }
773 #endif VSSBO
774 
775 vsInitDev(dev, retry)
776 dev_t dev;
777 int retry;
778 {
779 	register struct vsdevice *vsaddr;
780 	register struct vs_softc *vsp;
781 	int s;
782 	int vsInitNudge();
783 
784 	vsaddr = (struct vsdevice *) vsdinfo[VSUNIT(dev)]->ui_addr;
785 	vsp = &vs_softc[VSUNIT(dev)];
786 
787 	if (!vsp->linkAvail)
788 		vsInitFiber(dev);
789 	while (1) {
790 		if (retry)
791 			timeout(vsInitNudge, (caddr_t) dev, 10*hz);
792 		s = spl5();
793 		vsaddr->vs_irr = 0;
794 		vsaddr->vs_csr0 &= ~VS_FCN;
795 		vsaddr->vs_csr0 |= (VS_IE | (VS_INIT << VS_FCSHIFT) | VS_GO);
796 		tsleep((caddr_t) vsp, VSWAITPRI, SLP_VS_INITDEV, 0);
797 		splx(s);
798 		if (vsp->inited)
799 			break;
800 		printM("vs%d: VS_INIT fails\n", VSUNIT(dev));
801 		uprintf("vsInitDev %x %x\n",vsaddr->vs_csr0, vsaddr->vs_csr1);
802 	}
803 }
804 
805 vsInitNudge(dev)
806 dev_t dev;
807 {
808 	struct vs_softc *vsp = &vs_softc[VSUNIT(dev)];
809 
810 	if (!vsp->inited)
811 		wakeup((caddr_t) vsp);
812 }
813 
814 vsError(vsp)
815 	register struct vs_softc *vsp;
816 {
817 	if (vsp->irr.intr_error) {
818 		register int ret = vsp->irr.intr_reg;
819 
820 		printD("\treturning 0x%x\n", ret);
821 		vsp->irr.intr_reg = 0;
822 		return(ret+128);
823 	}
824 	return(0);
825 }
826 #endif
827 
828