Commit | Line | Data |
---|---|---|
e6453f14 | 1 | /* vx.c 1.4 86/01/12 */ |
b8c32975 SL |
2 | |
3 | #include "vx.h" | |
4 | #if NVX > 0 | |
5 | /* | |
336ca318 | 6 | * VIOC-X driver |
b8c32975 | 7 | */ |
9d915fad | 8 | #include "../tahoe/pte.h" |
b8c32975 SL |
9 | |
10 | #include "../h/param.h" | |
11 | #include "../h/ioctl.h" | |
12 | #include "../h/tty.h" | |
13 | #include "../h/dir.h" | |
14 | #include "../h/user.h" | |
15 | #include "../h/map.h" | |
b8c32975 | 16 | #include "../h/buf.h" |
b8c32975 SL |
17 | #include "../h/conf.h" |
18 | #include "../h/file.h" | |
19 | #include "../h/uio.h" | |
9d915fad SL |
20 | #include "../h/proc.h" |
21 | #include "../h/vm.h" | |
22 | ||
23 | #include "../tahoevba/vbavar.h" | |
24 | #include "../tahoevba/vioc.h" | |
b8c32975 | 25 | #ifdef VXPERF |
9d915fad | 26 | #include "../tahoevba/scope.h" |
b8c32975 SL |
27 | #endif VXPERF |
28 | #include "vbsc.h" | |
29 | #if NVBSC > 0 | |
e6453f14 SL |
30 | #include "../tahoebsc/bscio.h" |
31 | #include "../tahoebsc/bsc.h" | |
b8c32975 SL |
32 | char bscport[NVXPORTS]; |
33 | #endif | |
34 | ||
35 | #ifdef BSC_DEBUG | |
e6453f14 | 36 | #include "../tahoebsc/bscdebug.h" |
b8c32975 SL |
37 | #endif |
38 | ||
39 | #ifdef VX_DEBUG | |
40 | long vxintr4 = 0; | |
41 | long vxdebug = 0; | |
e6453f14 | 42 | #include "../tahoevba/vxdebug.h" |
b8c32975 SL |
43 | #endif |
44 | ||
45 | #define RSPquals 1 | |
46 | ||
336ca318 SL |
47 | struct vcx vcx[NVIOCX] ; |
48 | struct tty vx_tty[NVXPORTS]; | |
49 | extern struct vcmds v_cmds[]; | |
50 | extern long reinit; | |
b8c32975 SL |
51 | |
52 | int vxstart() ; | |
53 | int ttrstrt() ; | |
336ca318 SL |
54 | struct vxcmd *vobtain() ; |
55 | struct vxcmd *nextcmd() ; | |
b8c32975 SL |
56 | |
57 | /* | |
58 | * Driver information for auto-configuration stuff. | |
59 | * (not tested and probably should be changed) | |
60 | */ | |
61 | int vxprobe(), vxattach(), vxrint(); | |
62 | struct vba_device *vxinfo[NVIOCX]; | |
63 | long vxstd[] = { 0 }; | |
64 | struct vba_driver vxdriver = | |
336ca318 | 65 | { vxprobe, 0, vxattach, 0, vxstd, "vx", vxinfo }; |
b8c32975 | 66 | |
336ca318 SL |
67 | char vxtype[NVIOCX]; /* 0: viox-x/vioc-b; 1: vioc-bop */ |
68 | char vxbbno = -1; | |
69 | char vxbopno[NVIOCX]; /* BOP board no. if indicated by vxtype[] */ | |
70 | int vxivec[NVIOCX]; /* interrupt vector base */ | |
71 | extern vbrall(); | |
b8c32975 | 72 | |
336ca318 | 73 | vxprobe(reg, vi) |
b8c32975 | 74 | caddr_t reg; |
336ca318 | 75 | struct vba_device *vi; |
b8c32975 | 76 | { |
336ca318 | 77 | register int br, cvec; /* must be r12, r11 */ |
b8c32975 SL |
78 | register struct vblok *vp = (struct vblok *)reg; |
79 | ||
80 | #ifdef lint | |
81 | br = 0; cvec = br; br = cvec; | |
9d915fad | 82 | vackint(0); vunsol(0); vcmdrsp(0); vxfreset(0); |
b8c32975 | 83 | #endif |
9d915fad SL |
84 | if (badaddr((caddr_t)vp, 1)) |
85 | return (0); | |
86 | vp->v_fault = 0; | |
87 | vp->v_vioc = V_BSY; | |
88 | vp->v_hdwre = V_RESET; /* reset interrupt */ | |
b8c32975 | 89 | DELAY(4000000); |
9d915fad SL |
90 | if (vp->v_fault != VREADY) |
91 | return (0); | |
336ca318 SL |
92 | #ifdef notdef |
93 | /* | |
94 | * Align vioc interrupt vector base to 4 vector | |
95 | * boundary and fitting in 8 bits (is this necessary, | |
96 | * wish we had documentation). | |
97 | */ | |
98 | if ((vi->ui_hd->vh_lastiv -= 3) > 0xff) | |
99 | vi->ui_hd->vh_lastiv = 0xff; | |
100 | vxivec[vi->ui_unit] = vi->ui_hd->vh_lastiv = | |
101 | vi->ui_hd->vh_lastiv &~ 0x3; | |
102 | #else | |
103 | vxivec[vi->ui_unit] = 0x40+vi->ui_unit*4; | |
104 | #endif | |
105 | br = 0x18, cvec = vxivec[vi->ui_unit]; /* XXX */ | |
9d915fad | 106 | return (sizeof (*vp)); |
b8c32975 SL |
107 | } |
108 | ||
336ca318 SL |
109 | vxattach(vi) |
110 | register struct vba_device *vi; | |
b8c32975 | 111 | { |
9d915fad | 112 | |
336ca318 SL |
113 | VIOCBAS[vi->ui_unit] = vi->ui_addr; |
114 | vxinit(vi->ui_unit, (long)1); | |
b8c32975 SL |
115 | } |
116 | ||
117 | /* | |
118 | * Open a VX line. | |
119 | */ | |
9d915fad | 120 | /*ARGSUSED*/ |
b8c32975 SL |
121 | vxopen(dev, flag) |
122 | { | |
123 | register struct tty *tp; /* pointer to tty struct for port */ | |
124 | register struct vcx *xp; /* pointer to VIOC-X info/cmd buffer */ | |
125 | register d; /* minor device number */ | |
126 | register long jj; | |
127 | ||
128 | ||
129 | d = minor(dev); /* get minor device number */ | |
130 | if (d >= NVXPORTS) /* validate minor device number */ | |
131 | return ENXIO; /* set errno to indicate bad port # */ | |
132 | tp = &vx_tty[d]; /* index the tty structure for port */ | |
133 | ||
134 | xp = &vcx[d>>4]; /* index VIOC-X info/cmd area */ | |
135 | d &= 017; | |
136 | ||
137 | /* If we did not find a board with the correct port number on | |
138 | it, or the entry for the VIOC-X had no ports on it, inform the | |
139 | caller that the port does not exist. */ | |
140 | if(!( xp->v_loport <= d && d <= xp->v_hiport ) /* home? */ | |
141 | || (xp->v_hiport - xp->v_loport)==0) | |
142 | return ENXIO; /* bad minor device number */ | |
143 | tp->t_addr = (caddr_t)xp; /* store address of VIOC-X info */ | |
144 | tp->t_oproc = vxstart; /* store address of startup routine */ | |
145 | tp->t_dev = dev; /* store major/minor device numbers */ | |
146 | d = spl8(); | |
147 | tp->t_state |= TS_WOPEN; /* mark device as waiting for open */ | |
148 | if ((tp->t_state&TS_ISOPEN) == 0) /* is device already open? */ | |
149 | { /* no, open it */ | |
150 | ttychars(tp); /* set default control chars */ | |
151 | if (tp->t_ispeed == 0) /* if no default speeds set them */ | |
152 | { | |
153 | tp->t_ispeed = SSPEED; /* default input baud */ | |
154 | tp->t_ospeed = SSPEED; /* default output baud */ | |
155 | tp->t_flags |= (ODDP|EVENP|ECHO); /* default modes */ | |
156 | } | |
157 | vxparam(dev); /* set parameters for this port */ | |
158 | } | |
159 | splx(d); | |
160 | /* ? if already open for exclusive use open fails unless caller is | |
161 | root. */ | |
162 | if (tp->t_state&TS_XCLUDE && u.u_uid!=0) | |
163 | return EBUSY; /* device is busy, sorry */ | |
164 | ||
165 | /* wait for data carrier detect to go high */ | |
166 | d = spl8(); | |
167 | if( !vcmodem(dev,VMOD_ON) ) | |
168 | while( (tp->t_state&TS_CARR_ON) == 0 ) | |
9d915fad | 169 | sleep((caddr_t)&tp->t_canq,TTIPRI); |
b8c32975 SL |
170 | jj= (*linesw[tp->t_line].l_open)(dev,tp); /*let tty.c finish the open */ |
171 | splx(d); /* 1/2/85 : assures open complete */ | |
172 | return (jj); | |
173 | } | |
174 | ||
175 | /* | |
176 | * Close a VX line. | |
177 | */ | |
9d915fad | 178 | /*ARGSUSED*/ |
b8c32975 SL |
179 | vxclose(dev, flag) |
180 | dev_t dev; | |
181 | int flag; | |
182 | { | |
183 | register struct tty *tp; | |
184 | register d; | |
185 | ||
186 | d = minor(dev) & 0377; | |
187 | tp = &vx_tty[d]; | |
188 | d = spl8(); | |
189 | (*linesw[tp->t_line].l_close)(tp); | |
190 | if ((tp->t_state&TS_ISOPEN) && (tp->t_state&TS_HUPCLS)) | |
191 | if( !vcmodem(dev,VMOD_OFF) ) | |
192 | tp->t_state &= ~TS_CARR_ON; | |
193 | /* wait for the last response */ | |
194 | while(tp->t_state & TS_FLUSH) | |
195 | sleep( (caddr_t)&tp->t_state, TTOPRI ) ; | |
196 | ttyclose(tp); /* let tty.c finish the close */ | |
197 | splx(d); | |
198 | } | |
199 | ||
200 | /* | |
201 | * Read from a VX line. | |
202 | */ | |
203 | vxread(dev, uio) | |
204 | dev_t dev; | |
205 | struct uio *uio; | |
206 | { | |
207 | register struct tty *tp = &vx_tty[minor(dev) & 0377]; | |
208 | return (*linesw[tp->t_line].l_read)(tp, uio); | |
209 | } | |
210 | ||
211 | /* | |
212 | * write on a VX line | |
213 | */ | |
214 | vxwrite(dev, uio) | |
215 | dev_t dev; | |
216 | struct uio *uio; | |
217 | { | |
218 | register struct tty *tp = &vx_tty[minor(dev) & 0377]; | |
219 | return (*linesw[tp->t_line].l_write)(tp, uio); | |
220 | } | |
221 | ||
222 | /* | |
223 | * VIOCX unsolicited interrupt. | |
224 | */ | |
225 | vxrint(n) | |
226 | register n; /* mux number */ | |
227 | { | |
228 | register struct tty *tp; | |
229 | register struct vcx *xp; | |
230 | register short *sp; | |
231 | register struct vblok *kp; | |
232 | register int i, c; | |
233 | short *savsilo; | |
234 | struct silo { | |
235 | char data; | |
236 | char port; | |
237 | }; | |
238 | ||
239 | kp = VBAS(n); | |
240 | xp = &vcx[n]; | |
241 | switch(kp->v_uqual&037) { | |
242 | case 0: | |
243 | break; | |
244 | case 2: | |
245 | printf(" ERR NBR %x\n",kp->v_ustat); | |
246 | vpanic("vc: VC PROC ERR"); | |
247 | vxstreset(n); | |
248 | return(0); | |
249 | case 3: | |
250 | vcmintr(n); | |
251 | return(1); | |
252 | case 4: | |
253 | return(1); | |
254 | default: | |
255 | printf(" ERR NBR %x\n",kp->v_uqual); | |
256 | vpanic("vc: VC UQUAL ERR"); | |
257 | vxstreset(n); | |
258 | return(0); | |
259 | } | |
260 | if(xp->v_vers == V_NEW) { | |
261 | register short *aa ; | |
262 | aa = (short *)kp->v_usdata; | |
263 | sp = (short *)(*aa + (char *)kp) ; | |
264 | } else { | |
265 | c = kp->v_usdata[0] << 6; | |
266 | sp = (short *)((char *)kp + SILOBAS + c); | |
267 | } | |
b8c32975 SL |
268 | i = *(savsilo = sp); |
269 | if (i == 0) return(1); | |
270 | if(xp->v_vers == V_NEW) | |
271 | if( i > xp->v_silosiz ) { | |
272 | printf("vx: %d exceeds silo size\n",i) ; | |
273 | i = xp->v_silosiz; | |
274 | } | |
275 | for(sp++;i > 0;i--,sp++) { | |
276 | c = ((struct silo *)sp)->port & 017; | |
277 | tp = &vx_tty[c+n*16]; | |
278 | if(xp->v_loport > c || c > xp->v_hiport) | |
279 | continue; /* port out of bounds */ | |
280 | if( (tp->t_state & TS_ISOPEN) == 0) { | |
281 | wakeup((caddr_t)&tp->t_rawq); | |
282 | continue; | |
283 | } | |
284 | c = ((struct silo *)sp)->data; | |
285 | switch(((struct silo *)sp)->port&(PERROR|FERROR)) { | |
286 | case PERROR: | |
287 | case PERROR|FERROR: | |
288 | if( (tp->t_flags&(EVENP|ODDP)) == EVENP | |
289 | || (tp->t_flags & (EVENP|ODDP)) == ODDP ) | |
290 | continue; | |
291 | if(!(((struct silo *)sp)->port&FERROR)) | |
292 | break; | |
293 | case FERROR: | |
294 | if(tp->t_flags & RAW) c = 0; | |
295 | else c = tp->t_intrc; | |
296 | } | |
297 | (*linesw[tp->t_line].l_rint)(c, tp); | |
298 | } | |
299 | *savsilo = 0; | |
300 | return(1); | |
301 | } | |
302 | ||
303 | /* | |
304 | * stty/gtty for VX | |
305 | */ | |
306 | vxioctl(dev, cmd, data, flag) | |
307 | int dev; /* major, minor device numbers */ | |
308 | int cmd; /* command */ | |
309 | caddr_t data; | |
310 | int flag; | |
311 | { | |
312 | register struct tty *tp; | |
313 | register error; | |
314 | ||
315 | tp = &vx_tty[minor(dev) & 0377]; | |
316 | error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); | |
317 | if (error == 0) | |
318 | return error; | |
319 | if((error = ttioctl(tp, cmd, data, flag)) >= 0) | |
320 | { | |
321 | if (cmd==TIOCSETP||cmd==TIOCSETN) | |
322 | vxparam(dev); | |
323 | return error; | |
324 | } else | |
325 | return ENOTTY; | |
326 | } | |
327 | ||
328 | ||
329 | vxparam(dev) | |
330 | dev_t dev; | |
331 | { | |
332 | vxcparam(dev, 1); | |
333 | } | |
334 | ||
335 | /* | |
336 | * Set parameters from open or stty into the VX hardware | |
337 | * registers. | |
338 | */ | |
339 | vxcparam(dev, wait) | |
340 | dev_t dev; /* major, minor device numbers */ | |
341 | int wait; /* nonzero if we should wait for finish */ | |
342 | { | |
343 | register struct tty *tp; | |
344 | register struct vcx *xp; | |
345 | register struct vxcmd *cp; | |
346 | register s; | |
347 | ||
348 | tp = &vx_tty[minor(dev)]; /* pointer to tty structure for port */ | |
349 | xp = (struct vcx *)tp->t_addr; /* pointer to VIOCX info/cmd buffer */ | |
350 | cp = vobtain(xp); | |
351 | s = spl8(); | |
352 | cp->cmd = LPARAX; /* set command to "load parameters" */ | |
353 | cp->par[1] = minor(dev)&017; /* port number */ | |
354 | ||
355 | cp->par[2] = (tp->t_flags&RAW)? 0 : tp->t_startc; /* XON char */ | |
356 | cp->par[3] = (tp->t_flags&RAW)? 0 : tp->t_stopc; /* XOFF char */ | |
357 | ||
358 | if(tp->t_flags&(RAW|LITOUT) || | |
359 | (tp->t_flags&(EVENP|ODDP)) == (EVENP|ODDP)) { | |
360 | cp->par[4] = 0xc0; /* 8 bits of data */ | |
361 | cp->par[7] = 0; /* no parity */ | |
362 | } else { | |
363 | cp->par[4] = 0x40; /* 7 bits of data */ | |
364 | if((tp->t_flags&(EVENP|ODDP)) == ODDP) | |
365 | cp->par[7] = 1; /* odd parity */ | |
366 | else if((tp->t_flags&(EVENP|ODDP)) == EVENP) | |
367 | cp->par[7] = 3; /* even parity */ | |
368 | else | |
369 | cp->par[7] = 0; /* no parity */ | |
370 | } | |
371 | cp->par[5] = 0x4; /* 1 stop bit */ | |
372 | cp->par[6] = tp->t_ospeed; | |
373 | ||
9d915fad SL |
374 | if (vcmd(xp->v_nbr, (caddr_t)&cp->cmd) && wait) |
375 | sleep((caddr_t)cp,TTIPRI); | |
b8c32975 SL |
376 | splx(s); |
377 | } | |
378 | ||
379 | /* | |
380 | * VIOCX command response interrupt. | |
381 | * For transmission, restart output to any active port. | |
382 | * For all other commands, just clean up. | |
383 | */ | |
384 | vxxint(n,cp) | |
385 | register int n; /* VIOC number */ | |
386 | register struct vxcmd *cp; /* command structure */ | |
387 | { | |
388 | register struct vxmit *vp, *pvp; | |
389 | register struct tty *tp; | |
390 | register struct vcx *xp; | |
391 | register struct tty *hp; | |
392 | ||
393 | xp = &vcx[n]; | |
394 | cp = (struct vxcmd *)( (long *)cp - 1); | |
395 | #if NVBSC > 0 | |
396 | switch(cp->cmd) { | |
397 | case MDMCTL1: case HUNTMD1: case LPARAX1: | |
398 | vrelease(xp, cp); | |
399 | wakeup(cp); | |
400 | return; | |
401 | } | |
402 | #endif | |
403 | switch(cp->cmd&0xff00) { | |
404 | case LIDENT: /* initialization complete */ | |
405 | if (xp->v_state & V_RESETTING) { | |
406 | vxfnreset(n,cp); | |
407 | vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR); | |
408 | } | |
409 | cp->cmd++; | |
410 | return; | |
411 | case XMITDTA: case XMITIMM: | |
412 | break; | |
413 | case LPARAX: | |
9d915fad | 414 | wakeup((caddr_t)cp); |
b8c32975 SL |
415 | default: /* MDMCTL or FDTATOX */ |
416 | vrelease(xp, cp); | |
417 | if (xp->v_state & V_RESETTING) { | |
418 | vinthandl(n,((V_BSY | RSPquals) << 8) | V_INTR); | |
419 | } | |
420 | return; | |
421 | } | |
422 | for(vp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit); | |
423 | vp >= (struct vxmit *)cp->par; | |
424 | vp = (struct vxmit *) ((char *)vp - sizvxmit) ) | |
425 | { | |
426 | tp = &vx_tty[(vp->line & 017)+n*16]; | |
427 | /* cjk buffer bug */ | |
428 | #if NVBSC > 0 | |
429 | /* bsc change */ | |
430 | if (tp->t_line == LDISP) { | |
431 | vrelease(xp, cp); | |
432 | bsctxd((vp->line & 017)); | |
433 | return ; | |
434 | } | |
435 | /* End of bsc change */ | |
436 | #endif | |
437 | /* cjk */ | |
438 | pvp = vp; | |
439 | tp->t_state &= ~TS_BUSY; | |
440 | if(tp->t_state & TS_FLUSH) { | |
441 | tp->t_state &= ~TS_FLUSH; | |
442 | wakeup( (caddr_t)&tp->t_state ) ; | |
443 | } | |
444 | else | |
445 | ndflush(&tp->t_outq, vp->bcount+1); | |
446 | } | |
447 | xp->v_xmtcnt--; | |
448 | vrelease(xp,cp); | |
449 | if(xp->v_vers == V_NEW) { | |
450 | vp = pvp; | |
451 | xp->v_actport[(vp->line & 017) - xp->v_loport] |= 1 ; | |
452 | if(vxstart(tp) && (cp = nextcmd(xp)) != NULL) | |
453 | { | |
454 | xp->v_xmtcnt++; | |
9d915fad | 455 | vcmd(n, (caddr_t)&cp->cmd); |
b8c32975 SL |
456 | return ; |
457 | } | |
458 | xp->v_actport[(vp->line & 017) - xp->v_loport] = 0 ; | |
459 | return ; | |
460 | } | |
461 | xp->v_actflg = 1; | |
462 | hp = &vx_tty[xp->v_hiport+n*16]; | |
463 | for(tp = &vx_tty[xp->v_loport+n*16];tp <= hp;tp++) | |
464 | if(vxstart(tp) && (cp = nextcmd(xp)) != NULL) | |
465 | { | |
466 | xp->v_xmtcnt++; | |
9d915fad | 467 | vcmd(n, (caddr_t)&cp->cmd); |
b8c32975 SL |
468 | } |
469 | if( (cp = nextcmd(xp)) != NULL ) /* command to send ? */ | |
470 | { | |
471 | xp->v_xmtcnt++; | |
9d915fad | 472 | vcmd(n, (caddr_t)&cp->cmd); |
b8c32975 SL |
473 | } |
474 | xp->v_actflg = 0; | |
475 | } | |
476 | ||
477 | /* | |
478 | * Force out partial XMIT command after timeout | |
479 | */ | |
480 | vxforce(xp) | |
481 | register struct vcx *xp; | |
482 | { | |
483 | register struct vxcmd *cp; | |
484 | register int s; | |
485 | ||
486 | s = spl8(); | |
487 | if((cp = nextcmd(xp)) != NULL) { | |
488 | xp->v_xmtcnt++; | |
9d915fad | 489 | vcmd(xp->v_nbr, (caddr_t)&cp->cmd); |
b8c32975 SL |
490 | } |
491 | splx(s); | |
492 | } | |
493 | ||
494 | /* | |
495 | * Start (restart) transmission on the given VX line. | |
496 | */ | |
497 | vxstart(tp) | |
498 | register struct tty *tp; | |
499 | { | |
9d915fad | 500 | register short n; |
b8c32975 SL |
501 | register struct vcx *xp; |
502 | register char *outb; | |
503 | register full = 0; | |
504 | int k, s, port; | |
505 | ||
506 | s = spl8(); | |
507 | port = minor(tp->t_dev) & 017; | |
508 | xp = (struct vcx *)tp->t_addr; | |
509 | if (!(tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) { | |
510 | if (tp->t_outq.c_cc<=TTLOWAT(tp)) { | |
511 | if (tp->t_state&TS_ASLEEP) { | |
512 | tp->t_state &= ~TS_ASLEEP; | |
513 | wakeup((caddr_t)&tp->t_outq); | |
514 | } | |
515 | if (tp->t_wsel) { | |
516 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
517 | tp->t_wsel = 0; | |
518 | tp->t_state &= ~TS_WCOLL; | |
519 | } | |
520 | } | |
521 | if(tp->t_outq.c_cc == 0) { | |
522 | splx(s); | |
523 | return(0); | |
524 | } | |
525 | #ifdef VXPERF | |
526 | scope_out(3); | |
527 | #endif VXPERF | |
528 | if(!(tp->t_flags&(RAW|LITOUT))) | |
529 | full = 0200; | |
9d915fad | 530 | if((n = ndqb(&tp->t_outq, full)) == 0) { |
b8c32975 | 531 | if(full) { |
9d915fad SL |
532 | n = getc(&tp->t_outq); |
533 | timeout(ttrstrt, (caddr_t)tp, (n&0177) +6); | |
b8c32975 SL |
534 | tp->t_state |= TS_TIMEOUT; |
535 | full = 0; | |
536 | } | |
537 | } else { | |
538 | outb = (char *)tp->t_outq.c_cf; | |
539 | tp->t_state |= TS_BUSY; | |
540 | if(xp->v_vers == V_NEW) | |
541 | k = xp->v_actport[port - xp->v_loport] ; | |
542 | else | |
543 | k = xp->v_actflg ; | |
544 | ||
9d915fad | 545 | full = vsetq(xp, port, outb, n); |
b8c32975 SL |
546 | |
547 | if( (k&1) == 0 ) { /* not called from vxxint */ | |
548 | if(full || xp->v_xmtcnt == 0) { | |
549 | outb = (char *)(&nextcmd(xp)->cmd); | |
550 | xp->v_xmtcnt++; | |
551 | vcmd(xp->v_nbr, outb ); | |
552 | } else | |
9d915fad | 553 | timeout(vxforce,(caddr_t)xp,3); |
b8c32975 SL |
554 | } |
555 | } | |
556 | } | |
557 | splx(s); | |
558 | return(full); /* indicate if max commands or not */ | |
559 | } | |
560 | ||
561 | /* | |
562 | * Stop output on a line. | |
563 | */ | |
564 | vxstop(tp) | |
565 | register struct tty *tp; | |
566 | { | |
567 | register s; | |
568 | ||
569 | s = spl8(); | |
570 | if (tp->t_state & TS_BUSY) { | |
571 | if ((tp->t_state&TS_TTSTOP)==0) { | |
572 | tp->t_state |= TS_FLUSH; | |
573 | } | |
574 | } | |
575 | splx(s); | |
576 | } | |
577 | ||
578 | /* | |
579 | * VIOCX Initialization. Makes free lists of command buffers. | |
580 | * Resets all viocx's. Issues a LIDENT command to each | |
581 | * viocx which establishes interrupt vectors and logical | |
582 | * port numbers | |
583 | */ | |
584 | vxinit(i,wait) | |
585 | register int i; | |
586 | long wait; | |
587 | { | |
588 | register struct vcx *xp; /* ptr to VIOC-X info/cmd buffer */ | |
589 | register struct vblok *kp; /* pointer to VIOC-X control block */ | |
590 | register struct vxcmd *cp; /* pointer to a command buffer */ | |
591 | register char *resp; /* pointer to response buffer */ | |
592 | register int j; | |
b8c32975 | 593 | char type; |
9d915fad | 594 | #if NVBSC > 0 |
b8c32975 SL |
595 | register struct bsc *bp; /* bsc change */ |
596 | extern struct bsc bsc[]; | |
9d915fad | 597 | #endif |
b8c32975 SL |
598 | |
599 | ||
600 | kp = VBAS(i); /* get base adr of cntl blok for VIOC */ | |
601 | ||
602 | xp = &vcx[i]; /* index info/command buffers */ | |
b8c32975 SL |
603 | type = kp->v_ident; |
604 | vxtype[i] = 0; /* Type is Viox-x */ | |
605 | switch(type) { | |
606 | case VIOCX: | |
607 | { | |
608 | xp->v_vers = V_OLD ; | |
609 | /* set DCD for printer ports */ | |
610 | for(j = 0;j < 16;j++) | |
611 | if (kp->v_portyp[j] == 4 ) | |
612 | kp->v_dcd |= 1 << j ; | |
613 | } | |
614 | break ; | |
615 | case NWVIOCX: | |
616 | { | |
617 | xp->v_vers = V_NEW ; | |
618 | xp->v_silosiz = kp->v_maxsilo ; | |
619 | /* set DCD for printer ports */ | |
620 | for(j = 0;j < 16;j++) | |
621 | if (kp->v_portyp[j] == 4 ) | |
622 | kp->v_dcd |= 1 << j ; | |
623 | } | |
624 | break ; | |
625 | case PVIOCX: | |
626 | xp->v_vers = V_OLD ; | |
627 | break ; | |
628 | case NPVIOCX: | |
629 | xp->v_vers = V_NEW ; | |
630 | xp->v_silosiz = kp->v_maxsilo ; | |
631 | break ; | |
632 | #if NVBSC > 0 | |
633 | case VIOCB: /* old f/w, Bisync board */ | |
634 | printf("%X: %x%x OLD VIOC-B, ", | |
635 | (long)kp, (int)kp->v_ident, | |
636 | (int)kp->v_fault); | |
637 | xp->v_vers = V_OLD ; | |
638 | /* save device specific info */ | |
639 | for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++) | |
640 | bp->b_devregs = (caddr_t)xp ; | |
641 | printf("%d BSC Ports initialized.\n",NBSC); | |
642 | break ; | |
643 | ||
644 | case NWVIOCB: /* new f/w, Bisync board */ | |
645 | printf("%X: %x%x 16K VIOC-B, ", | |
646 | (long)kp, (int)kp->v_ident, | |
647 | (int)kp->v_fault); | |
648 | xp->v_vers = V_NEW ; | |
649 | xp->v_silosiz = kp->v_maxsilo ; | |
650 | /* save device specific info */ | |
651 | for(bp = &bsc[0]; bp <= &bsc[NBSC]; bp++) | |
652 | bp->b_devregs = (caddr_t)xp ; | |
653 | printf("%d BSC Ports initialized.\n",NBSC); | |
654 | if(CBSIZE > kp->v_maxxmt) | |
655 | printf("vxinit: Warning CBSIZE > maxxmt\n") ; | |
656 | break ; | |
657 | #endif | |
658 | case VBOPID: /* VIOC-BOP */ | |
659 | vxbbno++; | |
660 | vxtype[i] = 1; | |
661 | vxbopno[i] = vxbbno; | |
662 | printf("VIOC-BOP no. %d at %lx\n",vxbopno[i],VIOCBAS[i]); | |
663 | default: | |
664 | return ; /* Not a viocx type */ | |
665 | } | |
666 | xp->v_nbr = -1; /* no number for it yet */ | |
667 | xp->v_maxcmd = xp->v_vers == V_NEW ? 24 : 4; | |
668 | ||
669 | for(j=0; j<NVCXBUFS; j++) /* init all cmd buffers */ | |
670 | { | |
671 | cp = &xp->vx_lst[j]; /* index a buffer */ | |
672 | cp->c_fwd = &xp->vx_lst[j+1]; /* point to next buf */ | |
673 | } | |
674 | xp->vx_avail = &xp->vx_lst[0]; /* set idx to 1st free buf */ | |
675 | cp->c_fwd = (struct vxcmd *)0; /* mark last buf in free list */ | |
676 | ||
677 | cp = vobtain(xp); /* grap the control block */ | |
678 | cp->cmd = LIDENT; /* set command type */ | |
336ca318 SL |
679 | cp->par[0] = vxivec[i]; /* ack vector */ |
680 | cp->par[1] = cp->par[0]+1; /* cmd resp vector */ | |
681 | cp->par[3] = cp->par[0]+2; /* unsol intr vector */ | |
b8c32975 SL |
682 | cp->par[4] = 15; /* max ports, no longer used */ |
683 | cp->par[5] = 0; /* set 1st port number */ | |
9d915fad | 684 | vcmd(i, (caddr_t)&cp->cmd); /* initialize the VIOC-X */ |
b8c32975 SL |
685 | |
686 | if (!wait) return; | |
336ca318 SL |
687 | for (j = 0; cp->cmd == LIDENT && j < 4000000; j++) |
688 | ; | |
689 | if (j >= 4000000) | |
690 | printf("vx%d: didn't respond to LIDENT\n", i); | |
b8c32975 SL |
691 | |
692 | /* calculate address of response buffer */ | |
693 | resp = (char *)kp; | |
694 | resp += kp->v_rspoff & 0x3FFF; | |
695 | ||
696 | if(resp[0] != 0 && (resp[0]&0177) != 3) /* did init work? */ | |
697 | { | |
698 | vrelease(xp,cp); /* init failed */ | |
699 | return; /* try next VIOC-X */ | |
700 | } | |
701 | ||
702 | xp->v_loport = cp->par[5]; /* save low port number */ | |
703 | xp->v_hiport = cp->par[7];/* VIOC knows high port numbr */ | |
704 | vrelease(xp,cp); /* done with this control block */ | |
705 | xp->v_nbr = i; /* assign VIOC-X board number */ | |
706 | } | |
707 | ||
708 | /* | |
709 | * Obtain a command buffer | |
710 | */ | |
711 | struct vxcmd * | |
712 | vobtain(xp) | |
713 | register struct vcx *xp; | |
714 | { | |
715 | ||
716 | register struct vxcmd *p; | |
717 | register s; | |
718 | ||
719 | s = spl8(); | |
720 | p = xp->vx_avail; | |
721 | if(p == (struct vxcmd *)0) { | |
722 | #ifdef VX_DEBUG | |
723 | if (vxintr4 & VXNOBUF) vxintr4 &= ~VXNOBUF; | |
724 | #endif | |
725 | vpanic("vx: no buffs"); | |
726 | vxstreset(xp - vcx); | |
727 | splx(s); | |
728 | return(vobtain(xp)); | |
729 | } | |
730 | xp->vx_avail = (xp->vx_avail)->c_fwd; | |
731 | splx(s); | |
732 | return( (struct vxcmd *)p); | |
733 | } | |
734 | ||
735 | /* | |
736 | * Release a command buffer | |
737 | */ | |
738 | vrelease(xp,cp) | |
739 | register struct vcx *xp; | |
740 | register struct vxcmd *cp; | |
741 | { | |
742 | ||
743 | register s; | |
744 | ||
745 | #ifdef VX_DEBUG | |
746 | if (vxintr4 & VXNOBUF) return; | |
747 | #endif | |
748 | s = spl8(); | |
749 | cp->c_fwd = xp->vx_avail; | |
750 | xp->vx_avail = cp; | |
751 | splx(s); | |
752 | } | |
753 | ||
754 | /* | |
755 | * vxcmd - | |
756 | * | |
757 | */ | |
758 | struct vxcmd * | |
759 | nextcmd(xp) | |
760 | register struct vcx *xp; | |
761 | { | |
762 | register struct vxcmd *cp; | |
763 | register int s; | |
764 | ||
765 | s = spl8(); | |
766 | cp = xp->vx_build; | |
767 | xp->vx_build = (struct vxcmd *)0; | |
768 | splx(s); | |
769 | return(cp); | |
770 | } | |
771 | ||
772 | /* | |
773 | * assemble transmits into a multiple command. | |
774 | * up to 8 transmits to 8 lines can be assembled together | |
775 | */ | |
9d915fad | 776 | vsetq(xp ,d ,addr, n) |
b8c32975 SL |
777 | register struct vcx *xp; |
778 | caddr_t addr; | |
779 | { | |
780 | ||
781 | register struct vxcmd *cp; | |
782 | register struct vxmit *mp; | |
783 | register char *p; | |
784 | register i; | |
785 | ||
786 | cp = xp->vx_build; | |
787 | if(cp == (struct vxcmd *)0) { | |
788 | cp = vobtain(xp); | |
789 | xp->vx_build = cp; | |
790 | cp->cmd = XMITDTA; | |
791 | } else { | |
792 | if((cp->cmd & 07) == 07) { | |
793 | vpanic("vx: vsetq overflow"); | |
794 | vxstreset(xp->v_nbr); | |
795 | return(0); | |
796 | } | |
797 | cp->cmd++; | |
798 | } | |
799 | ||
800 | mp = (struct vxmit *)(cp->par + (cp->cmd & 07)*sizvxmit); | |
9d915fad | 801 | mp->bcount = n-1; |
b8c32975 SL |
802 | |
803 | mp->line = d; | |
9d915fad | 804 | if((xp->v_vers == V_NEW) && (n <= 6)) { |
b8c32975 SL |
805 | cp->cmd = XMITIMM ; |
806 | p = addr; | |
9d915fad | 807 | /* bcopy(addr, &(char *)mp->ostream, n) ; */ |
b8c32975 | 808 | } else { |
9d915fad SL |
809 | addr = (caddr_t)vtoph((struct proc *)0, (unsigned)addr); |
810 | /* should be a sys address */ | |
b8c32975 | 811 | p = (char *)&addr; |
9d915fad | 812 | n = sizeof addr; |
b8c32975 SL |
813 | /* mp->ostream = addr ; */ |
814 | } | |
9d915fad | 815 | for(i=0; i<n; i++) |
b8c32975 SL |
816 | mp->ostream[i] = *p++; |
817 | if(xp->v_vers == V_NEW) | |
818 | return(1) ; | |
819 | else | |
820 | return((cp->cmd&07) == 7) ; /* Indicate if full */ | |
821 | } | |
822 | #endif |