2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved. The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
12 #include <sys/types.h>
13 #include <sys/param.h>
14 #include <sys/signal.h>
15 #include <sys/systm.h>
16 #include <sys/termio.h>
17 #include <sys/ttold.h>
18 #include <sys/stropts.h>
19 #include <sys/stream.h>
20 #include <sys/strsubr.h>
21 #include <sys/strsun.h>
24 #include <sys/errno.h>
26 #include <sys/sunddi.h>
27 #include <sys/esunddi.h>
30 * The default (sane) set of termios values, unless
31 * otherwise set by the user.
33 static struct termios default_termios
= {
34 BRKINT
|ICRNL
|IXON
|IMAXBEL
, /* c_iflag */
35 OPOST
|ONLCR
|TAB3
, /* c_oflag */
36 B9600
|CS8
|CREAD
, /* c_cflag */
37 ISIG
|ICANON
|IEXTEN
|ECHO
|ECHOK
|ECHOE
|ECHOKE
|ECHOCTL
, /* c_lflag */
61 static int termioval(char **, uint_t
*, char *);
64 ttycommon_close(tty_common_t
*tc
)
66 mutex_enter(&tc
->t_excl
);
67 tc
->t_flags
&= ~TS_XCLUDE
;
70 if (tc
->t_iocpending
!= NULL
) {
73 mp
= tc
->t_iocpending
;
74 tc
->t_iocpending
= NULL
;
75 mutex_exit(&tc
->t_excl
);
77 * We were holding an "ioctl" response pending the
78 * availability of an "mblk" to hold data to be passed up;
79 * another "ioctl" came through, which means that "ioctl"
80 * must have timed out or been aborted.
84 mutex_exit(&tc
->t_excl
);
88 * A "line discipline" module's queue is full.
89 * Check whether IMAXBEL is set; if so, output a ^G, otherwise send an M_FLUSH
90 * upstream flushing all the read queues.
93 ttycommon_qfull(tty_common_t
*tc
, queue_t
*q
)
97 if (tc
->t_iflag
& IMAXBEL
) {
99 if ((mp
= allocb(1, BPRI_HI
)) != NULL
) {
100 *mp
->b_wptr
++ = CTRL('g');
101 (void) putq(WR(q
), mp
);
105 flushq(q
, FLUSHDATA
);
106 (void) putnextctl1(q
, M_FLUSH
, FLUSHR
);
111 * Process an "ioctl" message sent down to us, and return a reply message,
112 * even if we don't understand the "ioctl". Our client may want to use
113 * that reply message for its own purposes if we don't understand it but
114 * they do, and may want to modify it if we both understand it but they
115 * understand it better than we do.
116 * If the "ioctl" reply requires additional data to be passed up to the
117 * caller, and we cannot allocate an mblk to hold the data, we return the
118 * amount of data to be sent, so that our caller can do a "bufcall" and try
119 * again later; otherwise, we return 0.
122 ttycommon_ioctl(tty_common_t
*tc
, queue_t
*q
, mblk_t
*mp
, int *errorp
)
125 size_t ioctlrespsize
;
128 *errorp
= 0; /* no error detected yet */
130 iocp
= (struct iocblk
*)mp
->b_rptr
;
132 if (iocp
->ioc_count
== TRANSPARENT
) {
133 *errorp
= -1; /* we don't understand it, maybe they do */
137 switch (iocp
->ioc_cmd
) {
141 * Flush the driver's queue, and send an M_FLUSH upstream
142 * to flush everybody above us.
144 flushq(RD(q
), FLUSHDATA
);
145 (void) putnextctl1(RD(q
), M_FLUSH
, FLUSHR
);
152 if (miocpullup(mp
, sizeof (struct termios
)) != 0) {
158 * The only information we look at are the iflag word,
159 * the cflag word, and the start and stop characters.
161 cb
= (struct termios
*)mp
->b_cont
->b_rptr
;
162 mutex_enter(&tc
->t_excl
);
163 tc
->t_iflag
= cb
->c_iflag
;
164 tc
->t_cflag
= cb
->c_cflag
;
165 tc
->t_stopc
= cb
->c_cc
[VSTOP
];
166 tc
->t_startc
= cb
->c_cc
[VSTART
];
167 mutex_exit(&tc
->t_excl
);
173 * Flush the driver's queue, and send an M_FLUSH upstream
174 * to flush everybody above us.
176 flushq(RD(q
), FLUSHDATA
);
177 (void) putnextctl1(RD(q
), M_FLUSH
, FLUSHR
);
184 if (miocpullup(mp
, sizeof (struct termio
)) != 0) {
190 * The only information we look at are the iflag word
191 * and the cflag word. Don't touch the unset portions.
193 cb
= (struct termio
*)mp
->b_cont
->b_rptr
;
194 mutex_enter(&tc
->t_excl
);
195 tc
->t_iflag
= (tc
->t_iflag
& 0xffff0000 | cb
->c_iflag
);
196 tc
->t_cflag
= (tc
->t_cflag
& 0xffff0000 | cb
->c_cflag
);
197 mutex_exit(&tc
->t_excl
);
204 if (miocpullup(mp
, sizeof (struct winsize
)) != 0) {
210 * If the window size changed, send a SIGWINCH.
212 ws
= (struct winsize
*)mp
->b_cont
->b_rptr
;
213 mutex_enter(&tc
->t_excl
);
214 if (bcmp(&tc
->t_size
, ws
, sizeof (struct winsize
)) != 0) {
216 mutex_exit(&tc
->t_excl
);
217 (void) putnextctl1(RD(q
), M_PCSIG
, SIGWINCH
);
219 mutex_exit(&tc
->t_excl
);
224 * Prevent more opens.
227 mutex_enter(&tc
->t_excl
);
228 tc
->t_flags
|= TS_XCLUDE
;
229 mutex_exit(&tc
->t_excl
);
236 mutex_enter(&tc
->t_excl
);
237 tc
->t_flags
&= ~TS_XCLUDE
;
238 mutex_exit(&tc
->t_excl
);
242 * Set or clear the "soft carrier" flag.
245 if (miocpullup(mp
, sizeof (int)) != 0) {
250 mutex_enter(&tc
->t_excl
);
251 if (*(int *)mp
->b_cont
->b_rptr
)
252 tc
->t_flags
|= TS_SOFTCAR
;
254 tc
->t_flags
&= ~TS_SOFTCAR
;
255 mutex_exit(&tc
->t_excl
);
259 * The permission checking has already been done at the stream
260 * head, since it has to be done in the context of the process
266 if (miocpullup(mp
, sizeof (char)) != 0) {
272 * Simulate typing of a character at the terminal.
274 if ((bp
= allocb(1, BPRI_MED
)) != NULL
) {
275 if (!canput(tc
->t_readq
->q_next
))
278 *bp
->b_wptr
++ = *mp
->b_cont
->b_rptr
;
279 putnext(tc
->t_readq
, bp
);
287 * Turn the ioctl message into an ioctl ACK message.
289 iocp
->ioc_count
= 0; /* no data returned unless we say so */
290 mp
->b_datap
->db_type
= M_IOCACK
;
292 switch (iocp
->ioc_cmd
) {
306 * We've done all the important work on these already;
307 * just reply with an ACK.
315 if ((datap
= allocb(sizeof (struct termios
),
317 ioctlrespsize
= sizeof (struct termios
);
320 cb
= (struct termios
*)datap
->b_wptr
;
322 * The only information we supply is the cflag word.
323 * Our copy of the iflag word is just that, a copy.
325 bzero(cb
, sizeof (struct termios
));
326 cb
->c_cflag
= tc
->t_cflag
;
327 datap
->b_wptr
+= sizeof (struct termios
);
328 iocp
->ioc_count
= sizeof (struct termios
);
329 if (mp
->b_cont
!= NULL
)
339 if ((datap
= allocb(sizeof (struct termio
), BPRI_HI
)) == NULL
) {
340 ioctlrespsize
= sizeof (struct termio
);
344 cb
= (struct termio
*)datap
->b_wptr
;
346 * The only information we supply is the cflag word.
347 * Our copy of the iflag word is just that, a copy.
349 bzero(cb
, sizeof (struct termio
));
350 cb
->c_cflag
= tc
->t_cflag
;
351 datap
->b_wptr
+= sizeof (struct termio
);
352 iocp
->ioc_count
= sizeof (struct termio
);
353 if (mp
->b_cont
!= NULL
)
360 * Get the "soft carrier" flag.
365 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
) {
366 ioctlrespsize
= sizeof (int);
369 if (tc
->t_flags
& TS_SOFTCAR
)
370 *(int *)datap
->b_wptr
= 1;
372 *(int *)datap
->b_wptr
= 0;
373 datap
->b_wptr
+= sizeof (int);
374 iocp
->ioc_count
= sizeof (int);
375 if (mp
->b_cont
!= NULL
)
384 if ((datap
= allocb(sizeof (struct winsize
),
386 ioctlrespsize
= sizeof (struct winsize
);
390 * Return the current size.
392 *(struct winsize
*)datap
->b_wptr
= tc
->t_size
;
393 datap
->b_wptr
+= sizeof (struct winsize
);
394 iocp
->ioc_count
= sizeof (struct winsize
);
395 if (mp
->b_cont
!= NULL
)
402 *errorp
= -1; /* we don't understand it, maybe they do */
409 mutex_enter(&tc
->t_excl
);
410 tmp
= tc
->t_iocpending
;
411 tc
->t_iocpending
= mp
; /* hold this ioctl */
412 mutex_exit(&tc
->t_excl
);
414 * We needed to allocate something to handle this "ioctl", but
415 * couldn't; save this "ioctl" and arrange to get called back when
416 * it's more likely that we can get what we need.
417 * If there's already one being saved, throw it out, since it
418 * must have timed out.
422 return (ioctlrespsize
);
425 #define NFIELDS 22 /* 18 control characters + 4 sets of modes */
428 * Init routine run from main at boot time.
429 * Creates a property in the "options" node that is
430 * the default set of termios modes upon driver open.
431 * If the property already existed, then it was
432 * defined in the options.conf file. In this case we
433 * need to convert this string (stty -g style) to an
434 * actual termios structure and store the new property
442 struct termios new_termios
;
444 char *property
= "ttymodes";
452 * If the termios defaults were NOT set up by the
453 * user via the options.conf file, create it using the
454 * "sane" set of termios modes.
455 * Note that if the property had been created via the
456 * options.conf file, it would have been created as
457 * a string property. Since we would like to store
458 * a structure (termios) in this property, we need
459 * to change the property type to byte array.
461 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY
, ddi_root_node(), 0,
462 property
, (char ***)&modesp
, &len
) != DDI_PROP_SUCCESS
) {
464 if ((dip
= ddi_find_devinfo("options", -1, 0)) == NULL
) {
466 "ttyinit: Can't find options node!\n");
469 * Create the property.
471 if (ddi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
472 property
, (uchar_t
*)&default_termios
,
473 sizeof (struct termios
)) != DDI_PROP_SUCCESS
) {
474 cmn_err(CE_PANIC
, "ttyinit: can't create %s property\n",
481 * This property was already set in the options.conf
482 * file. We must convert it from a "stty -g" string
483 * to an actual termios structure.
485 bzero(&new_termios
, sizeof (struct termios
));
488 for (i
= 0; i
< NFIELDS
; i
++) {
490 * Check for bad field/string.
492 if (termioval(&cp
, &val
, *modesp
+strlen(*modesp
)) == -1) {
494 "ttyinit: property '%s' %s\n", property
,
495 "set incorrectly, using sane value");
496 tp
= &default_termios
;
501 new_termios
.c_iflag
= (tcflag_t
)val
;
504 new_termios
.c_oflag
= (tcflag_t
)val
;
507 new_termios
.c_cflag
= (tcflag_t
)val
;
510 new_termios
.c_lflag
= (tcflag_t
)val
;
513 new_termios
.c_cc
[i
- 4] = (cc_t
)val
;
516 if ((dip
= ddi_find_devinfo("options", -1, 0)) == NULL
) {
517 cmn_err(CE_PANIC
, "ttyinit: Can't find options node!\n");
521 * We need to create ttymode property as a byte array
522 * since it will be interpreted as a termios struct.
523 * The property was created as a string by default.
524 * So remove the old property and add the new one -
525 * otherwise we end up with two ttymodes properties.
527 if (e_ddi_prop_remove(DDI_DEV_T_NONE
, dip
, property
)
528 != DDI_PROP_SUCCESS
) {
529 cmn_err(CE_WARN
, "ttyinit: cannot remove '%s' property\n",
533 * Store the new defaults. Since, this property was
534 * autoconfig'ed, we must use e_ddi_prop_update_byte_array().
536 if (e_ddi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
, property
,
537 (uchar_t
*)tp
, sizeof (struct termios
)) != DDI_PROP_SUCCESS
) {
538 cmn_err(CE_PANIC
, "ttyinit: cannot modify '%s' property\n",
541 ddi_prop_free(modesp
);
545 * Convert hex string representation of termios field
546 * to a uint_t. Increments string pointer to the next
547 * field, and assigns value. Returns -1 if no more fields
552 termioval(char **sp
, uint_t
*valp
, char *ep
)
561 if (*s
>= '0' && *s
<= '9')
563 else if (*s
>= 'a' && *s
<= 'f')
564 digit
= *s
++ - 'a' + 10;
565 else if (*s
>= 'A' && *s
<= 'F')
566 digit
= *s
++ - 'A' + 10;
567 else if (*s
== ':' || *s
== '\0')
571 *valp
= (*valp
* 16) + digit
;
574 * Null string or empty field.
579 if (s
< ep
&& *s
== ':')