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 */
60 static int termioval(char **, uint_t
*, char *);
63 ttycommon_close(tty_common_t
*tc
)
65 mutex_enter(&tc
->t_excl
);
66 tc
->t_flags
&= ~TS_XCLUDE
;
69 if (tc
->t_iocpending
!= NULL
) {
72 mp
= tc
->t_iocpending
;
73 tc
->t_iocpending
= NULL
;
74 mutex_exit(&tc
->t_excl
);
76 * We were holding an "ioctl" response pending the
77 * availability of an "mblk" to hold data to be passed up;
78 * another "ioctl" came through, which means that "ioctl"
79 * must have timed out or been aborted.
83 mutex_exit(&tc
->t_excl
);
87 * A "line discipline" module's queue is full.
88 * Check whether IMAXBEL is set; if so, output a ^G, otherwise send an M_FLUSH
89 * upstream flushing all the read queues.
92 ttycommon_qfull(tty_common_t
*tc
, queue_t
*q
)
96 if (tc
->t_iflag
& IMAXBEL
) {
98 if ((mp
= allocb(1, BPRI_HI
)) != NULL
) {
99 *mp
->b_wptr
++ = CTRL('g');
100 (void) putq(WR(q
), mp
);
104 flushq(q
, FLUSHDATA
);
105 (void) putnextctl1(q
, M_FLUSH
, FLUSHR
);
110 * Process an "ioctl" message sent down to us, and return a reply message,
111 * even if we don't understand the "ioctl". Our client may want to use
112 * that reply message for its own purposes if we don't understand it but
113 * they do, and may want to modify it if we both understand it but they
114 * understand it better than we do.
115 * If the "ioctl" reply requires additional data to be passed up to the
116 * caller, and we cannot allocate an mblk to hold the data, we return the
117 * amount of data to be sent, so that our caller can do a "bufcall" and try
118 * again later; otherwise, we return 0.
121 ttycommon_ioctl(tty_common_t
*tc
, queue_t
*q
, mblk_t
*mp
, int *errorp
)
124 size_t ioctlrespsize
;
127 *errorp
= 0; /* no error detected yet */
129 iocp
= (struct iocblk
*)mp
->b_rptr
;
131 if (iocp
->ioc_count
== TRANSPARENT
) {
132 *errorp
= -1; /* we don't understand it, maybe they do */
136 switch (iocp
->ioc_cmd
) {
140 * Flush the driver's queue, and send an M_FLUSH upstream
141 * to flush everybody above us.
143 flushq(RD(q
), FLUSHDATA
);
144 (void) putnextctl1(RD(q
), M_FLUSH
, FLUSHR
);
151 if (miocpullup(mp
, sizeof (struct termios
)) != 0) {
157 * The only information we look at are the iflag word,
158 * the cflag word, and the start and stop characters.
160 cb
= (struct termios
*)mp
->b_cont
->b_rptr
;
161 mutex_enter(&tc
->t_excl
);
162 tc
->t_iflag
= cb
->c_iflag
;
163 tc
->t_cflag
= cb
->c_cflag
;
164 tc
->t_stopc
= cb
->c_cc
[VSTOP
];
165 tc
->t_startc
= cb
->c_cc
[VSTART
];
166 mutex_exit(&tc
->t_excl
);
172 * Flush the driver's queue, and send an M_FLUSH upstream
173 * to flush everybody above us.
175 flushq(RD(q
), FLUSHDATA
);
176 (void) putnextctl1(RD(q
), M_FLUSH
, FLUSHR
);
183 if (miocpullup(mp
, sizeof (struct termio
)) != 0) {
189 * The only information we look at are the iflag word
190 * and the cflag word. Don't touch the unset portions.
192 cb
= (struct termio
*)mp
->b_cont
->b_rptr
;
193 mutex_enter(&tc
->t_excl
);
194 tc
->t_iflag
= (tc
->t_iflag
& 0xffff0000 | cb
->c_iflag
);
195 tc
->t_cflag
= (tc
->t_cflag
& 0xffff0000 | cb
->c_cflag
);
196 mutex_exit(&tc
->t_excl
);
203 if (miocpullup(mp
, sizeof (struct winsize
)) != 0) {
209 * If the window size changed, send a SIGWINCH.
211 ws
= (struct winsize
*)mp
->b_cont
->b_rptr
;
212 mutex_enter(&tc
->t_excl
);
213 if (bcmp(&tc
->t_size
, ws
, sizeof (struct winsize
)) != 0) {
215 mutex_exit(&tc
->t_excl
);
216 (void) putnextctl1(RD(q
), M_PCSIG
, SIGWINCH
);
218 mutex_exit(&tc
->t_excl
);
223 * Prevent more opens.
226 mutex_enter(&tc
->t_excl
);
227 tc
->t_flags
|= TS_XCLUDE
;
228 mutex_exit(&tc
->t_excl
);
235 mutex_enter(&tc
->t_excl
);
236 tc
->t_flags
&= ~TS_XCLUDE
;
237 mutex_exit(&tc
->t_excl
);
241 * Set or clear the "soft carrier" flag.
244 if (miocpullup(mp
, sizeof (int)) != 0) {
249 mutex_enter(&tc
->t_excl
);
250 if (*(int *)mp
->b_cont
->b_rptr
)
251 tc
->t_flags
|= TS_SOFTCAR
;
253 tc
->t_flags
&= ~TS_SOFTCAR
;
254 mutex_exit(&tc
->t_excl
);
258 * The permission checking has already been done at the stream
259 * head, since it has to be done in the context of the process
265 if (miocpullup(mp
, sizeof (char)) != 0) {
271 * Simulate typing of a character at the terminal.
273 if ((bp
= allocb(1, BPRI_MED
)) != NULL
) {
274 if (!canput(tc
->t_readq
->q_next
))
277 *bp
->b_wptr
++ = *mp
->b_cont
->b_rptr
;
278 putnext(tc
->t_readq
, bp
);
286 * Turn the ioctl message into an ioctl ACK message.
288 iocp
->ioc_count
= 0; /* no data returned unless we say so */
289 mp
->b_datap
->db_type
= M_IOCACK
;
291 switch (iocp
->ioc_cmd
) {
305 * We've done all the important work on these already;
306 * just reply with an ACK.
314 if ((datap
= allocb(sizeof (struct termios
),
316 ioctlrespsize
= sizeof (struct termios
);
319 cb
= (struct termios
*)datap
->b_wptr
;
321 * The only information we supply is the cflag word.
322 * Our copy of the iflag word is just that, a copy.
324 bzero(cb
, sizeof (struct termios
));
325 cb
->c_cflag
= tc
->t_cflag
;
326 datap
->b_wptr
+= sizeof (struct termios
);
327 iocp
->ioc_count
= sizeof (struct termios
);
328 if (mp
->b_cont
!= NULL
)
338 if ((datap
= allocb(sizeof (struct termio
), BPRI_HI
)) == NULL
) {
339 ioctlrespsize
= sizeof (struct termio
);
343 cb
= (struct termio
*)datap
->b_wptr
;
345 * The only information we supply is the cflag word.
346 * Our copy of the iflag word is just that, a copy.
348 bzero(cb
, sizeof (struct termio
));
349 cb
->c_cflag
= tc
->t_cflag
;
350 datap
->b_wptr
+= sizeof (struct termio
);
351 iocp
->ioc_count
= sizeof (struct termio
);
352 if (mp
->b_cont
!= NULL
)
359 * Get the "soft carrier" flag.
364 if ((datap
= allocb(sizeof (int), BPRI_HI
)) == NULL
) {
365 ioctlrespsize
= sizeof (int);
368 if (tc
->t_flags
& TS_SOFTCAR
)
369 *(int *)datap
->b_wptr
= 1;
371 *(int *)datap
->b_wptr
= 0;
372 datap
->b_wptr
+= sizeof (int);
373 iocp
->ioc_count
= sizeof (int);
374 if (mp
->b_cont
!= NULL
)
383 if ((datap
= allocb(sizeof (struct winsize
),
385 ioctlrespsize
= sizeof (struct winsize
);
389 * Return the current size.
391 *(struct winsize
*)datap
->b_wptr
= tc
->t_size
;
392 datap
->b_wptr
+= sizeof (struct winsize
);
393 iocp
->ioc_count
= sizeof (struct winsize
);
394 if (mp
->b_cont
!= NULL
)
401 *errorp
= -1; /* we don't understand it, maybe they do */
408 mutex_enter(&tc
->t_excl
);
409 tmp
= tc
->t_iocpending
;
410 tc
->t_iocpending
= mp
; /* hold this ioctl */
411 mutex_exit(&tc
->t_excl
);
413 * We needed to allocate something to handle this "ioctl", but
414 * couldn't; save this "ioctl" and arrange to get called back when
415 * it's more likely that we can get what we need.
416 * If there's already one being saved, throw it out, since it
417 * must have timed out.
421 return (ioctlrespsize
);
424 #define NFIELDS 21 /* 16 control characters + 4 sets of modes */
427 * Init routine run from main at boot time.
428 * Creates a property in the "options" node that is
429 * the default set of termios modes upon driver open.
430 * If the property already existed, then it was
431 * defined in the options.conf file. In this case we
432 * need to convert this string (stty -g style) to an
433 * actual termios structure and store the new property
441 struct termios new_termios
;
443 char *property
= "ttymodes";
451 * If the termios defaults were NOT set up by the
452 * user via the options.conf file, create it using the
453 * "sane" set of termios modes.
454 * Note that if the property had been created via the
455 * options.conf file, it would have been created as
456 * a string property. Since we would like to store
457 * a structure (termios) in this property, we need
458 * to change the property type to byte array.
460 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY
, ddi_root_node(), 0,
461 property
, (char ***)&modesp
, &len
) != DDI_PROP_SUCCESS
) {
463 if ((dip
= ddi_find_devinfo("options", -1, 0)) == NULL
) {
465 "ttyinit: Can't find options node!\n");
468 * Create the property.
470 if (ddi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
,
471 property
, (uchar_t
*)&default_termios
,
472 sizeof (struct termios
)) != DDI_PROP_SUCCESS
) {
473 cmn_err(CE_PANIC
, "ttyinit: can't create %s property\n",
480 * This property was already set in the options.conf
481 * file. We must convert it from a "stty -g" string
482 * to an actual termios structure.
484 bzero(&new_termios
, sizeof (struct termios
));
487 for (i
= 0; i
< NFIELDS
; i
++) {
489 * Check for bad field/string.
491 if (termioval(&cp
, &val
, *modesp
+strlen(*modesp
)) == -1) {
493 "ttyinit: property '%s' %s\n", property
,
494 "set incorrectly, using sane value");
495 tp
= &default_termios
;
500 new_termios
.c_iflag
= (tcflag_t
)val
;
503 new_termios
.c_oflag
= (tcflag_t
)val
;
506 new_termios
.c_cflag
= (tcflag_t
)val
;
509 new_termios
.c_lflag
= (tcflag_t
)val
;
512 new_termios
.c_cc
[i
- 4] = (cc_t
)val
;
515 if ((dip
= ddi_find_devinfo("options", -1, 0)) == NULL
) {
516 cmn_err(CE_PANIC
, "ttyinit: Can't find options node!\n");
520 * We need to create ttymode property as a byte array
521 * since it will be interpreted as a termios struct.
522 * The property was created as a string by default.
523 * So remove the old property and add the new one -
524 * otherwise we end up with two ttymodes properties.
526 if (e_ddi_prop_remove(DDI_DEV_T_NONE
, dip
, property
)
527 != DDI_PROP_SUCCESS
) {
528 cmn_err(CE_WARN
, "ttyinit: cannot remove '%s' property\n",
532 * Store the new defaults. Since, this property was
533 * autoconfig'ed, we must use e_ddi_prop_update_byte_array().
535 if (e_ddi_prop_update_byte_array(DDI_DEV_T_NONE
, dip
, property
,
536 (uchar_t
*)tp
, sizeof (struct termios
)) != DDI_PROP_SUCCESS
) {
537 cmn_err(CE_PANIC
, "ttyinit: cannot modify '%s' property\n",
540 ddi_prop_free(modesp
);
544 * Convert hex string representation of termios field
545 * to a uint_t. Increments string pointer to the next
546 * field, and assigns value. Returns -1 if no more fields
551 termioval(char **sp
, uint_t
*valp
, char *ep
)
560 if (*s
>= '0' && *s
<= '9')
562 else if (*s
>= 'a' && *s
<= 'f')
563 digit
= *s
++ - 'a' + 10;
564 else if (*s
>= 'A' && *s
<= 'F')
565 digit
= *s
++ - 'A' + 10;
566 else if (*s
== ':' || *s
== '\0')
570 *valp
= (*valp
* 16) + digit
;
573 * Null string or empty field.
578 if (s
< ep
&& *s
== ':')