]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/tty_pty.c
43386b2a600a8c42737f68693e15ab703ba2d540
[apple/xnu.git] / bsd / kern / tty_pty.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
23 /*
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
56 */
57
58 /*
59 * Pseudo-teletype Driver
60 * (Actually two drivers, requiring two entries in 'cdevsw')
61 */
62 #include "pty.h" /* XXX */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/ioctl.h>
67 #include <sys/proc.h>
68 #include <sys/tty.h>
69 #include <sys/conf.h>
70 #include <sys/file.h>
71 #include <sys/uio.h>
72 #include <sys/kernel.h>
73 #include <sys/vnode.h>
74 #include <sys/user.h>
75 #include <sys/signalvar.h>
76
77 #ifndef NeXT
78
79 #define FREE_BSDSTATIC static
80 #else
81 #include <machine/spl.h>
82
83 #define FREE_BSDSTATIC __private_extern__
84 #define d_open_t open_close_fcn_t
85 #define d_close_t open_close_fcn_t
86 #define d_devtotty_t struct tty **
87 #define d_ioctl_t ioctl_fcn_t
88 #define d_read_t read_write_fcn_t
89 #define d_write_t read_write_fcn_t
90 #define d_select_t select_fcn_t
91 typedef void d_stop_t __P((struct tty *tp, int rw));
92 #endif /* NeXT */
93
94 #ifdef notyet
95 static void ptyattach __P((int n));
96 #endif
97 static void ptsstart __P((struct tty *tp));
98 static void ptcwakeup __P((struct tty *tp, int flag));
99
100 FREE_BSDSTATIC d_open_t ptsopen;
101 FREE_BSDSTATIC d_close_t ptsclose;
102 FREE_BSDSTATIC d_read_t ptsread;
103 FREE_BSDSTATIC d_write_t ptswrite;
104 FREE_BSDSTATIC d_ioctl_t ptyioctl;
105 FREE_BSDSTATIC d_stop_t ptsstop;
106 FREE_BSDSTATIC d_devtotty_t ptydevtotty;
107 FREE_BSDSTATIC d_open_t ptcopen;
108 FREE_BSDSTATIC d_close_t ptcclose;
109 FREE_BSDSTATIC d_read_t ptcread;
110 FREE_BSDSTATIC d_write_t ptcwrite;
111 FREE_BSDSTATIC d_select_t ptcselect;
112
113 #ifndef NeXT
114 #define CDEV_MAJOR_S 5
115 #define CDEV_MAJOR_C 6
116 static struct cdevsw pts_cdevsw =
117 { ptsopen, ptsclose, ptsread, ptswrite, /*5*/
118 ptyioctl, ptsstop, nullreset, ptydevtotty,/* ttyp */
119 ttselect, nommap, NULL, "pts", NULL, -1 };
120
121 static struct cdevsw ptc_cdevsw =
122 { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/
123 ptyioctl, nullstop, nullreset, ptydevtotty,/* ptyp */
124 ptcselect, nommap, NULL, "ptc", NULL, -1 };
125 #endif /* !NeXT */
126
127
128 #if NPTY == 1
129 #undef NPTY
130 #define NPTY 32 /* crude XXX */
131 #warning You have only one pty defined, redefining to 32.
132 #endif
133
134 #ifndef NeXT
135 #ifdef DEVFS
136 #define MAXUNITS (8 * 32)
137 static void *devfs_token_pts[MAXUNITS];
138 static void *devfs_token_ptc[MAXUNITS];
139 static const char jnames[] = "pqrsPQRS";
140 #if NPTY > MAXUNITS
141 #undef NPTY
142 #define NPTY MAXUNITS
143 #warning Can't have more than 256 pty's with DEVFS defined.
144 #endif /* NPTY > MAXUNITS */
145 #endif /* DEVFS */
146 #endif /* !NeXT */
147
148 #define BUFSIZ 100 /* Chunk size iomoved to/from user */
149
150 /*
151 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
152 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
153 */
154 #ifndef NeXT
155 FREE_BSDSTATIC struct tty pt_tty[NPTY]; /* XXX */
156 #else /* NeXT */
157 /* NeXT All references to have been changed to indirections in the file */
158 FREE_BSDSTATIC struct tty *pt_tty[NPTY] = { NULL };
159 #endif /* ! NeXT */
160
161 static struct pt_ioctl {
162 int pt_flags;
163 struct selinfo pt_selr, pt_selw;
164 u_char pt_send;
165 u_char pt_ucntl;
166 } pt_ioctl[NPTY]; /* XXX */
167 static int npty = NPTY; /* for pstat -t */
168
169 #define PF_PKT 0x08 /* packet mode */
170 #define PF_STOPPED 0x10 /* user told stopped */
171 #define PF_REMOTE 0x20 /* remote and flow controlled input */
172 #define PF_NOSTOP 0x40
173 #define PF_UCNTL 0x80 /* user control mode */
174
175 #ifdef notyet
176 /*
177 * Establish n (or default if n is 1) ptys in the system.
178 *
179 * XXX cdevsw & pstat require the array `pty[]' to be an array
180 */
181 FREEBSD_STATIC void
182 ptyattach(n)
183 int n;
184 {
185 char *mem;
186 register u_long ntb;
187 #define DEFAULT_NPTY 32
188
189 /* maybe should allow 0 => none? */
190 if (n <= 1)
191 n = DEFAULT_NPTY;
192 ntb = n * sizeof(struct tty);
193 #ifndef NeXT
194 mem = malloc(ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
195 M_DEVBUF, M_WAITOK);
196 #else
197 MALLOC(mem, char *, ntb + ALIGNBYTES + n * sizeof(struct pt_ioctl),
198 M_DEVBUF, M_WAITOK);
199 #endif /* !NeXT */
200 pt_tty = (struct tty *)mem;
201 mem = (char *)ALIGN(mem + ntb);
202 pt_ioctl = (struct pt_ioctl *)mem;
203 npty = n;
204 }
205 #endif
206
207 #ifndef DEVFS
208 int pty_init()
209 {
210 return 0;
211 }
212 #else
213 #include <miscfs/devfs/devfs.h>
214 #define START_CHAR 'p'
215 #define HEX_BASE 16
216 int pty_init(int n_ptys)
217 {
218 int i;
219 int j;
220
221 /* create the pseudo tty device nodes */
222 for (j = 0; j < 10; j++) {
223 for (i = 0; i < HEX_BASE; i++) {
224 int m = j * HEX_BASE + i;
225 if (m == n_ptys)
226 goto done;
227 (void)devfs_make_node(makedev(4, m),
228 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
229 "tty%c%x", j + START_CHAR, i);
230 (void)devfs_make_node(makedev(5, m),
231 DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666,
232 "pty%c%x", j + START_CHAR, i);
233 }
234 }
235 done:
236 return (0);
237 }
238 #endif DEVFS
239
240 /*ARGSUSED*/
241 FREE_BSDSTATIC int
242 ptsopen(dev, flag, devtype, p)
243 dev_t dev;
244 int flag, devtype;
245 struct proc *p;
246 {
247 register struct tty *tp;
248 int error;
249
250 #ifndef NeXT
251 tp = &pt_tty[minor(dev)];
252 #else
253 /*
254 * You will see this sourt of code coming up in diffs later both
255 * the ttymalloc and the tp indirection.
256 */
257 if (minor(dev) >= npty)
258 return (ENXIO);
259 if (!pt_tty[minor(dev)]) {
260 tp = pt_tty[minor(dev)] = ttymalloc();
261 } else
262 tp = pt_tty[minor(dev)];
263 #endif
264 if ((tp->t_state & TS_ISOPEN) == 0) {
265 ttychars(tp); /* Set up default chars */
266 tp->t_iflag = TTYDEF_IFLAG;
267 tp->t_oflag = TTYDEF_OFLAG;
268 tp->t_lflag = TTYDEF_LFLAG;
269 tp->t_cflag = TTYDEF_CFLAG;
270 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
271 ttsetwater(tp); /* would be done in xxparam() */
272 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
273 return (EBUSY);
274 if (tp->t_oproc) /* Ctrlr still around. */
275 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
276 while ((tp->t_state & TS_CARR_ON) == 0) {
277 if (flag&FNONBLOCK)
278 break;
279 error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
280 "ptsopn", 0);
281 if (error)
282 return (error);
283 }
284 error = (*linesw[tp->t_line].l_open)(dev, tp);
285 if (error == 0)
286 ptcwakeup(tp, FREAD|FWRITE);
287 return (error);
288 }
289
290 FREE_BSDSTATIC int
291 ptsclose(dev, flag, mode, p)
292 dev_t dev;
293 int flag, mode;
294 struct proc *p;
295 {
296 register struct tty *tp;
297 int err;
298
299 tp = pt_tty[minor(dev)];
300 err = (*linesw[tp->t_line].l_close)(tp, flag);
301 ptsstop(tp, FREAD|FWRITE);
302 (void) ttyclose(tp);
303 return (err);
304 }
305
306 FREE_BSDSTATIC int
307 ptsread(dev, uio, flag)
308 dev_t dev;
309 struct uio *uio;
310 int flag;
311 {
312 #ifndef NeXT
313 struct proc *p = curproc;
314 #else
315 struct proc *p = current_proc();
316 #endif /* NeXT */
317 register struct tty *tp = pt_tty[minor(dev)];
318 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
319 int error = 0;
320 struct uthread *ut;
321
322 ut = (struct uthread *)get_bsdthread_info(current_act());
323 again:
324 if (pti->pt_flags & PF_REMOTE) {
325 while (isbackground(p, tp)) {
326 if ((p->p_sigignore & sigmask(SIGTTIN)) ||
327 (ut->uu_sigmask & sigmask(SIGTTIN)) ||
328 p->p_pgrp->pg_jobc == 0 ||
329 p->p_flag & P_PPWAIT)
330 return (EIO);
331 pgsignal(p->p_pgrp, SIGTTIN, 1);
332 error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PTTYBLOCK, "ptsbg",
333 0);
334 if (error)
335 return (error);
336 }
337 if (tp->t_canq.c_cc == 0) {
338 if (flag & IO_NDELAY)
339 return (EWOULDBLOCK);
340 error = ttysleep(tp, TSA_PTS_READ(tp), TTIPRI | PCATCH,
341 "ptsin", 0);
342 if (error)
343 return (error);
344 goto again;
345 }
346 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
347 if (ureadc(getc(&tp->t_canq), uio) < 0) {
348 error = EFAULT;
349 break;
350 }
351 if (tp->t_canq.c_cc == 1)
352 (void) getc(&tp->t_canq);
353 if (tp->t_canq.c_cc)
354 return (error);
355 } else
356 if (tp->t_oproc)
357 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
358 ptcwakeup(tp, FWRITE);
359 return (error);
360 }
361
362 /*
363 * Write to pseudo-tty.
364 * Wakeups of controlling tty will happen
365 * indirectly, when tty driver calls ptsstart.
366 */
367 FREE_BSDSTATIC int
368 ptswrite(dev, uio, flag)
369 dev_t dev;
370 struct uio *uio;
371 int flag;
372 {
373 register struct tty *tp;
374
375 tp = pt_tty[minor(dev)];
376 if (tp->t_oproc == 0)
377 return (EIO);
378 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
379 }
380
381 /*
382 * Start output on pseudo-tty.
383 * Wake up process selecting or sleeping for input from controlling tty.
384 */
385 static void
386 ptsstart(tp)
387 struct tty *tp;
388 {
389 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
390
391 if (tp->t_state & TS_TTSTOP)
392 return;
393 if (pti->pt_flags & PF_STOPPED) {
394 pti->pt_flags &= ~PF_STOPPED;
395 pti->pt_send = TIOCPKT_START;
396 }
397 ptcwakeup(tp, FREAD);
398 }
399
400 static void
401 ptcwakeup(tp, flag)
402 struct tty *tp;
403 int flag;
404 {
405 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
406
407 if (flag & FREAD) {
408 selwakeup(&pti->pt_selr);
409 wakeup(TSA_PTC_READ(tp));
410 }
411 if (flag & FWRITE) {
412 selwakeup(&pti->pt_selw);
413 wakeup(TSA_PTC_WRITE(tp));
414 }
415 }
416
417 FREE_BSDSTATIC int
418 ptcopen(dev, flag, devtype, p)
419 dev_t dev;
420 int flag, devtype;
421 struct proc *p;
422 {
423 register struct tty *tp;
424 struct pt_ioctl *pti;
425
426 if (minor(dev) >= npty)
427 return (ENXIO);
428 if(!pt_tty[minor(dev)]) {
429 tp = pt_tty[minor(dev)] = ttymalloc();
430 } else
431 tp = pt_tty[minor(dev)];
432 if (tp->t_oproc)
433 return (EIO);
434 tp->t_oproc = ptsstart;
435 #ifdef sun4c
436 tp->t_stop = ptsstop;
437 #endif
438 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
439 tp->t_lflag &= ~EXTPROC;
440 pti = &pt_ioctl[minor(dev)];
441 pti->pt_flags = 0;
442 pti->pt_send = 0;
443 pti->pt_ucntl = 0;
444 return (0);
445 }
446
447 FREE_BSDSTATIC int
448 ptcclose(dev, flags, fmt, p)
449 dev_t dev;
450 int flags;
451 int fmt;
452 struct proc *p;
453 {
454 register struct tty *tp;
455
456 tp = pt_tty[minor(dev)];
457 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
458
459 /*
460 * XXX MDMBUF makes no sense for ptys but would inhibit the above
461 * l_modem(). CLOCAL makes sense but isn't supported. Special
462 * l_modem()s that ignore carrier drop make no sense for ptys but
463 * may be in use because other parts of the line discipline make
464 * sense for ptys. Recover by doing everything that a normal
465 * ttymodem() would have done except for sending a SIGHUP.
466 */
467 if (tp->t_state & TS_ISOPEN) {
468 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
469 tp->t_state |= TS_ZOMBIE;
470 ttyflush(tp, FREAD | FWRITE);
471 }
472
473 tp->t_oproc = 0; /* mark closed */
474 return (0);
475 }
476
477 FREE_BSDSTATIC int
478 ptcread(dev, uio, flag)
479 dev_t dev;
480 struct uio *uio;
481 int flag;
482 {
483 register struct tty *tp = pt_tty[minor(dev)];
484 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
485 char buf[BUFSIZ];
486 int error = 0, cc;
487
488 /*
489 * We want to block until the slave
490 * is open, and there's something to read;
491 * but if we lost the slave or we're NBIO,
492 * then return the appropriate error instead.
493 */
494 for (;;) {
495 if (tp->t_state&TS_ISOPEN) {
496 if (pti->pt_flags&PF_PKT && pti->pt_send) {
497 error = ureadc((int)pti->pt_send, uio);
498 if (error)
499 return (error);
500 if (pti->pt_send & TIOCPKT_IOCTL) {
501 cc = min(uio->uio_resid,
502 sizeof(tp->t_termios));
503 uiomove((caddr_t)&tp->t_termios, cc,
504 uio);
505 }
506 pti->pt_send = 0;
507 return (0);
508 }
509 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
510 error = ureadc((int)pti->pt_ucntl, uio);
511 if (error)
512 return (error);
513 pti->pt_ucntl = 0;
514 return (0);
515 }
516 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
517 break;
518 }
519 if ((tp->t_state & TS_CONNECTED) == 0)
520 return (0); /* EOF */
521 if (flag & IO_NDELAY)
522 return (EWOULDBLOCK);
523 error = tsleep(TSA_PTC_READ(tp), TTIPRI | PCATCH, "ptcin", 0);
524 if (error)
525 return (error);
526 }
527 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
528 error = ureadc(0, uio);
529 while (uio->uio_resid > 0 && error == 0) {
530 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
531 if (cc <= 0)
532 break;
533 error = uiomove(buf, cc, uio);
534 }
535 ttwwakeup(tp);
536 return (error);
537 }
538
539 FREE_BSDSTATIC void
540 ptsstop(tp, flush)
541 register struct tty *tp;
542 int flush;
543 {
544 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
545 int flag;
546
547 /* note: FLUSHREAD and FLUSHWRITE already ok */
548 if (flush == 0) {
549 flush = TIOCPKT_STOP;
550 pti->pt_flags |= PF_STOPPED;
551 } else
552 pti->pt_flags &= ~PF_STOPPED;
553 pti->pt_send |= flush;
554 /* change of perspective */
555 flag = 0;
556 if (flush & FREAD)
557 flag |= FWRITE;
558 if (flush & FWRITE)
559 flag |= FREAD;
560 ptcwakeup(tp, flag);
561 }
562
563 FREE_BSDSTATIC int
564 ptcselect(dev, rw, wql, p)
565 dev_t dev;
566 int rw;
567 void * wql;
568 struct proc *p;
569 {
570 register struct tty *tp = pt_tty[minor(dev)];
571 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
572 int s;
573
574 if ((tp->t_state & TS_CONNECTED) == 0)
575 return (1);
576 switch (rw) {
577
578 case FREAD:
579 /*
580 * Need to block timeouts (ttrstart).
581 */
582 s = spltty();
583 if ((tp->t_state&TS_ISOPEN) &&
584 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
585 splx(s);
586 return (1);
587 }
588 splx(s);
589 /* FALLTHROUGH */
590
591 case 0: /* exceptional */
592 if ((tp->t_state&TS_ISOPEN) &&
593 ((pti->pt_flags&PF_PKT && pti->pt_send) ||
594 (pti->pt_flags&PF_UCNTL && pti->pt_ucntl)))
595 return (1);
596 selrecord(p, &pti->pt_selr, wql);
597 break;
598
599
600 case FWRITE:
601 if (tp->t_state&TS_ISOPEN) {
602 if (pti->pt_flags & PF_REMOTE) {
603 if (tp->t_canq.c_cc == 0)
604 return (1);
605 } else {
606 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
607 return (1);
608 if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
609 return (1);
610 }
611 }
612 selrecord(p, &pti->pt_selw, wql);
613 break;
614
615 }
616 return (0);
617 }
618
619 FREE_BSDSTATIC int
620 ptcwrite(dev, uio, flag)
621 dev_t dev;
622 register struct uio *uio;
623 int flag;
624 {
625 register struct tty *tp = pt_tty[minor(dev)];
626 register u_char *cp = NULL;
627 register int cc = 0;
628 u_char locbuf[BUFSIZ];
629 int cnt = 0;
630 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
631 int error = 0;
632
633 again:
634 if ((tp->t_state&TS_ISOPEN) == 0)
635 goto block;
636 if (pti->pt_flags & PF_REMOTE) {
637 if (tp->t_canq.c_cc)
638 goto block;
639 while ((uio->uio_resid > 0 || cc > 0) &&
640 tp->t_canq.c_cc < TTYHOG - 1) {
641 if (cc == 0) {
642 cc = min(uio->uio_resid, BUFSIZ);
643 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
644 cp = locbuf;
645 error = uiomove((caddr_t)cp, cc, uio);
646 if (error)
647 return (error);
648 /* check again for safety */
649 if ((tp->t_state & TS_ISOPEN) == 0) {
650 /* adjust as usual */
651 uio->uio_resid += cc;
652 return (EIO);
653 }
654 }
655 if (cc > 0) {
656 cc = b_to_q((char *)cp, cc, &tp->t_canq);
657 /*
658 * XXX we don't guarantee that the canq size
659 * is >= TTYHOG, so the above b_to_q() may
660 * leave some bytes uncopied. However, space
661 * is guaranteed for the null terminator if
662 * we don't fail here since (TTYHOG - 1) is
663 * not a multiple of CBSIZE.
664 */
665 if (cc > 0)
666 break;
667 }
668 }
669 /* adjust for data copied in but not written */
670 uio->uio_resid += cc;
671 (void) putc(0, &tp->t_canq);
672 ttwakeup(tp);
673 wakeup(TSA_PTS_READ(tp));
674 return (0);
675 }
676 while (uio->uio_resid > 0 || cc > 0) {
677 if (cc == 0) {
678 cc = min(uio->uio_resid, BUFSIZ);
679 cp = locbuf;
680 error = uiomove((caddr_t)cp, cc, uio);
681 if (error)
682 return (error);
683 /* check again for safety */
684 if ((tp->t_state & TS_ISOPEN) == 0) {
685 /* adjust for data copied in but not written */
686 uio->uio_resid += cc;
687 return (EIO);
688 }
689 }
690 while (cc > 0) {
691 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
692 (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
693 wakeup(TSA_HUP_OR_INPUT(tp));
694 goto block;
695 }
696 (*linesw[tp->t_line].l_rint)(*cp++, tp);
697 cnt++;
698 cc--;
699 }
700 cc = 0;
701 }
702 return (0);
703 block:
704 /*
705 * Come here to wait for slave to open, for space
706 * in outq, or space in rawq, or an empty canq.
707 */
708 if ((tp->t_state & TS_CONNECTED) == 0) {
709 /* adjust for data copied in but not written */
710 uio->uio_resid += cc;
711 return (EIO);
712 }
713 if (flag & IO_NDELAY) {
714 /* adjust for data copied in but not written */
715 uio->uio_resid += cc;
716 if (cnt == 0)
717 return (EWOULDBLOCK);
718 return (0);
719 }
720 error = tsleep(TSA_PTC_WRITE(tp), TTOPRI | PCATCH, "ptcout", 0);
721 if (error) {
722 /* adjust for data copied in but not written */
723 uio->uio_resid += cc;
724 return (error);
725 }
726 goto again;
727 }
728
729 #ifndef NeXT
730 /* XXX we eventually want to go to this model,
731 * but premier can't change the cdevsw */
732 static struct tty *
733 ptydevtotty(dev)
734 dev_t dev;
735 {
736 if (minor(dev) >= npty)
737 return (NULL);
738
739 return &pt_tty[minor(dev)];
740 }
741 #endif /* !NeXT */
742
743 /*ARGSUSED*/
744 FREE_BSDSTATIC int
745 #ifndef NeXT
746 ptyioctl(dev, cmd, data, flag)
747 dev_t dev;
748 int cmd;
749 caddr_t data;
750 int flag;
751 #else
752 ptyioctl(dev, cmd, data, flag, p)
753 dev_t dev;
754 u_long cmd;
755 caddr_t data;
756 int flag;
757 struct proc *p;
758 #endif
759 {
760 register struct tty *tp = pt_tty[minor(dev)];
761 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
762 register u_char *cc = tp->t_cc;
763 int stop, error;
764
765 /*
766 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
767 * ttywflush(tp) will hang if there are characters in the outq.
768 */
769 if (cmd == TIOCEXT) {
770 /*
771 * When the EXTPROC bit is being toggled, we need
772 * to send an TIOCPKT_IOCTL if the packet driver
773 * is turned on.
774 */
775 if (*(int *)data) {
776 if (pti->pt_flags & PF_PKT) {
777 pti->pt_send |= TIOCPKT_IOCTL;
778 ptcwakeup(tp, FREAD);
779 }
780 tp->t_lflag |= EXTPROC;
781 } else {
782 if ((tp->t_lflag & EXTPROC) &&
783 (pti->pt_flags & PF_PKT)) {
784 pti->pt_send |= TIOCPKT_IOCTL;
785 ptcwakeup(tp, FREAD);
786 }
787 tp->t_lflag &= ~EXTPROC;
788 }
789 return(0);
790 } else
791 #ifndef NeXT
792 if (cdevsw[major(dev)]->d_open == ptcopen)
793 #else
794 if (cdevsw[major(dev)].d_open == ptcopen)
795 #endif
796 switch (cmd) {
797
798 case TIOCGPGRP:
799 /*
800 * We aviod calling ttioctl on the controller since,
801 * in that case, tp must be the controlling terminal.
802 */
803 *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
804 return (0);
805
806 case TIOCPKT:
807 if (*(int *)data) {
808 if (pti->pt_flags & PF_UCNTL)
809 return (EINVAL);
810 pti->pt_flags |= PF_PKT;
811 } else
812 pti->pt_flags &= ~PF_PKT;
813 return (0);
814
815 case TIOCUCNTL:
816 if (*(int *)data) {
817 if (pti->pt_flags & PF_PKT)
818 return (EINVAL);
819 pti->pt_flags |= PF_UCNTL;
820 } else
821 pti->pt_flags &= ~PF_UCNTL;
822 return (0);
823
824 case TIOCREMOTE:
825 if (*(int *)data)
826 pti->pt_flags |= PF_REMOTE;
827 else
828 pti->pt_flags &= ~PF_REMOTE;
829 ttyflush(tp, FREAD|FWRITE);
830 return (0);
831
832 #ifdef COMPAT_43
833 case TIOCSETP:
834 case TIOCSETN:
835 #endif
836 case TIOCSETD:
837 case TIOCSETA:
838 case TIOCSETAW:
839 case TIOCSETAF:
840 ndflush(&tp->t_outq, tp->t_outq.c_cc);
841 break;
842
843 case TIOCSIG:
844 if (*(unsigned int *)data >= NSIG ||
845 *(unsigned int *)data == 0)
846 return(EINVAL);
847 if ((tp->t_lflag&NOFLSH) == 0)
848 ttyflush(tp, FREAD|FWRITE);
849 pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
850 if ((*(unsigned int *)data == SIGINFO) &&
851 ((tp->t_lflag&NOKERNINFO) == 0))
852 ttyinfo(tp);
853 return(0);
854 }
855 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
856 if (error < 0)
857 error = ttioctl(tp, cmd, data, flag, p);
858 if (error < 0) {
859 if (pti->pt_flags & PF_UCNTL &&
860 (cmd & ~0xff) == UIOCCMD(0)) {
861 if (cmd & 0xff) {
862 pti->pt_ucntl = (u_char)cmd;
863 ptcwakeup(tp, FREAD);
864 }
865 return (0);
866 }
867 error = ENOTTY;
868 }
869 /*
870 * If external processing and packet mode send ioctl packet.
871 */
872 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
873 switch(cmd) {
874 case TIOCSETA:
875 case TIOCSETAW:
876 case TIOCSETAF:
877 #ifdef COMPAT_43
878 case TIOCSETP:
879 case TIOCSETN:
880 #endif
881 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
882 case TIOCSETC:
883 case TIOCSLTC:
884 case TIOCLBIS:
885 case TIOCLBIC:
886 case TIOCLSET:
887 #endif
888 pti->pt_send |= TIOCPKT_IOCTL;
889 ptcwakeup(tp, FREAD);
890 default:
891 break;
892 }
893 }
894 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
895 && CCEQ(cc[VSTART], CTRL('q'));
896 if (pti->pt_flags & PF_NOSTOP) {
897 if (stop) {
898 pti->pt_send &= ~TIOCPKT_NOSTOP;
899 pti->pt_send |= TIOCPKT_DOSTOP;
900 pti->pt_flags &= ~PF_NOSTOP;
901 ptcwakeup(tp, FREAD);
902 }
903 } else {
904 if (!stop) {
905 pti->pt_send &= ~TIOCPKT_DOSTOP;
906 pti->pt_send |= TIOCPKT_NOSTOP;
907 pti->pt_flags |= PF_NOSTOP;
908 ptcwakeup(tp, FREAD);
909 }
910 }
911 return (error);
912 }
913
914 #ifndef NeXT
915 static ptc_devsw_installed = 0;
916
917 static void
918 ptc_drvinit(void *unused)
919 {
920 #ifdef DEVFS
921 int i,j,k;
922 #endif
923 dev_t dev;
924
925 if( ! ptc_devsw_installed ) {
926 dev = makedev(CDEV_MAJOR_S, 0);
927 cdevsw_add(&dev, &pts_cdevsw, NULL);
928 dev = makedev(CDEV_MAJOR_C, 0);
929 cdevsw_add(&dev, &ptc_cdevsw, NULL);
930 ptc_devsw_installed = 1;
931 #ifdef DEVFS
932 for ( i = 0 ; i<NPTY ; i++ ) {
933 j = i / 32;
934 k = i % 32;
935 devfs_token_pts[i] =
936 devfs_add_devswf(&pts_cdevsw,i,
937 DV_CHR,0,0,0666,
938 "tty%c%n",jnames[j],k);
939 devfs_token_ptc[i] =
940 devfs_add_devswf(&ptc_cdevsw,i,
941 DV_CHR,0,0,0666,
942 "pty%c%n",jnames[j],k);
943 }
944 #endif
945 }
946 }
947
948 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)
949 #endif /* !NeXT */