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