1 /* @(#)vs.c 7.8 (MIT) 12/16/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 "../include/pte.h"
28
29 #include "sys/param.h"
30 #include "sys/user.h"
31 #include "sys/buf.h"
32 #include "sys/systm.h"
33 #include "sys/map.h"
34 #include "sys/kernel.h"
35 #include "sys/ioctl.h"
36
37 #include "vsio.h"
38
39 #include "sys/proc.h"
40 #include "sys/uio.h"
41 #include "sys/vmmac.h"
42 #include "sys/file.h"
43
44 #include "ubareg.h"
45 #include "ubavar.h"
46 #include "vsreg.h"
47
48 #include "../include/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
vsprobe(reg)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
vsopen(dev,flag)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
vsclose(dev)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
vsread(dev,uio)289 vsread(dev,uio)
290 dev_t dev;
291 struct uio *uio;
292 {
293 return(-1);
294 }
295
vswrite(dev,uio)296 vswrite(dev, uio)
297 dev_t dev;
298 struct uio *uio;
299 {
300 return(-1);
301 }
302
303 /*ARGSUSED*/
vsioctl(dev,cmd,addr,flag)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
vsintr(dev)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
vsreset(uban)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
vsselect(dev,rw)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 default:
747 splx(s);
748 return(0); /* can never write */
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
vsInitFiber(dev)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
vsInitDev(dev,retry)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
vsError(vsp)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