xref: /original-bsd/sys/vax/vax/tu.c (revision 50f8aa26)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)tu.c	7.1 (Berkeley) 06/05/86
7  */
8 
9 #if defined(VAX750) || defined(VAX730)
10 /*
11  * TU58 DECtape II device driver
12  *
13  * TU58 console cassette driver (for VAX-11/750 or VAX-11/730).
14  * The TU58 is treated as a block device (only).  Error detection and
15  * recovery is not extensive, but sufficient for most situations. It is
16  * assumed that the TU58 will follow the RSP (or MRSP) protocol exactly,
17  * very few protocol errors are checked for.  It is also assumed that
18  * the 730 uses Modified RSP (MRSP), while the 750 may use either RSP
19  * or MRSP depending on whether defined(MRSP) is true or not.
20  * In the case of a 750 without MRSP, the only way for the CPU to
21  * keep up with the tu58 is to lock out virtually everything else.
22  *
23  * NOTE: Reading large amounts of data from the tu58 is likely
24  *	 to crash your system if you are running multiuser.
25  *	 	******FOR SINGLE USER USE ONLY*****
26  */
27 #include "param.h"
28 #include "systm.h"
29 #include "buf.h"
30 #include "conf.h"
31 #include "dir.h"
32 #include "user.h"
33 #include "kernel.h"
34 
35 #include "cpu.h"
36 #include "mtpr.h"
37 #include "rsp.h"
38 
39 #define	printd	if(tudebug) printf
40 #ifdef	printd
41 int	tudebug;	/* printd */
42 #endif	printd
43 
44 #define	NTU	((cpu == VAX_750) ? 1 : 2)
45 #define DNUM    01		/* mask for drive number (should match NTU) */
46 #define	NTUBLK	512		/* number of blocks on a TU58 cassette */
47 #define WRV     02              /* bit in minor dev => write w. read verify */
48 #define NTUQ    2               /* # of blocks which can be queued up */
49 #define	spltu()	((cpu == VAX_750) ? spl7() : spl4())
50 
51 #ifndef MRSP
52 #define MRSP (cpu != VAX_750)
53 #endif
54 
55 /*
56  * State information
57  */
58 struct tu {
59 	u_char	*tu_rbptr;	/* pointer to buffer for read */
60 	int	tu_rcnt;	/* how much to read */
61 	u_char	*tu_wbptr;	/* pointer to buffer for write */
62 	int	tu_wcnt;	/* how much to write */
63 	int	tu_state;	/* current state of tansfer operation */
64 	int	tu_flag;	/* read in progress flag */
65 	char	*tu_addr;	/* real buffer data address */
66 	int	tu_count;	/* real requested count */
67 	int	tu_serrs;	/* count of soft errors */
68 	int	tu_cerrs;	/* count of checksum errors */
69 	int	tu_herrs;	/* count of hard errors */
70 	char    tu_dopen[2];	/* drive is open */
71 } tu;
72 
73 
74 /*
75  * Device register bits
76  */
77 #define	READY	0200		/* transmitter ready */
78 #define	DONE	0200		/* receiver done */
79 #define	IE	0100		/* interrupt enable */
80 #define	BREAK	1		/* send break */
81 
82 struct packet tucmd;		/* a command sent to the TU58 */
83 struct packet tudata;		/* a command or data returned from TU58 */
84 
85 char *tustates[TUS_NSTATES] = {
86 	"INIT1", "INIT2", "IDLE", "SENDH", "SENDD", "SENDC", "SENDR",
87 	"SENDW", "GETH", "GETD", "GETC", "GET", "WAIT", "RCVERR", "CHKERR"
88 };
89 
90 u_char	tunull[2] = { 0, 0 };	/* nulls to send for initialization */
91 u_char	tuinit[2] = { TUF_INITF, TUF_INITF };	/* inits to send */
92 static char tu_pcnt[2];            		/* pee/vee counters */
93 int	tutimer = 0;
94 int	tuwake();
95 struct buf tutab;				/* I/O queue header */
96 
97 /*
98  * Open the TU58
99  */
100 /*ARGSUSED*/
101 tuopen(dev, flag)
102 {
103 	extern int tuwatch();
104 	register s;
105 
106 #ifdef lint
107 	turintr(); tuwintr();
108 #endif
109 	if ((minor(dev)&DNUM) >= NTU)
110 		return (ENXIO);
111 	if (tu.tu_dopen[minor(dev)&DNUM])
112 		return (EBUSY);
113 	if (tutimer++ == 0)
114 		timeout(tuwatch, (caddr_t)0, hz);
115 
116 	s = spltu();
117 	tu.tu_dopen[minor(dev)&DNUM]++;
118 	/*
119 	 * If the cassette's already initialized,
120 	 * just enable interrupts and return.
121 	 */
122 	if (tu.tu_state == TUS_IDLE) {
123 		mtpr(CSRS, IE);
124 		goto ok;
125 	}
126 
127 	/*
128 	 * Must initialize, reset the cassette
129 	 * and wait for things to settle down.
130 	 */
131 	tureset();
132 	sleep((caddr_t)&tu, PZERO+1);
133 	tutab.b_active = NULL;
134 	if (tu.tu_state != TUS_IDLE) {
135 		tu.tu_state = TUS_INIT1;
136 		tu.tu_dopen[minor(dev)&DNUM] = 0;
137 		tu.tu_rcnt = tu.tu_wcnt = 0;
138 		mtpr(CSTS, 0);
139 		mtpr(CSRS, 0);
140 		splx(s);
141 		return (EIO);
142 	}
143 ok:
144 	splx(s);
145 	return (0);
146 }
147 
148 /*
149  * Close the TU58, but make sure all
150  * outstanding i/o is complete first..
151  */
152 /* ARGSUSED */
153 tuclose(dev, flag)
154 	dev_t dev;
155 	int flag;
156 {
157 	int s, unit = minor(dev);
158 	struct buf *bp, *last = NULL;
159 
160 	s = spltu();
161 	while (tu_pcnt[unit])
162 		sleep(&tu_pcnt[unit], PRIBIO);
163 	/*
164 	 * No more writes are pending, scan the
165 	 * buffer queue for oustanding reads from
166 	 * this unit.
167 	 */
168 	for (bp = tutab.b_actf; bp; bp = bp->b_actf) {
169 		if (bp->b_dev == dev)
170 			last = bp;
171 	}
172 	if (last) {
173 		last->b_flags |= B_CALL;
174 		last->b_iodone = tuwake;
175 		sleep((caddr_t)last, PRIBIO);
176 	}
177 	tu.tu_dopen[unit&DNUM] = 0;
178 	if (!tu.tu_dopen[0] && !tu.tu_dopen[1]) {
179 		tutimer = 0;
180 		mtpr(CSRS, 0);
181 		tu.tu_flag = 0;
182 	}
183 	splx(s);
184 }
185 
186 tuwake(bp)
187 	struct buf *bp;
188 {
189 	wakeup((caddr_t)bp);
190 }
191 
192 /*
193  * Reset the TU58
194  */
195 tureset()
196 {
197 
198 	mtpr(CSRS, 0);
199 	tu.tu_state = TUS_INIT1;
200 	tu.tu_wbptr = tunull;
201 	tu.tu_wcnt = sizeof (tunull);
202 	tucmd.pk_flag = TUF_CMD;
203 	tucmd.pk_mcount = sizeof (tucmd) - 4;
204 	tucmd.pk_mod = 0;
205 	tucmd.pk_seq = 0;
206 	tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
207 	tutab.b_active++;
208 	mtpr(CSTS, IE | BREAK);
209 	tuxintr();			/* start output */
210 }
211 
212 /*
213  * Strategy routine for block I/O
214  */
215 tustrategy(bp)
216 	register struct buf *bp;
217 {
218 	register int s;
219 
220 	if (bp->b_blkno >= NTUBLK) {
221 		bp->b_flags |= B_ERROR;
222 		iodone(bp);
223 		return;
224 	}
225 	if ((bp->b_flags&B_READ) == 0)
226 		tu_pee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
227 	bp->av_forw = NULL;
228 	s = spltu();
229 	if (tutab.b_actf == NULL)
230 		tutab.b_actf = bp;
231 	else
232 		tutab.b_actl->av_forw = bp;
233 	tutab.b_actl = bp;
234 	if (tutab.b_active == NULL)
235 		tustart();
236 	splx(s);
237 }
238 
239 /*
240  * Start the transfer
241  */
242 tustart()
243 {
244 	register struct buf *bp;
245 	int s;
246 
247 	if ((bp = tutab.b_actf) == NULL)
248 		return;
249 	s = spltu();
250 	if (tu.tu_state != TUS_IDLE) {
251 		tureset();
252 		splx(s);
253 		return;
254 	}
255 	tutab.b_active++;
256 	tutab.b_errcnt = 0;
257 	tucmd.pk_op = bp->b_flags&B_READ ? TUOP_READ : TUOP_WRITE;
258 	tucmd.pk_mod = ((bp->b_flags&B_READ) == 0 && (minor(bp->b_dev)&WRV)) ?
259 	    TUMD_WRV : 0;
260 	tucmd.pk_unit = (minor(bp->b_dev)&DNUM);
261 	tucmd.pk_sw = MRSP ? TUSW_MRSP : 0;
262 	tucmd.pk_count = tu.tu_count = bp->b_bcount;
263 	tucmd.pk_block = bp->b_blkno;
264 	tucmd.pk_chksum =
265 	    tuchk(*((short *)&tucmd), (u_short *)&tucmd.pk_op,
266 		(int)tucmd.pk_mcount);
267 	tu.tu_state = bp->b_flags&B_READ ? TUS_SENDR : TUS_SENDW;
268 	tu.tu_addr = bp->b_un.b_addr;
269 	tu.tu_wbptr = (u_char *)&tucmd;
270 	tu.tu_wcnt = sizeof (tucmd);
271 	tuxintr();
272 	splx(s);
273 }
274 
275 /*
276  * TU58 receiver interrupt
277  */
278 turintr()
279 {
280 	register struct buf *bp;
281 	register int c;
282 
283 	c = mfpr(CSRD)&0xff;
284 	if (MRSP) {
285 		while ((mfpr(CSTS)&READY) == 0)
286 			;
287 		mtpr(CSTD, TUF_CONT);			/* ACK */
288 		if (tu.tu_rcnt) {
289 			*tu.tu_rbptr++ = c;
290 			if (--tu.tu_rcnt)
291 				return;
292 		}
293 	}
294 
295 	/*
296 	 * Switch on the state of the transfer.
297 	 */
298 	switch(tu.tu_state) {
299 
300 	/*
301 	 * Probably an overrun error,
302 	 * cannot happen if MRSP is used
303 	 */
304 	case TUS_RCVERR:
305 		mtpr(CSRS, 0);					/* flush */
306 		printf("overrun error, transfer restarted\n");	/* DEBUG */
307 		tu.tu_serrs++;
308 		tu_restart();
309 		break;
310 
311 	/*
312 	 * If we get an unexpected "continue",
313 	 * start all over again...
314 	 */
315 	case TUS_INIT2:
316 		tu.tu_state = c == TUF_CONT ? TUS_IDLE : TUS_INIT1;
317 		tu.tu_flag = 0;
318 		wakeup((caddr_t)&tu);
319 		tustart();
320 		break;
321 
322 	/*
323 	 * Only transition from this state
324 	 * is on a "continue", so if we don't
325 	 * get it, reset the world.
326 	 */
327 	case TUS_WAIT:			/* waiting for continue */
328 		switch(c) {
329 		case TUF_CONT:  /* got the expected continue */
330 			tu.tu_flag = 0;
331 			tudata.pk_flag = TUF_DATA;
332 			tudata.pk_mcount = MIN(128, tu.tu_count);
333 			tudata.pk_chksum =
334 			    tuchk(*((short *)&tudata), (u_short *)tu.tu_addr,
335 				(int)tudata.pk_mcount);
336 			tu.tu_state = TUS_SENDH;
337 			tu.tu_wbptr = (u_char *)&tudata;
338 			tu.tu_wcnt = 2;
339 			tuxintr();
340 			break;
341 
342 		case TUF_CMD:   /* sending us an END packet...error */
343 			tu.tu_state = TUS_GET;
344 			tu.tu_rbptr = (u_char *) &tudata;
345 			tu.tu_rcnt = sizeof (tudata) - 1;
346 			tu.tu_flag = 1;
347 			mtpr (CSTS, 0);
348 			*tu.tu_rbptr = c;
349 			break;
350 
351 		case TUF_INITF:
352 			tureset();
353 			break;
354 
355 		default:        /* something random...bad news */
356 			tu.tu_state = TUS_INIT1;
357 			break;
358 		}
359 		break;
360 
361 	case TUS_SENDW:
362 		if (c != TUF_CONT && c != TUF_INITF)
363 			goto bad;
364 		tureset();
365 		break;
366 
367 	/*
368 	 * Got header, now get data; amount to
369 	 * fetch is included in packet.
370 	 */
371 	case TUS_GETH:
372 		if (MRSP && (tudata.pk_flag == TUF_DATA))
373 			tu.tu_rbptr = (u_char *)tu.tu_addr;
374 		tu.tu_rcnt = tudata.pk_mcount;
375 		tu.tu_state = TUS_GETD;
376 		break;
377 
378 	/*
379 	 * Got the data, now fetch the checksum.
380 	 */
381 	case TUS_GETD:
382 		tu.tu_rbptr = (u_char *)&tudata.pk_chksum;
383 		tu.tu_rcnt = sizeof (tudata.pk_chksum);
384 		tu.tu_state = TUS_GETC;
385 		break;
386 
387 	case TUS_CHKERR:		/* from tudma only */
388 		tu.tu_cerrs++;
389 		goto tus_get;
390 
391 	case TUS_GET:
392 		if (MRSP)
393 			/*
394 		 	 * The checksum has already been calculated and
395 		 	 * verified in the pseudo DMA routine
396 		 	 */
397 			goto tus_get;
398 
399 	case TUS_GETC:
400 		/* got entire packet */
401 		if (tudata.pk_chksum !=
402 		    tuchk(*((short *)&tudata), (u_short *)
403 		     (tudata.pk_flag == TUF_DATA ?
404 		     (u_short *) tu.tu_addr : (u_short *)&tudata.pk_op),
405 		     (int)tudata.pk_mcount))
406 			tu.tu_cerrs++;
407 tus_get:
408 		if (tudata.pk_flag == TUF_DATA) {
409 			/* data packet, advance to next */
410 			tu.tu_addr += tudata.pk_mcount;
411 			tu.tu_count -= tudata.pk_mcount;
412 			tu.tu_state = TUS_GETH;
413 			tu.tu_rbptr = (u_char *)&tudata; /* next packet */
414 			tu.tu_rcnt = 2;
415 		} else if (tudata.pk_flag==TUF_CMD && tudata.pk_op==TUOP_END) {
416 			/* end packet, idle and reenable transmitter */
417 			tu.tu_state = TUS_IDLE;
418 			tu.tu_flag = 0;
419 			mtpr(CSTS, IE);
420 			printd("ON ");
421 			if ((bp = tutab.b_actf) == NULL) {
422 				printf("tu%d: no bp, active %d\n",
423 					tudata.pk_unit, tutab.b_active);
424 				tustart();
425 				return;
426 			}
427 			if (tudata.pk_mod > 1) {        /* hard error */
428 				bp->b_flags |= B_ERROR;
429 				tu.tu_herrs++;
430 				printf("tu%d: hard error bn%d,",
431 					minor(bp->b_dev)&DNUM, bp->b_blkno);
432 				printf("  pk_mod %o\n", tudata.pk_mod&0377);
433 			} else if (tudata.pk_mod != 0)	/* soft error */
434 				tu.tu_serrs++;
435 			tutab.b_active = NULL;
436 			tutab.b_actf = bp->av_forw;
437 			bp->b_resid = tu.tu_count;
438 			if ((bp->b_flags&B_READ) == 0)
439 				tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
440 			iodone(bp);
441 			tustart();
442 		} else {
443 			/*
444 			 * Neither data nor end: data was lost
445 			 * somehow, restart the transfer
446 			 */
447 			mtpr(CSRS, 0);		/* flush the rest */
448 			tu_restart();
449 			tu.tu_serrs++;
450 		}
451 		break;
452 
453 	case TUS_IDLE:
454 	case TUS_INIT1:
455 		break;
456 
457 	default:
458 bad:
459 		if (c == TUF_INITF) {
460 			printf("tu%d protocol error, state=",
461 							(int)tudata.pk_unit);
462 			printstate(tu.tu_state);
463 			printf(", op=%x, cnt=%d, block=%d\n",
464 			    tucmd.pk_op, tucmd.pk_count, tucmd.pk_block);
465 			tutab.b_active = NULL;
466 			if (bp = tutab.b_actf) {
467 				bp->b_flags |= B_ERROR;
468 				tutab.b_actf = bp->av_forw;
469 				if ((bp->b_flags&B_READ) == 0)
470 					tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
471 				iodone(bp);
472 			}
473 			tu.tu_state = TUS_INIT1;
474 		} else {
475 			printf("tu%d: receive state error, state=",
476 						(int)tudata.pk_unit);
477 			printstate(tu.tu_state);
478 			printf(", byte=%x\n", c & 0xff);
479 			if (tutab.b_actf)
480 				tu_restart();
481 			else
482 				wakeup((caddr_t)&tu);
483 		}
484 	}
485 }
486 
487 /*
488  * TU58 transmitter interrupt
489  */
490 tuxintr()
491 {
492 
493 top:
494 	if (tu.tu_wcnt) {
495 		/* still stuff to send, send one byte */
496 		while ((mfpr(CSTS) & READY) == 0)
497 			;
498 		mtpr(CSTD, *tu.tu_wbptr++);
499 		tu.tu_wcnt--;
500 		return;
501 	}
502 
503 	/*
504 	 * Last message byte was sent out.
505 	 * Switch on state of transfer.
506 	 */
507 	if (tudebug) {
508 		printf("tuxintr: state=");
509 		printstate(tu.tu_state);
510 	}
511 	switch(tu.tu_state) {
512 
513 	/*
514 	 * Two nulls have been sent, remove break, and send inits
515 	 */
516 	case TUS_INIT1:
517 		mtpr(CSTS, IE);
518 		printd("ON2 ");
519 		tu.tu_state = TUS_INIT2;
520 		tu.tu_wbptr = tuinit;
521 		tu.tu_wcnt = sizeof (tuinit);
522 		goto top;
523 
524 	/*
525 	 * Inits have been sent, wait for a continue msg.
526 	 */
527 	case TUS_INIT2:
528 		(void) mfpr(CSRD);
529 		mtpr(CSRS, IE);
530 		tu.tu_flag = 1;
531 		break;
532 
533 	/*
534 	 * Read cmd packet sent, get ready for data
535 	 */
536 	case TUS_SENDR:
537 		tu.tu_state = TUS_GETH;
538 		tu.tu_rbptr = (u_char *)&tudata;
539 		tu.tu_rcnt = 2;
540 		tu.tu_flag = 1;
541 		mtpr(CSTS, 0);	/* disable transmitter interrupts */
542 		printd("OFF ");
543 		break;
544 
545 	/*
546 	 * Write cmd packet sent, wait for continue
547 	 */
548 	case TUS_SENDW:
549 		tu.tu_state = TUS_WAIT;
550 		tu.tu_flag = 1;
551 		if ((mfpr(CSRS)&IE) == 0) {
552 			printf("NO IE\n");
553 			mtpr(CSRS, IE);
554 		}
555 		break;
556 
557 	/*
558 	 * Header sent, send data.
559 	 */
560 	case TUS_SENDH:
561 		tu.tu_state = TUS_SENDD;
562 		tu.tu_wbptr = (u_char *)tu.tu_addr;
563 		tu.tu_wcnt = tudata.pk_mcount;
564 		goto top;
565 
566 	/*
567 	 * Data sent, follow with checksum.
568 	 */
569 	case TUS_SENDD:
570 		tu.tu_state = TUS_SENDC;
571 		tu.tu_wbptr = (u_char *)&tudata.pk_chksum;
572 		tu.tu_wcnt = sizeof tudata.pk_chksum;
573 		goto top;
574 
575 	/*
576 	 * Checksum sent, wait for continue.
577 	 */
578 	case TUS_SENDC:
579 		/*
580 		 * Updata buffer address and count.
581 		 */
582 		tu.tu_addr += tudata.pk_mcount;
583 		tu.tu_count -= tudata.pk_mcount;
584 		if (tu.tu_count) {
585 			tu.tu_state = TUS_WAIT;
586 			tu.tu_flag = 1;
587 			break;
588 		}
589 
590 		/*
591 		 * End of transmission, get ready for end packet.
592 		 */
593 		tu.tu_state = TUS_GET;
594 		tu.tu_rbptr = (u_char *)&tudata;
595 		tu.tu_rcnt = sizeof (tudata);
596 		tu.tu_flag = 1;
597 		mtpr(CSTS, 0);
598 		printd("OFF2 ");
599 		break;
600 
601 	/*
602 	 * Random interrupt, probably from MRSP ACK
603 	 */
604 	case TUS_IDLE:
605 
606 	default:
607 		break;
608 
609 	}
610 	if (tudebug) {
611 		printd("  new tu_state=");
612 		printstate(tu.tu_state);
613 	}
614 }
615 
616 /*
617  * Compute checksum TU58 fashion
618  */
619 #ifdef lint
620 tuchk(word, cp, n)
621 	register word;
622 	register unsigned short *cp;
623 	int n;
624 {
625 	register int c = n >> 1;
626 	register long temp;
627 
628 	do {
629 		temp = *cp++;	/* temp, only because vax cc won't *r++ */
630 		word += temp;
631 	} while (--c > 0);
632 	if (n & 1)
633 		word += *(unsigned char *)cp;
634 	while (word & 0xffff0000)
635 		word = (word & 0xffff) + ((word >> 16) & 0xffff);
636 	return (word);
637 }
638 #else
639 tuchk(word0, wp, n)
640 	register int word0;	/* r11 */
641 	register u_short *wp;	/* r10 */
642 	register int n;		/* r9 */
643 {
644 	asm("loop:");
645 	asm("	addw2	(r10)+,r11");	/* add a word to sum */
646 	asm("	adwc	$0,r11");	/* add in carry, end-around */
647 	asm("	acbl	$2,$-2,r9,loop");	/* done yet? */
648 	asm("	blbc	r9,ok");	/* odd byte count? */
649 	asm("	movzbw	(r10),r10");	/* yes, get last byte */
650 	asm("	addw2	r10,r11");	/* add it in */
651 	asm("	adwc	$0,r11");	/* and the carry */
652 	asm("ok:");
653 	asm("	movl	r11,r0");	/* return sum */
654 }
655 #endif
656 
657 tuwatch()
658 {
659 	register int s;
660 	register struct buf *bp;
661 
662 	if (tutimer == 0)
663 		return;
664 
665 	if (tu.tu_flag == 0) {		/* if no read in progress - skip */
666 		timeout(tuwatch, (caddr_t)0, hz);
667 		return;
668 	}
669 	if (tu.tu_flag++ <= 40) {
670 		timeout(tuwatch, (caddr_t)0, hz);
671 		return;
672 	}
673 	printf("tu%d: read stalled\n", tudata.pk_unit);
674 #ifdef TUDEBUG
675 	printf("%X %X %X %X %X %X %X %X\n", tu.tu_rbptr, tu.tu_rcnt,
676 		tu.tu_wbptr, tu.tu_wcnt, tu.tu_state, tu.tu_flag,
677 		tu.tu_addr, tu.tu_count);
678 #endif
679 	s = spltu();
680 	tu.tu_flag = 0;
681 	(void) mfpr(CSRD);
682 	mtpr(CSRS, IE);		/* in case we were flushing */
683 	mtpr(CSTS, IE);
684 	tu.tu_state = TUS_IDLE;
685 	if (!tutab.b_active) {
686 		wakeup((caddr_t)&tu);
687 		goto retry;
688 	}
689 	if (++tutab.b_errcnt <= 1) {
690 		tustart();
691 		goto retry;
692 	}
693 	if (bp = tutab.b_actf) {
694 		bp->b_flags |= B_ERROR;
695 		if ((bp->b_flags&B_READ) == 0)
696 			tu_vee(&tu_pcnt[minor(bp->b_dev)&DNUM]);
697 		iodone(bp);
698 	}
699 retry:
700 	splx(s);
701 	timeout(tuwatch, (caddr_t)0, hz);
702 }
703 
704 tu_pee(cp)
705 	char *cp;
706 {
707 	register int s;
708 
709 	s = spltu();
710 	if (++(*cp) > NTUQ)
711 		sleep(cp, PRIBIO);
712 	splx(s);
713 }
714 
715 tu_vee(cp)
716 	char *cp;
717 {
718 	register int s;
719 
720 	s = spltu();
721 	if (--(*cp) <= NTUQ)
722 		wakeup(cp);
723 	splx(s);
724 }
725 
726 tu_restart()
727 {
728 	tureset();
729 	timeout(tustart, (caddr_t)0, hz * 3);
730 }
731 
732 #endif
733