2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
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.
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
55 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
59 * Pseudo-teletype Driver
60 * (Actually two drivers, requiring two entries in 'cdevsw')
62 #include "pty.h" /* XXX */
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/ioctl.h>
67 #include <sys/proc_internal.h>
68 #include <sys/kauth.h>
71 #include <sys/file_internal.h>
73 #include <sys/kernel.h>
74 #include <sys/vnode.h>
76 #include <sys/signalvar.h>
80 #define FREE_BSDSTATIC static
82 #define FREE_BSDSTATIC __private_extern__
83 #define d_devtotty_t struct tty **
88 typedef void d_stop_t(struct tty
*tp
, int rw
);
92 /* XXX function should be removed??? */
93 int pty_init(int n_ptys
);
96 static void ptyattach(int n
);
98 static void ptsstart(struct tty
*tp
);
99 static void ptcwakeup(struct tty
*tp
, int flag
);
101 FREE_BSDSTATIC d_open_t ptsopen
;
102 FREE_BSDSTATIC d_close_t ptsclose
;
103 FREE_BSDSTATIC d_read_t ptsread
;
104 FREE_BSDSTATIC d_write_t ptswrite
;
105 FREE_BSDSTATIC d_ioctl_t ptyioctl
;
106 FREE_BSDSTATIC d_stop_t ptsstop
;
107 FREE_BSDSTATIC d_devtotty_t ptydevtotty
;
108 FREE_BSDSTATIC d_open_t ptcopen
;
109 FREE_BSDSTATIC d_close_t ptcclose
;
110 FREE_BSDSTATIC d_read_t ptcread
;
111 FREE_BSDSTATIC d_write_t ptcwrite
;
112 FREE_BSDSTATIC d_select_t ptcselect
;
115 #define CDEV_MAJOR_S 5
116 #define CDEV_MAJOR_C 6
117 static struct cdevsw pts_cdevsw
=
118 { ptsopen
, ptsclose
, ptsread
, ptswrite
, /*5*/
119 ptyioctl
, ptsstop
, nullreset
, ptydevtotty
,/* ttyp */
120 ttselect
, nommap
, NULL
, "pts", NULL
, -1 };
122 static struct cdevsw ptc_cdevsw
=
123 { ptcopen
, ptcclose
, ptcread
, ptcwrite
, /*6*/
124 ptyioctl
, nullstop
, nullreset
, ptydevtotty
,/* ptyp */
125 ptcselect
, nommap
, NULL
, "ptc", NULL
, -1 };
131 #define NPTY 32 /* crude XXX */
132 #warning You have only one pty defined, redefining to 32.
137 #define MAXUNITS (8 * 32)
138 static void *devfs_token_pts
[MAXUNITS
];
139 static void *devfs_token_ptc
[MAXUNITS
];
140 static const char jnames
[] = "pqrsPQRS";
143 #define NPTY MAXUNITS
144 #warning Can't have more than 256 pty's with DEVFS defined.
145 #endif /* NPTY > MAXUNITS */
149 #define BUFSIZ 100 /* Chunk size iomoved to/from user */
152 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
153 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
156 FREE_BSDSTATIC
struct tty pt_tty
[NPTY
]; /* XXX */
158 /* NeXT All references to have been changed to indirections in the file */
159 FREE_BSDSTATIC
struct tty
*pt_tty
[NPTY
] = { NULL
};
162 static struct pt_ioctl
{
164 struct selinfo pt_selr
, pt_selw
;
167 } pt_ioctl
[NPTY
]; /* XXX */
168 static int npty
= NPTY
; /* for pstat -t */
170 #define PF_PKT 0x08 /* packet mode */
171 #define PF_STOPPED 0x10 /* user told stopped */
172 #define PF_REMOTE 0x20 /* remote and flow controlled input */
173 #define PF_NOSTOP 0x40
174 #define PF_UCNTL 0x80 /* user control mode */
178 * Establish n (or default if n is 1) ptys in the system.
180 * XXX cdevsw & pstat require the array `pty[]' to be an array
188 #define DEFAULT_NPTY 32
190 /* maybe should allow 0 => none? */
193 ntb
= n
* sizeof(struct tty
);
195 mem
= malloc(ntb
+ ALIGNBYTES
+ n
* sizeof(struct pt_ioctl
),
198 MALLOC(mem
, char *, ntb
+ ALIGNBYTES
+ n
* sizeof(struct pt_ioctl
),
201 pt_tty
= (struct tty
*)mem
;
202 mem
= (char *)ALIGN(mem
+ ntb
);
203 pt_ioctl
= (struct pt_ioctl
*)mem
;
210 pty_init(__unused
int n_ptys
)
215 #include <miscfs/devfs/devfs.h>
216 #define START_CHAR 'p'
224 /* create the pseudo tty device nodes */
225 for (j
= 0; j
< 10; j
++) {
226 for (i
= 0; i
< HEX_BASE
; i
++) {
227 int m
= j
* HEX_BASE
+ i
;
230 (void)devfs_make_node(makedev(4, m
),
231 DEVFS_CHAR
, UID_ROOT
, GID_WHEEL
, 0666,
232 "tty%c%x", j
+ START_CHAR
, i
);
233 (void)devfs_make_node(makedev(5, m
),
234 DEVFS_CHAR
, UID_ROOT
, GID_WHEEL
, 0666,
235 "pty%c%x", j
+ START_CHAR
, i
);
245 ptsopen(dev_t dev
, int flag
, __unused
int devtype
, __unused
struct proc
*p
)
247 register struct tty
*tp
;
249 boolean_t funnel_state
;
251 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
253 tp
= &pt_tty
[minor(dev
)];
256 * You will see this sort of code coming up in diffs later both
257 * the ttymalloc and the tp indirection.
259 if (minor(dev
) >= npty
) {
263 if (!pt_tty
[minor(dev
)]) {
264 tp
= pt_tty
[minor(dev
)] = ttymalloc();
266 tp
= pt_tty
[minor(dev
)];
268 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
269 ttychars(tp
); /* Set up default chars */
270 tp
->t_iflag
= TTYDEF_IFLAG
;
271 tp
->t_oflag
= TTYDEF_OFLAG
;
272 tp
->t_lflag
= TTYDEF_LFLAG
;
273 tp
->t_cflag
= TTYDEF_CFLAG
;
274 tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
275 ttsetwater(tp
); /* would be done in xxparam() */
276 } else if (tp
->t_state
&TS_XCLUDE
&& suser(kauth_cred_get(), NULL
)) {
280 if (tp
->t_oproc
) /* Ctrlr still around. */
281 (void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
282 while ((tp
->t_state
& TS_CARR_ON
) == 0) {
285 error
= ttysleep(tp
, TSA_CARR_ON(tp
), TTIPRI
| PCATCH
,
290 error
= (*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
292 ptcwakeup(tp
, FREAD
|FWRITE
);
294 (void) thread_funnel_set(kernel_flock
, funnel_state
);
299 ptsclose(dev_t dev
, int flag
, __unused
int mode
, __unused proc_t p
)
301 register struct tty
*tp
;
303 boolean_t funnel_state
;
305 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
307 tp
= pt_tty
[minor(dev
)];
308 err
= (*linesw
[tp
->t_line
].l_close
)(tp
, flag
);
309 ptsstop(tp
, FREAD
|FWRITE
);
312 (void) thread_funnel_set(kernel_flock
, funnel_state
);
317 ptsread(dev
, uio
, flag
)
323 struct proc
*p
= curproc
;
325 struct proc
*p
= current_proc();
327 register struct tty
*tp
= pt_tty
[minor(dev
)];
328 register struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
331 boolean_t funnel_state
;
333 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
336 ut
= (struct uthread
*)get_bsdthread_info(current_thread());
338 if (pti
->pt_flags
& PF_REMOTE
) {
339 while (isbackground(p
, tp
)) {
340 if ((p
->p_sigignore
& sigmask(SIGTTIN
)) ||
341 (ut
->uu_sigmask
& sigmask(SIGTTIN
)) ||
342 p
->p_pgrp
->pg_jobc
== 0 ||
343 p
->p_flag
& P_PPWAIT
) {
347 pgsignal(p
->p_pgrp
, SIGTTIN
, 1);
348 error
= ttysleep(tp
, &lbolt
, TTIPRI
| PCATCH
| PTTYBLOCK
, "ptsbg",
353 if (tp
->t_canq
.c_cc
== 0) {
354 if (flag
& IO_NDELAY
)
355 return (EWOULDBLOCK
);
356 error
= ttysleep(tp
, TSA_PTS_READ(tp
), TTIPRI
| PCATCH
,
362 while (tp
->t_canq
.c_cc
> 1 && uio_resid(uio
) > 0) {
366 cc
= min(uio_resid(uio
), BUFSIZ
);
367 // Don't copy the very last byte
368 cc
= min(cc
, tp
->t_canq
.c_cc
- 1);
369 cc
= q_to_b(&tp
->t_canq
, buf
, cc
);
370 error
= uiomove(buf
, cc
, uio
);
374 if (tp
->t_canq
.c_cc
== 1)
375 (void) getc(&tp
->t_canq
);
380 error
= (*linesw
[tp
->t_line
].l_read
)(tp
, uio
, flag
);
381 ptcwakeup(tp
, FWRITE
);
383 (void) thread_funnel_set(kernel_flock
, funnel_state
);
388 * Write to pseudo-tty.
389 * Wakeups of controlling tty will happen
390 * indirectly, when tty driver calls ptsstart.
393 ptswrite(dev
, uio
, flag
)
398 register struct tty
*tp
;
400 boolean_t funnel_state
;
402 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
404 tp
= pt_tty
[minor(dev
)];
405 if (tp
->t_oproc
== 0)
408 error
= (*linesw
[tp
->t_line
].l_write
)(tp
, uio
, flag
);
410 (void) thread_funnel_set(kernel_flock
, funnel_state
);
415 * Start output on pseudo-tty.
416 * Wake up process selecting or sleeping for input from controlling tty.
422 register struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
423 boolean_t funnel_state
;
425 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
427 if (tp
->t_state
& TS_TTSTOP
)
429 if (pti
->pt_flags
& PF_STOPPED
) {
430 pti
->pt_flags
&= ~PF_STOPPED
;
431 pti
->pt_send
= TIOCPKT_START
;
433 ptcwakeup(tp
, FREAD
);
435 (void) thread_funnel_set(kernel_flock
, funnel_state
);
444 struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
445 boolean_t funnel_state
;
447 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
450 selwakeup(&pti
->pt_selr
);
451 wakeup(TSA_PTC_READ(tp
));
454 selwakeup(&pti
->pt_selw
);
455 wakeup(TSA_PTC_WRITE(tp
));
457 (void) thread_funnel_set(kernel_flock
, funnel_state
);
461 ptcopen(dev_t dev
, __unused
int flag
, __unused
int devtype
, __unused proc_t p
)
463 register struct tty
*tp
;
464 struct pt_ioctl
*pti
;
466 boolean_t funnel_state
;
468 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
470 if (minor(dev
) >= npty
) {
474 if(!pt_tty
[minor(dev
)]) {
475 tp
= pt_tty
[minor(dev
)] = ttymalloc();
477 tp
= pt_tty
[minor(dev
)];
482 tp
->t_oproc
= ptsstart
;
484 tp
->t_stop
= ptsstop
;
486 (void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
487 tp
->t_lflag
&= ~EXTPROC
;
488 pti
= &pt_ioctl
[minor(dev
)];
493 (void) thread_funnel_set(kernel_flock
, funnel_state
);
498 ptcclose(dev_t dev
, __unused
int flags
, __unused
int fmt
, __unused proc_t p
)
500 register struct tty
*tp
;
501 boolean_t funnel_state
;
503 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
505 tp
= pt_tty
[minor(dev
)];
506 (void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
509 * XXX MDMBUF makes no sense for ptys but would inhibit the above
510 * l_modem(). CLOCAL makes sense but isn't supported. Special
511 * l_modem()s that ignore carrier drop make no sense for ptys but
512 * may be in use because other parts of the line discipline make
513 * sense for ptys. Recover by doing everything that a normal
514 * ttymodem() would have done except for sending a SIGHUP.
516 if (tp
->t_state
& TS_ISOPEN
) {
517 tp
->t_state
&= ~(TS_CARR_ON
| TS_CONNECTED
);
518 tp
->t_state
|= TS_ZOMBIE
;
519 ttyflush(tp
, FREAD
| FWRITE
);
522 tp
->t_oproc
= 0; /* mark closed */
524 (void) thread_funnel_set(kernel_flock
, funnel_state
);
529 ptcread(dev
, uio
, flag
)
534 register struct tty
*tp
= pt_tty
[minor(dev
)];
535 struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
538 boolean_t funnel_state
;
540 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
543 * We want to block until the slave
544 * is open, and there's something to read;
545 * but if we lost the slave or we're NBIO,
546 * then return the appropriate error instead.
549 if (tp
->t_state
&TS_ISOPEN
) {
550 if (pti
->pt_flags
&PF_PKT
&& pti
->pt_send
) {
551 error
= ureadc((int)pti
->pt_send
, uio
);
554 if (pti
->pt_send
& TIOCPKT_IOCTL
) {
555 cc
= min(uio_resid(uio
),
556 sizeof(tp
->t_termios
));
557 uiomove((caddr_t
)&tp
->t_termios
, cc
,
563 if (pti
->pt_flags
&PF_UCNTL
&& pti
->pt_ucntl
) {
564 error
= ureadc((int)pti
->pt_ucntl
, uio
);
570 if (tp
->t_outq
.c_cc
&& (tp
->t_state
&TS_TTSTOP
) == 0)
573 if ((tp
->t_state
& TS_CONNECTED
) == 0)
575 if (flag
& IO_NDELAY
) {
579 error
= tsleep(TSA_PTC_READ(tp
), TTIPRI
| PCATCH
, "ptcin", 0);
583 if (pti
->pt_flags
& (PF_PKT
|PF_UCNTL
))
584 error
= ureadc(0, uio
);
585 while (uio_resid(uio
) > 0 && error
== 0) {
586 cc
= q_to_b(&tp
->t_outq
, buf
, min(uio_resid(uio
), BUFSIZ
));
589 error
= uiomove(buf
, cc
, uio
);
591 (*linesw
[tp
->t_line
].l_start
)(tp
);
594 (void) thread_funnel_set(kernel_flock
, funnel_state
);
600 register struct tty
*tp
;
603 struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
605 boolean_t funnel_state
;
607 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
609 /* note: FLUSHREAD and FLUSHWRITE already ok */
611 flush
= TIOCPKT_STOP
;
612 pti
->pt_flags
|= PF_STOPPED
;
614 pti
->pt_flags
&= ~PF_STOPPED
;
615 pti
->pt_send
|= flush
;
616 /* change of perspective */
624 (void) thread_funnel_set(kernel_flock
, funnel_state
);
628 ptcselect(dev
, rw
, wql
, p
)
634 register struct tty
*tp
= pt_tty
[minor(dev
)];
635 struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
637 boolean_t funnel_state
;
639 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
641 if ((tp
->t_state
& TS_CONNECTED
) == 0) {
649 * Need to block timeouts (ttrstart).
651 if ((tp
->t_state
&TS_ISOPEN
) &&
652 tp
->t_outq
.c_cc
&& (tp
->t_state
&TS_TTSTOP
) == 0) {
658 case 0: /* exceptional */
659 if ((tp
->t_state
&TS_ISOPEN
) &&
660 ((pti
->pt_flags
&PF_PKT
&& pti
->pt_send
) ||
661 (pti
->pt_flags
&PF_UCNTL
&& pti
->pt_ucntl
))) {
665 selrecord(p
, &pti
->pt_selr
, wql
);
670 if (tp
->t_state
&TS_ISOPEN
) {
671 if (pti
->pt_flags
& PF_REMOTE
) {
672 if (tp
->t_canq
.c_cc
== 0) {
677 if (tp
->t_rawq
.c_cc
+ tp
->t_canq
.c_cc
< TTYHOG
-2) {
681 if (tp
->t_canq
.c_cc
== 0 && (tp
->t_iflag
&ICANON
)) {
687 selrecord(p
, &pti
->pt_selw
, wql
);
692 (void) thread_funnel_set(kernel_flock
, funnel_state
);
697 ptcwrite(dev
, uio
, flag
)
699 register struct uio
*uio
;
702 register struct tty
*tp
= pt_tty
[minor(dev
)];
703 register u_char
*cp
= NULL
;
705 u_char locbuf
[BUFSIZ
];
707 struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
709 boolean_t funnel_state
;
711 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
714 if ((tp
->t_state
&TS_ISOPEN
) == 0)
716 if (pti
->pt_flags
& PF_REMOTE
) {
719 while ((uio_resid(uio
) > 0 || cc
> 0) &&
720 tp
->t_canq
.c_cc
< TTYHOG
- 1) {
722 cc
= min(uio_resid(uio
), BUFSIZ
);
723 cc
= min(cc
, TTYHOG
- 1 - tp
->t_canq
.c_cc
);
725 error
= uiomove((caddr_t
)cp
, cc
, uio
);
728 /* check again for safety */
729 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
730 /* adjust as usual */
731 uio_setresid(uio
, (uio_resid(uio
) + cc
));
737 cc
= b_to_q((char *)cp
, cc
, &tp
->t_canq
);
739 * XXX we don't guarantee that the canq size
740 * is >= TTYHOG, so the above b_to_q() may
741 * leave some bytes uncopied. However, space
742 * is guaranteed for the null terminator if
743 * we don't fail here since (TTYHOG - 1) is
744 * not a multiple of CBSIZE.
750 /* adjust for data copied in but not written */
751 uio_setresid(uio
, (uio_resid(uio
) + cc
));
752 (void) putc(0, &tp
->t_canq
);
754 wakeup(TSA_PTS_READ(tp
));
757 while (uio_resid(uio
) > 0 || cc
> 0) {
759 cc
= min(uio_resid(uio
), BUFSIZ
);
761 error
= uiomove((caddr_t
)cp
, cc
, uio
);
764 /* check again for safety */
765 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
766 /* adjust for data copied in but not written */
767 uio_setresid(uio
, (uio_resid(uio
) + cc
));
773 if ((tp
->t_rawq
.c_cc
+ tp
->t_canq
.c_cc
) >= TTYHOG
- 2 &&
774 (tp
->t_canq
.c_cc
> 0 || !(tp
->t_iflag
&ICANON
))) {
775 wakeup(TSA_HUP_OR_INPUT(tp
));
778 (*linesw
[tp
->t_line
].l_rint
)(*cp
++, tp
);
785 (void) thread_funnel_set(kernel_flock
, funnel_state
);
789 * Come here to wait for slave to open, for space
790 * in outq, or space in rawq, or an empty canq.
792 if ((tp
->t_state
& TS_CONNECTED
) == 0) {
793 /* adjust for data copied in but not written */
794 uio_setresid(uio
, (uio_resid(uio
) + cc
));
798 if (flag
& IO_NDELAY
) {
799 /* adjust for data copied in but not written */
800 uio_setresid(uio
, (uio_resid(uio
) + cc
));
805 error
= tsleep(TSA_PTC_WRITE(tp
), TTOPRI
| PCATCH
, "ptcout", 0);
807 /* adjust for data copied in but not written */
808 uio_setresid(uio
, (uio_resid(uio
) + cc
));
815 /* XXX we eventually want to go to this model,
816 * but premier can't change the cdevsw */
821 if (minor(dev
) >= npty
)
824 return &pt_tty
[minor(dev
)];
831 ptyioctl(dev
, cmd
, data
, flag
)
837 ptyioctl(dev
, cmd
, data
, flag
, p
)
845 register struct tty
*tp
= pt_tty
[minor(dev
)];
846 register struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
847 register u_char
*cc
= tp
->t_cc
;
849 boolean_t funnel_state
;
851 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
854 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
855 * ttywflush(tp) will hang if there are characters in the outq.
857 if (cmd
== TIOCEXT
) {
859 * When the EXTPROC bit is being toggled, we need
860 * to send an TIOCPKT_IOCTL if the packet driver
864 if (pti
->pt_flags
& PF_PKT
) {
865 pti
->pt_send
|= TIOCPKT_IOCTL
;
866 ptcwakeup(tp
, FREAD
);
868 tp
->t_lflag
|= EXTPROC
;
870 if ((tp
->t_lflag
& EXTPROC
) &&
871 (pti
->pt_flags
& PF_PKT
)) {
872 pti
->pt_send
|= TIOCPKT_IOCTL
;
873 ptcwakeup(tp
, FREAD
);
875 tp
->t_lflag
&= ~EXTPROC
;
880 if (cdevsw
[major(dev
)]->d_open
== ptcopen
)
882 if (cdevsw
[major(dev
)].d_open
== ptcopen
)
888 * We aviod calling ttioctl on the controller since,
889 * in that case, tp must be the controlling terminal.
891 *(int *)data
= tp
->t_pgrp
? tp
->t_pgrp
->pg_id
: 0;
896 if (pti
->pt_flags
& PF_UCNTL
) {
900 pti
->pt_flags
|= PF_PKT
;
902 pti
->pt_flags
&= ~PF_PKT
;
907 if (pti
->pt_flags
& PF_PKT
) {
911 pti
->pt_flags
|= PF_UCNTL
;
913 pti
->pt_flags
&= ~PF_UCNTL
;
918 pti
->pt_flags
|= PF_REMOTE
;
920 pti
->pt_flags
&= ~PF_REMOTE
;
921 ttyflush(tp
, FREAD
|FWRITE
);
932 ndflush(&tp
->t_outq
, tp
->t_outq
.c_cc
);
936 if (*(unsigned int *)data
>= NSIG
||
937 *(unsigned int *)data
== 0) {
941 if ((tp
->t_lflag
&NOFLSH
) == 0)
942 ttyflush(tp
, FREAD
|FWRITE
);
943 pgsignal(tp
->t_pgrp
, *(unsigned int *)data
, 1);
944 if ((*(unsigned int *)data
== SIGINFO
) &&
945 ((tp
->t_lflag
&NOKERNINFO
) == 0))
949 error
= (*linesw
[tp
->t_line
].l_ioctl
)(tp
, cmd
, data
, flag
, p
);
950 if (error
== ENOTTY
) {
951 error
= ttioctl(tp
, cmd
, data
, flag
, p
);
953 && pti
->pt_flags
& PF_UCNTL
&& (cmd
& ~0xff) == UIOCCMD(0)) {
954 /* Process the UIOCMD ioctl group */
956 pti
->pt_ucntl
= (u_char
)cmd
;
957 ptcwakeup(tp
, FREAD
);
965 * If external processing and packet mode send ioctl packet.
967 if ((tp
->t_lflag
&EXTPROC
) && (pti
->pt_flags
& PF_PKT
)) {
976 #if COMPAT_43_TTY || defined(COMPAT_SUNOS)
983 pti
->pt_send
|= TIOCPKT_IOCTL
;
984 ptcwakeup(tp
, FREAD
);
989 stop
= (tp
->t_iflag
& IXON
) && CCEQ(cc
[VSTOP
], CTRL('s'))
990 && CCEQ(cc
[VSTART
], CTRL('q'));
991 if (pti
->pt_flags
& PF_NOSTOP
) {
993 pti
->pt_send
&= ~TIOCPKT_NOSTOP
;
994 pti
->pt_send
|= TIOCPKT_DOSTOP
;
995 pti
->pt_flags
&= ~PF_NOSTOP
;
996 ptcwakeup(tp
, FREAD
);
1000 pti
->pt_send
&= ~TIOCPKT_DOSTOP
;
1001 pti
->pt_send
|= TIOCPKT_NOSTOP
;
1002 pti
->pt_flags
|= PF_NOSTOP
;
1003 ptcwakeup(tp
, FREAD
);
1007 (void) thread_funnel_set(kernel_flock
, funnel_state
);
1012 static ptc_devsw_installed
= 0;
1015 ptc_drvinit(void *unused
)
1022 if( ! ptc_devsw_installed
) {
1023 dev
= makedev(CDEV_MAJOR_S
, 0);
1024 cdevsw_add(&dev
, &pts_cdevsw
, NULL
);
1025 dev
= makedev(CDEV_MAJOR_C
, 0);
1026 cdevsw_add(&dev
, &ptc_cdevsw
, NULL
);
1027 ptc_devsw_installed
= 1;
1029 for ( i
= 0 ; i
<NPTY
; i
++ ) {
1032 devfs_token_pts
[i
] =
1033 devfs_add_devswf(&pts_cdevsw
,i
,
1035 "tty%c%n",jnames
[j
],k
);
1036 devfs_token_ptc
[i
] =
1037 devfs_add_devswf(&ptc_cdevsw
,i
,
1039 "pty%c%n",jnames
[j
],k
);
1045 SYSINIT(ptcdev
,SI_SUB_DRIVERS
,SI_ORDER_MIDDLE
+CDEV_MAJOR_C
,ptc_drvinit
,NULL
)