4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
30 * ttymux - Multiplexer driver for multiplexing termio compliant streams onto
31 * a single upper stream.
33 * ADD2FRONT macro can be used to specify the order in which a console
34 * device is put in the queue of multiplexed physical serial devices,
35 * during the association and disassociation of a console interface.
36 * When this macro is defined, the device is placed in front of the queue,
37 * otherwise by default it is placed at the end.
38 * Console I/O happens to each of the physical devices in the order of
39 * their position in this queue.
42 #include <sys/types.h>
44 #include <sys/stream.h>
45 #include <sys/strsubr.h>
46 #include <sys/strlog.h>
47 #include <sys/strsun.h>
48 #include <sys/modctl.h>
49 #include <sys/debug.h>
51 #include <sys/devops.h>
52 #include <sys/errno.h>
56 #include <sys/consdev.h>
58 #include <sys/ptyvar.h>
59 #include <sys/termio.h>
60 #include <sys/fcntl.h>
61 #include <sys/mkdev.h>
62 #include <sys/ser_sync.h>
63 #include <sys/esunddi.h>
64 #include <sys/policy.h>
66 #include <sys/ttymux.h>
67 #include "ttymux_impl.h"
72 extern mblk_t
*mkiocb(uint_t
);
74 extern uintptr_t space_fetch(char *key
);
76 extern int sm_ioctl_cmd(sm_uqi_t
*, mblk_t
*);
77 extern int ttymux_abort_ioctl(mblk_t
*);
78 extern int ttymux_device_fini(sm_lqi_t
*);
79 extern int ttymux_device_init(sm_lqi_t
*);
84 int sm_disassociate(int, sm_lqi_t
*, ulong_t
);
85 int sm_associate(int, sm_lqi_t
*, ulong_t
, uint_t
, char *);
88 * Variables defined here and visible only internally
91 static int sm_instance
= 0;
94 static uint_t sm_default_trflag
= 0;
95 uint_t sm_max_units
= 6;
96 uint_t sm_minor_cnt
= 0;
97 static uint_t sm_refuse_opens
= 0;
103 /* force these flags to be unset on console devices */
104 static ulong_t sm_cmask
= (ulong_t
)(CRTSXOFF
|CRTSCTS
);
108 * Implementation Section:
111 sm_debug(char *msg
, ...)
118 sz
= vsnprintf(buf
, sizeof (buf
), msg
, args
);
122 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
), sm_instance
, 1,
123 SL_TRACE
, "vsnprintf parse error\n");
124 else if (sz
> sizeof (buf
)) {
128 b
= kmem_alloc(len
, KM_SLEEP
);
130 sz
= vsnprintf(b
, len
, msg
, args
);
133 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
),
134 sm_instance
, 1, SL_TRACE
, b
);
138 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
), sm_instance
,
144 sm_log(char *msg
, ...)
151 sz
= vsnprintf(buf
, sizeof (buf
), msg
, args
);
155 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
), sm_instance
, 1,
156 SL_TRACE
, "vsnprintf parse error\n");
157 else if (sz
> sizeof (buf
)) {
161 b
= kmem_alloc(len
, KM_SLEEP
);
163 sz
= vsnprintf(b
, len
, msg
, args
);
166 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
),
167 sm_instance
, 1, SL_NOTE
, b
);
171 (void) strlog(ddi_driver_major(sm_ssp
->sm_dip
), sm_instance
,
177 * Should only be called if the caller can guarantee that the vnode
178 * and/or the stream won't disappear while finding the dip.
179 * This routine is only called during an I_PLINK request so it's safe.
180 * The routine obtains the dev_t for a linked se stream.
183 sm_setdip(queue_t
*q
, sm_lqi_t
*lqi
)
185 lqi
->sm_dev
= q
&& STREAM(q
) ? STREAM(q
)->sd_vnode
->v_rdev
: NODEV
;
189 * Called from driver close, state change reports and I_PUNLINK ioctl.
190 * A lower stream has been unlinked - clean up the state associated with it.
193 sm_lqifree(sm_lqi_t
*lqi
)
198 ASSERT(mutex_owned(lqi
->sm_umutex
));
199 ASSERT(SM_RQ(lqi
) != 0);
202 * Clear all state associated with this lower queue except
203 * the identity of the queues themselves and the link id which
204 * can only be cleared by issuing a streams I_PUNLINK ioctl.
206 * The association of a lower queue is a two step process:
207 * 1. initialise the lower q data structure on I_PLINK
208 * 2. associate an upper q with the lower q on SM_CMD_ASSOCIATE.
210 * If step 2 has ocurred then
211 * remove this lower queue info from the logical unit.
214 sm_dbg('Y', ("lqifree unit %d, ", lqi
->sm_uqi
->sm_lunit
));
215 if ((mu_owned
= mutex_owned(lqi
->sm_uqi
->sm_umutex
)) == 0)
216 LOCK_UNIT(lqi
->sm_uqi
);
218 pplqi
= &lqi
->sm_uqi
->sm_lqs
;
219 while (*pplqi
!= lqi
) {
221 pplqi
= &((*pplqi
)->sm_nlqi
);
223 *pplqi
= lqi
->sm_nlqi
;
224 lqi
->sm_uqi
->sm_nlqs
--;
227 UNLOCK_UNIT(lqi
->sm_uqi
);
234 * Given a q return the associated lower queue data structure or NULL.
235 * Return the data locked.
238 get_lqi_byq(queue_t
*q
)
241 sm_lqi_t
*lqi
, *flqi
= 0;
243 for (i
= 0; i
< MAX_LQS
; i
++) {
244 lqi
= &sm_ssp
->sm_lqs
[i
];
246 if (flqi
== 0 && lqi
->sm_linkid
== 0) /* assumes muxids != 0 */
248 else if (SM_RQ(lqi
) == q
|| SM_WQ(lqi
) == q
) {
260 * Given a streams link identifier return the associated lower queue data
264 get_lqi_byid(int linkid
)
271 for (i
= 0; i
< MAX_LQS
; i
++) {
272 lqi
= &sm_ssp
->sm_lqs
[i
];
273 if (lqi
->sm_linkid
== linkid
)
280 * Given a dev_t for a lower stream return the associated lower queue data
284 get_lqi_bydevt(dev_t dev
)
292 for (i
= 0; i
< MAX_LQS
; i
++) {
293 lqi
= &sm_ssp
->sm_lqs
[i
];
294 if (lqi
->sm_dev
== dev
)
301 * Determine whether the input flag is set on at least
305 sm_is_flag_set(sm_uqi_t
*uqi
, uint_t flag
, uint_t howmany
)
312 for (lqi
= uqi
->sm_lqs
; lqi
; lqi
= lqi
->sm_nlqi
) {
313 if (lqi
->sm_flags
& flag
)
321 * How many usable queues are associated with a given upper stream
324 sm_uwq_error(sm_uqi_t
*uqi
)
326 return (sm_is_flag_set(uqi
, (WERROR_MODE
|HANGUP_MODE
), uqi
->sm_nlqs
));
330 * How many of the queues associated with a given upper stream
331 * - do not - have the given flags set.
334 sm_q_count(sm_uqi_t
*uqi
, uint_t flag
)
339 for (lqi
= uqi
->sm_lqs
; lqi
; lqi
= lqi
->sm_nlqi
) {
340 if ((lqi
->sm_flags
& flag
) == 0)
347 * How many of the queues associated with a given upper stream
348 * - do not - have the given flags set.
351 sm_qs_without(sm_uqi_t
*uqi
, uint_t flag
, uint_t ioflag
)
356 for (lqi
= uqi
->sm_lqs
; lqi
; lqi
= lqi
->sm_nlqi
) {
357 if ((lqi
->sm_flags
& flag
) == 0 &&
358 (lqi
->sm_ioflag
& ioflag
) == 0)
365 * How many usable queues are associated with a given upper stream
368 sm_good_qs(sm_uqi_t
*uqi
)
370 return (sm_q_count(uqi
, (WERROR_MODE
|HANGUP_MODE
)));
374 sm_cnt_oqs(sm_uqi_t
*uqi
)
376 return (sm_qs_without(uqi
, (WERROR_MODE
|HANGUP_MODE
),
381 * Send an ioctl downstream and remember that it was sent so that
382 * its response can be caught on the way back up.
385 sm_issue_ioctl(void *arg
)
389 queue_t
*q
= SM_WQ(lqi
);
395 if ((lqi
->sm_flags
& (WERROR_MODE
|HANGUP_MODE
)) == 0 &&
396 (lqi
->sm_flags
& (WANT_CDSTAT
|WANT_TCSET
))) {
399 if (lqi
->sm_flags
& WANT_TCSET
) {
400 lqi
->sm_flags
&= ~WANT_TCSET
;
402 cmdflag
= WANT_TCSET
;
403 } else if (lqi
->sm_flags
& WANT_SC
) {
404 lqi
->sm_flags
&= ~WANT_SC
;
405 iocmd
= TIOCGSOFTCAR
;
407 } else if (lqi
->sm_flags
& WANT_CD
) {
408 lqi
->sm_flags
&= ~WANT_CD
;
410 } else if (lqi
->sm_flags
& WANT_CL
) {
411 lqi
->sm_flags
&= ~WANT_CL
;
419 if (pioc
= mkiocb(iocmd
)) {
420 if (cmdflag
== WANT_TCSET
) {
422 sm_allocb(sizeof (struct termios
),
424 if (pioc
->b_cont
== 0) {
428 struct termios
*tc
= (struct termios
*)
429 pioc
->b_cont
->b_wptr
;
432 sizeof (struct termios
));
433 tc
->c_cflag
= lqi
->sm_ttycommon
->
435 pioc
->b_cont
->b_rptr
=
436 pioc
->b_cont
->b_wptr
;
437 pioc
->b_cont
->b_wptr
+=
438 sizeof (struct termios
);
440 size
= sizeof (struct iocblk
) +
441 sizeof (struct termios
);
444 size
= sizeof (struct iocblk
);
447 size
= sizeof (struct iocblk
);
451 lqi
->sm_piocid
= ((struct iocblk
*)pioc
->b_rptr
)->
453 lqi
->sm_flags
|= SM_IOCPENDING
;
455 /* lqi->sm_flags |= cmdflag; */
457 (void) putq(q
, pioc
);
460 lqi
->sm_bid
= qbufcall(WR(q
), size
, BPRI_MED
,
461 sm_issue_ioctl
, lqi
);
469 * Associate one of the drivers minor nodes with a serial device.
472 sm_associate(int unit
, sm_lqi_t
*plqi
, ulong_t tag
, uint_t ioflag
, char *dp
)
477 sm_dbg('Y', ("sm_associate(%d, %d, %d): ",
478 (plqi
) ? plqi
->sm_linkid
: 0, unit
, ioflag
));
480 * Check the data is valid.
481 * Associate a lower queue with a logical unit.
484 if (unit
< 0 || unit
>= NLUNITS
|| plqi
== 0 ||
485 (uqi
= get_uqi(sm_ssp
, unit
)) == 0) {
486 sm_dbg('@', (" invalid: lqi=0x%p lui=0x%p:", plqi
, uqi
));
489 if ((ioflag
& FORIO
) == 0)
495 if (plqi
->sm_uqi
->sm_lunit
== unit
) {
496 if ((ioflag
& (uint_t
)FORIO
) != 0)
498 (ioflag
& (uint_t
)FORIO
);
501 sm_dbg('@', ("already associated with unit %d:",
502 plqi
->sm_uqi
->sm_lunit
));
509 if ((ioflag
& (uint_t
)FORIO
) != 0)
510 plqi
->sm_ioflag
= (ioflag
& (uint_t
)FORIO
);
512 plqi
->sm_ttycommon
->t_cflag
= uqi
->sm_ttycommon
->
514 plqi
->sm_ttycommon
->t_flags
= uqi
->sm_ttycommon
->
521 (void) strncpy(plqi
->sm_path
, dp
, MAXPATHLEN
);
523 *(plqi
->sm_path
) = '\0';
525 plqi
->sm_flags
|= WANT_TCSET
;
527 plqi
->sm_nlqi
= uqi
->sm_lqs
;
533 for (lq
= uqi
->sm_lqs
; lq
->sm_nlqi
;
542 (void) ttymux_device_init(plqi
);
547 * Everything looks good so it's now ok to enable lower
549 * Note the lower queue should be enabled as soon as
550 * I_PLINK returns (used in sm_get_ttymodes etc).
551 * Schedule ioctls to obtain the terminal settings.
554 if ((uqi
->sm_flags
& FULLY_OPEN
) || uqi
->sm_waitq
)
555 plqi
->sm_uqflags
|= SM_UQVALID
;
557 qenable(SM_RQ(plqi
));
558 if (plqi
->sm_flags
& (WANT_CDSTAT
|WANT_TCSET
)) {
560 * Bypass the lower half of the driver (hence
561 * no qwriter) and apply the current termio
562 * settings on the lower stream.
566 qunbufcall(SM_WQ(plqi
), plqi
->sm_bid
);
570 * Only set cflags on the lower q if we know
571 * the settings on any other lower queue.
573 sm_issue_ioctl(plqi
);
581 sm_dbg('Y', ("sm_associate: rval=%d.\n", rval
));
586 * Break an association between one of the driver's minor nodes and
590 sm_disassociate(int unit
, sm_lqi_t
*plqi
, ulong_t tag
)
595 sm_dbg('Y', ("sm_disassociate: link %d, unit %d: ",
596 (plqi
) ? plqi
->sm_linkid
: 0, unit
));
598 * Check the data is valid.
599 * Disassociate a lower queue with a logical unit.
601 if (unit
< 0 || unit
>= NLUNITS
|| plqi
== 0 ||
602 (uqi
= get_uqi(sm_ssp
, unit
)) == 0) {
603 sm_dbg('@', ("invalid: lqi=0x%p lui=0x%p", plqi
, uqi
));
608 if (plqi
->sm_uqi
== NULL
) {
609 sm_dbg('@', ("unit not associated"));
611 } else if (plqi
->sm_uqi
->sm_lunit
!= unit
) {
612 sm_dbg('@', ("unit and linkid not related",
613 plqi
->sm_uqi
->sm_lunit
));
615 } else if (plqi
->sm_tag
!= tag
) {
617 ("Invalid tag for TTYMUX_DISASSOC ioctl\n"));
620 sm_dbg('Y', ("disassociating "));
622 (void) ttymux_device_fini(plqi
);
625 * Indicate that carrier status is no
626 * longer required and that the upper
627 * queue should not be used by plqi
629 plqi
->sm_flags
&= ~(WANT_CDSTAT
|WANT_TCSET
);
630 plqi
->sm_uqflags
&= ~(SM_UQVALID
|SM_OBPCNDEV
);
631 plqi
->sm_ioflag
= 0u;
638 sm_dbg('Y', (" rval=%d.\n", rval
));
644 * Streams helper routines;
648 * Schedule a qbufcall for an upper queue.
649 * Must be called within the perimiter of the parameter q.
650 * fn must reenable the q.
652 * whenever a message must be placed on multiple queues and allocb fails;
655 sm_sched_uqcb(queue_t
*q
, int memreq
, int pri
, void (*fn
)())
657 sm_uqi_t
*uqi
= q
->q_ptr
;
659 if (uqi
->sm_ttybid
!= 0)
660 qunbufcall(q
, uqi
->sm_ttybid
);
664 uqi
->sm_ttybid
= qbufcall(q
, memreq
, pri
, fn
, uqi
);
668 * qbufcall routine to restart the queues when memory is available.
671 sm_reenable_q(sm_uqi_t
*uqi
)
673 queue_t
*wq
= SM_WQ(uqi
);
675 if ((uqi
->sm_flags
& SM_STOPPED
) == 0) {
682 * Place a message on the write queue of each stream associated with
683 * the given upper stream.
686 sm_senddown(sm_uqi_t
*uqi
)
690 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
691 if (lqi
->sm_mp
!= 0) {
692 putnext(SM_WQ(lqi
), lqi
->sm_mp
);
699 * For each lower device that should receive a write message duplicate
703 sm_dupmsg(sm_uqi_t
*uqi
, mblk_t
*mp
)
708 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
710 if (lqi
->sm_flags
& WERROR_MODE
) {
713 if ((lqi
->sm_ioflag
& (uint_t
)FOROUTPUT
) == 0) {
714 if (DB_TYPE(mp
) == M_DATA
)
717 if (lqi
->sm_nlqi
== 0) {
720 } else if ((lqi
->sm_mp
= sm_copymsg(mp
)) == 0) {
723 for (flqi
= uqi
->sm_lqs
; flqi
!= lqi
;
724 flqi
= flqi
->sm_nlqi
) {
726 /* must have been sm_copymsg */
727 sm_freemsg(lqi
->sm_mp
);
731 return (sm_cnt_oqs(uqi
) * msgdsize(mp
));
740 * Return 1 if all associated lower devices have room for another message
741 * otherwise return 0.
744 sm_cansenddown(sm_uqi_t
*uqi
)
747 register sm_lqi_t
*lqi
;
749 if (uqi
->sm_lqs
== 0)
752 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
753 if ((lqi
->sm_flags
& WERROR_MODE
) == 0 &&
754 canputnext(SM_WQ(lqi
)) == 0)
761 * Put a message down all associated lower queues.
762 * Return 1 if the q function was called.
765 sm_putqs(queue_t
*q
, mblk_t
*mp
, int (*qfn
)())
767 register sm_uqi_t
*uqi
= (sm_uqi_t
*)q
->q_ptr
;
769 int pri
= (DB_TYPE(mp
) < QPCTL
) ? BPRI_MED
: BPRI_HI
;
772 if (uqi
->sm_lqs
== 0 || (uqi
->sm_flags
& WERROR_MODE
)) {
774 sm_dbg('Q', ("sm_putqs: freeing (0x%p 0x%p).\n", uqi
->sm_lqs
,
777 } else if (pri
!= BPRI_HI
&& sm_cansenddown(uqi
) == 0) {
778 /* a lower q is flow controlled */
781 } else if ((memreq
= sm_dupmsg(uqi
, mp
)) == 0) {
786 sm_log("sm_putqs: msg 0x%x - can't alloc %d bytes (pri %d).\n",
787 DB_TYPE(mp
), memreq
, pri
);
788 sm_sched_uqcb(q
, memreq
, pri
, sm_reenable_q
);
799 * Service a streams link and unlink requests.
802 sm_link_req(queue_t
*wq
, mblk_t
*mp
)
804 struct linkblk
*linkp
;
809 ASSERT(DB_TYPE(mp
) == M_IOCTL
);
811 cmd
= ((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
;
816 sm_dbg('G', ("sm_link_req: M_IOCTL %x (I_PLINK).\n", cmd
));
818 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
821 * 1. Sanity check the link block.
822 * 2. Validate that the queue is not already linked
823 * (and resources available).
824 * 3. Validate that the lower queue is not associated with
826 * 4. Remember that this lower queue is linked to the driver.
828 if ((linkp
== NULL
) || (MBLKL(mp
) < sizeof (*linkp
)) ||
829 linkp
->l_qbot
== NULL
) {
830 sm_dbg('I', ("sm_link_req: invalid link block.\n"));
832 } else if ((plqi
= get_lqi_byq(linkp
->l_qbot
)) == 0) {
833 sm_dbg('I', ("sm_link_req: out of resources.\n"));
834 rval
= EBUSY
; /* out of resources */
835 } else if (plqi
->sm_uqi
) {
836 UNLOCK_UNIT(plqi
); /* was aquired by get_lqi_byq */
837 sm_dbg('I', ("sm_link_req: already associated.\n"));
838 rval
= EBUSY
; /* already linked */
840 SM_WQ(plqi
) = linkp
->l_qbot
;
841 SM_RQ(plqi
) = OTHERQ(linkp
->l_qbot
);
843 linkp
->l_qbot
->q_ptr
=
844 OTHERQ(linkp
->l_qbot
)->q_ptr
= plqi
;
845 plqi
->sm_linkid
= linkp
->l_index
;
846 UNLOCK_UNIT(plqi
); /* was aquired by get_lqi_byq */
848 sm_dbg('H', ("sm_link_req: linkid = %d.\n",
851 sm_setdip(linkp
->l_qbot
, plqi
);
852 plqi
->sm_ttycommon
->t_flags
= 0;
853 plqi
->sm_ttycommon
->t_cflag
= 0;
855 (void) ttymux_device_init(plqi
);
863 sm_dbg('G', ("sm_link_req: M_IOCTL (I_PUNLINK).\n"));
865 linkp
= (struct linkblk
*)mp
->b_cont
->b_rptr
;
867 if ((linkp
== NULL
) ||
868 (MBLKL(mp
) < sizeof (*linkp
)) ||
869 linkp
->l_qbot
== NULL
) {
871 } else if ((plqi
= get_lqi_byid(linkp
->l_index
)) == 0) {
878 * Mark the lower q as invalid.
880 sm_dbg('G', ("I_PUNLINK: freeing link %d\n",
884 qunbufcall(SM_RQ(plqi
), plqi
->sm_bid
);
887 if (plqi
->sm_ttybid
) {
888 qunbufcall(SM_RQ(plqi
), plqi
->sm_ttybid
);
895 (void) ttymux_device_fini(plqi
);
898 (void) sm_disassociate(uqi
->sm_lunit
,
905 werrmode
= (plqi
->sm_flags
& (WERROR_MODE
|HANGUP_MODE
))
911 ttycommon_close(plqi
->sm_ttycommon
);
912 /* SM_RQ(plqi) = SM_WQ(plqi) = 0; */
913 plqi
->sm_ttycommon
->t_flags
= 0;
914 plqi
->sm_ttycommon
->t_cflag
= 0;
915 plqi
->sm_ttycommon
->t_iflag
= 0;
917 plqi
->sm_dev
= NODEV
;
918 plqi
->sm_hadkadbchar
= 0;
919 plqi
->sm_nachar
= sm_ssp
->sm_abs
;
924 (uqi
->sm_flags
& FULLY_OPEN
) &&
926 putnextctl(SM_RQ(uqi
), M_HANGUP
) == 0) {
927 sm_log("sm_link_req: putnextctl(M_HANGUP)"
939 miocnak(wq
, mp
, 0, rval
);
941 miocack(wq
, mp
, 0, 0);
945 sm_getiocinfo(mblk_t
*mp
, struct sm_iocinfo
*info
)
947 switch (DB_TYPE(mp
)) {
949 info
->sm_id
= ((struct copyreq
*)mp
->b_rptr
)->cq_id
;
950 info
->sm_cmd
= ((struct copyreq
*)mp
->b_rptr
)->cq_cmd
;
951 info
->sm_data
= (((struct copyreq
*)mp
->b_rptr
)->cq_size
&&
952 mp
->b_cont
) ? (void *)mp
->b_cont
->b_rptr
: 0;
955 info
->sm_id
= ((struct copyresp
*)mp
->b_rptr
)->cp_id
;
956 info
->sm_cmd
= ((struct copyresp
*)mp
->b_rptr
)->cp_cmd
;
960 info
->sm_id
= ((struct iocblk
*)mp
->b_rptr
)->ioc_id
;
961 info
->sm_cmd
= ((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
;
962 /* the se driver has bug so we cannot use ioc_count */
963 info
->sm_data
= (((struct iocblk
*)mp
->b_rptr
)->
964 ioc_error
== 0 && mp
->b_cont
) ?
965 (void *)mp
->b_cont
->b_rptr
: 0;
968 info
->sm_id
= ((struct iocblk
*)mp
->b_rptr
)->ioc_id
;
969 info
->sm_cmd
= ((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
;
973 info
->sm_id
= ((struct copyresp
*)mp
->b_rptr
)->cp_id
;
974 info
->sm_cmd
= ((struct copyresp
*)mp
->b_rptr
)->cp_cmd
;
975 info
->sm_data
= (((struct copyresp
*)mp
->b_rptr
)->
976 cp_rval
== 0 && mp
->b_cont
) ?
977 (void *)mp
->b_cont
->b_rptr
: 0;
980 info
->sm_id
= ((struct iocblk
*)mp
->b_rptr
)->ioc_id
;
981 info
->sm_cmd
= ((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
;
991 * Record the termio settings that have been set on the upper stream
994 sm_update_ttyinfo(mblk_t
*mp
, sm_uqi_t
*uqi
)
997 struct sm_iocinfo info
;
999 if ((err
= sm_getiocinfo(mp
, &info
)) != 0)
1002 switch (info
.sm_cmd
) {
1015 uqi
->sm_flags
|= FLUSHR_PEND
;
1016 sm_dbg('I', ("TCSETSF: FLUSH is pending\n"));
1021 if (info
.sm_data
!= 0) {
1022 ((struct termios
*)info
.sm_data
)->c_cflag
&=
1023 (tcflag_t
)(~uqi
->sm_cmask
);
1024 uqi
->sm_ttycommon
->t_cflag
=
1025 ((struct termios
*)info
.sm_data
)->c_cflag
;
1029 sm_dbg('I', ("TCSETAF: FLUSH is pending\n"));
1030 uqi
->sm_flags
|= FLUSHR_PEND
;
1035 if (info
.sm_data
!= 0) {
1036 ((struct termio
*)info
.sm_data
)->c_cflag
&=
1037 (tcflag_t
)(~uqi
->sm_cmask
);
1038 uqi
->sm_ttycommon
->t_cflag
=
1039 (tcflag_t
)((struct termio
*)info
.sm_data
)->c_cflag
;
1044 if (info
.sm_data
!= 0) {
1045 if (*(int *)info
.sm_data
== 1)
1046 uqi
->sm_ttycommon
->t_flags
|= TS_SOFTCAR
;
1048 uqi
->sm_ttycommon
->t_flags
&= ~TS_SOFTCAR
;
1053 if (info
.sm_data
!= 0)
1054 uqi
->sm_mbits
= *(int *)info
.sm_data
;
1057 if (info
.sm_data
!= 0)
1058 uqi
->sm_mbits
|= *(int *)info
.sm_data
;
1061 if (info
.sm_data
!= 0)
1062 uqi
->sm_mbits
&= ~(*(int *)info
.sm_data
);
1067 } /* end switch cmd */
1069 if ((uqi
->sm_mbits
& TIOCM_CD
) ||
1070 (uqi
->sm_ttycommon
->t_flags
& TS_SOFTCAR
) ||
1071 (uqi
->sm_ttycommon
->t_cflag
& CLOCAL
))
1072 uqi
->sm_flags
|= SM_CARON
;
1074 uqi
->sm_flags
&= ~SM_CARON
;
1081 * STREAM's interface to the OS.
1082 * Routines directly callable from the OS.
1086 * Processes high priority messages comming from modules above the
1088 * Return 1 if the queue was disabled.
1091 sm_hp_uwput(queue_t
*wq
, mblk_t
*mp
)
1093 sm_uqi_t
*uqi
= (sm_uqi_t
*)(wq
->q_ptr
);
1096 int msgtype
= DB_TYPE(mp
);
1102 * How to flush the bottom half:
1103 * putctl1(SM_WQ(plqi), *mp->b_rptr)
1104 * will work on the bottom half but if FLUSHR is set
1105 * when is the right time to flush the upper read queue.
1107 * Could set uqi->sm_flags & WANT_FLUSH but then what happens
1108 * if FLUSHR is set and the driver sends up a FLUSHR
1109 * before it handles the current FLUSHR request
1110 * (if only there was an id for the message that could
1111 * be matched when it returns back from the drivers.
1113 * Thus I'm going by the book - the bottom half acts like
1114 * a stream head and turns around FLUSHW back down to
1115 * the driver (see lrput). The upper half acts like a
1116 * driver and turns around FLUSHR:
1119 sm_dbg('I', ("sm_hp_uwput: FLUSH request 0x%x\n", *mp
->b_rptr
));
1120 /* flush the upper write queue */
1121 if (*mp
->b_rptr
& FLUSHW
)
1122 flushq(wq
, FLUSHDATA
);
1125 * flush each associated lower write queue
1126 * and pass down the driver (ignore the FLUSHR and deal with
1127 * it when it comes back up the read side.
1129 for (plqi
= uqi
->sm_lqs
; plqi
!= 0; plqi
= plqi
->sm_nlqi
) {
1130 if ((plqi
->sm_flags
& WERROR_MODE
) == 0 &&
1132 sm_dbg('I', ("flush lq 0x%p\n", SM_WQ(plqi
)));
1133 if (*mp
->b_rptr
& FLUSHW
)
1134 flushq(SM_WQ(plqi
), FLUSHDATA
);
1135 (void) putnextctl1(SM_WQ(plqi
), M_FLUSH
,
1142 for (plqi
= uqi
->sm_lqs
; plqi
!= 0; plqi
= plqi
->sm_nlqi
) {
1143 plqi
->sm_flags
&= ~SM_ISTOPPED
;
1144 if ((plqi
->sm_flags
& WERROR_MODE
) == 0)
1145 (void) putnextctl(SM_WQ(plqi
), msgtype
);
1150 for (plqi
= uqi
->sm_lqs
; plqi
!= 0; plqi
= plqi
->sm_nlqi
) {
1151 plqi
->sm_flags
|= SM_ISTOPPED
;
1152 if ((plqi
->sm_flags
& WERROR_MODE
) == 0)
1153 (void) putnextctl(SM_WQ(plqi
), msgtype
);
1157 case M_STOP
: /* must never be queued */
1158 uqi
->sm_flags
|= SM_STOPPED
;
1160 for (plqi
= uqi
->sm_lqs
; plqi
!= 0; plqi
= plqi
->sm_nlqi
)
1161 if ((plqi
->sm_flags
& WERROR_MODE
) == 0)
1162 (void) putnextctl(SM_WQ(plqi
), msgtype
);
1167 case M_START
: /* never be queued */
1168 uqi
->sm_flags
&= ~SM_STOPPED
;
1171 for (plqi
= uqi
->sm_lqs
; plqi
!= 0; plqi
= plqi
->sm_nlqi
)
1172 if ((plqi
->sm_flags
& WERROR_MODE
) == 0)
1173 (void) putnextctl(SM_WQ(plqi
), msgtype
);
1182 /* Wrong direction for message */
1189 sm_dbg('I', ("sm_hp_uwput: default case %d.\n", msgtype
));
1191 } /* end switch on high pri message type */
1198 sm_default_uwioctl(queue_t
*wq
, mblk_t
*mp
, int (*qfn
)())
1201 struct iocblk
*iobp
;
1204 uqi
= (sm_uqi_t
*)(wq
->q_ptr
);
1205 iobp
= (struct iocblk
*)mp
->b_rptr
;
1207 switch (iobp
->ioc_cmd
) {
1212 * The three ioctl types we support do not require any
1213 * additional allocation and should not return a pending
1214 * ioctl state. For this reason it is safe for us to ignore
1215 * the return value from ttycommon_ioctl().
1216 * Additionally, we translate any error response from
1217 * ttycommon_ioctl() into EINVAL.
1219 (void) ttycommon_ioctl(uqi
->sm_ttycommon
, wq
, mp
, &err
);
1221 miocnak(wq
, mp
, 0, EINVAL
);
1223 miocack(wq
, mp
, 0, 0);
1228 if ((err
= sm_update_ttyinfo(mp
, uqi
)) != 0) {
1229 miocnak(wq
, mp
, 0, err
);
1234 * If uqi->sm_siocdata.sm_iocid just overwrite it since the stream
1235 * head will have timed it out
1237 uqi
->sm_siocdata
.sm_iocid
= iobp
->ioc_id
;
1238 uqi
->sm_siocdata
.sm_acked
= 0;
1239 uqi
->sm_siocdata
.sm_nacks
= sm_good_qs(uqi
);
1240 uqi
->sm_siocdata
.sm_acnt
= 0;
1241 uqi
->sm_siocdata
.sm_policy
= uqi
->sm_policy
;
1242 uqi
->sm_siocdata
.sm_flags
= 0;
1243 sm_dbg('Z', (" want %d acks for id %d.\n",
1244 uqi
->sm_siocdata
.sm_nacks
, iobp
->ioc_id
));
1246 return (sm_putqs(wq
, mp
, qfn
));
1251 * sm_uwput - put function for an upper STREAM write.
1254 sm_uwput(queue_t
*wq
, mblk_t
*mp
)
1259 struct iocblk
*iobp
;
1261 uqi
= (sm_uqi_t
*)(wq
->q_ptr
);
1262 msgtype
= DB_TYPE(mp
);
1264 ASSERT(uqi
!= 0 && sm_ssp
!= 0);
1266 if (msgtype
>= QPCTL
&& msgtype
!= M_IOCDATA
) {
1267 (void) sm_hp_uwput(wq
, mp
);
1271 switch (DB_TYPE(mp
)) {
1276 (void) sm_putqs(wq
, mp
, putq
);
1280 if (((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
== MC_CANONQUERY
) {
1281 (void) putnextctl1(OTHERQ(wq
), M_CTL
, MC_NOCANON
);
1285 case M_IOCDATA
: /* not handled as high pri because may need to putbq */
1286 sm_dbg('M', ("sm_uwput(M_IOCDATA)\n"));
1289 cmd
= (msgtype
== M_IOCDATA
) ?
1290 ((struct copyresp
*)mp
->b_rptr
)->cp_cmd
:
1291 ((struct iocblk
*)mp
->b_rptr
)->ioc_cmd
;
1293 iobp
= (struct iocblk
*)mp
->b_rptr
;
1296 sm_dbg('M', ("sm_uwput(M_IOCTL:%d)\n", cmd
));
1300 case CONSGETABORTENABLE
:
1301 iobp
->ioc_error
= ttymux_abort_ioctl(mp
);
1302 DB_TYPE(mp
) = iobp
->ioc_error
? M_IOCNAK
: M_IOCACK
;
1305 case CONSSETABORTENABLE
:
1307 secpolicy_sys_config(iobp
->ioc_cr
, B_FALSE
) != 0 ?
1308 EPERM
: ttymux_abort_ioctl(mp
);
1309 DB_TYPE(mp
) = iobp
->ioc_error
? M_IOCNAK
: M_IOCACK
;
1312 case TTYMUX_SETABORT
:
1313 if (secpolicy_sys_config(iobp
->ioc_cr
, B_FALSE
) != 0) {
1314 iobp
->ioc_error
= EPERM
;
1315 DB_TYPE(mp
) = M_IOCNAK
;
1320 case TTYMUX_GETABORT
:
1321 case TTYMUX_GETABORTSTR
:
1323 case TTYMUX_DISASSOC
:
1325 case TTYMUX_GETLINK
:
1326 case TTYMUX_CONSDEV
:
1329 (void) sm_ioctl_cmd(uqi
, mp
);
1336 qwriter(wq
, mp
, sm_link_req
, PERIM_OUTER
);
1344 sm_dbg('A', ("sm_uwput: TCSET-> on srv q.\n"));
1345 /* keep message order intact */
1346 (void) putq(wq
, mp
);
1351 (void) sm_default_uwioctl(wq
, mp
, putq
);
1355 break; /* M_IOCTL */
1357 } /* end switch on message type */
1363 * sm_uwsrv - service function for an upper STREAM write.
1364 * 'sm_uwsrv' takes a q parameter. The q parameter specifies the queue
1365 * which is to be serviced. This function reads the messages which are on
1366 * this service queue and passes them to the appropriate lower driver queue.
1369 sm_uwsrv(queue_t
*q
)
1372 sm_uqi_t
*uqi
= (sm_uqi_t
*)(q
->q_ptr
);
1375 ASSERT(q
== SM_WQ(uqi
));
1378 * Empty the queue unless explicitly stopped.
1380 while (mp
= getq(q
)) {
1381 msgtype
= DB_TYPE(mp
);
1383 if (msgtype
>= QPCTL
&& msgtype
!= M_IOCDATA
)
1384 if (sm_hp_uwput(q
, mp
)) {
1385 sm_dbg('T', ("sm_uwsrv: flowcontrolled.\n"));
1386 break; /* indicates that the is disabled */
1391 if (uqi
->sm_flags
& SM_STOPPED
) {
1392 (void) putbq(q
, mp
);
1393 sm_dbg('T', ("sm_uwsrv: SM_STOPPED.\n"));
1398 * Read any ttycommon data that may
1399 * change (TS_SOFTCAR, CREAD, etc.).
1401 switch (DB_TYPE(mp
)) {
1404 if (sm_default_uwioctl(q
, mp
, putbq
))
1409 if (sm_putqs(q
, mp
, putbq
))
1417 * Lower write side service routine used for backenabling upstream
1421 sm_lwsrv(queue_t
*q
)
1423 sm_lqi_t
*lqi
= (sm_lqi_t
*)q
->q_ptr
;
1427 if (lqi
->sm_uqflags
& SM_UQVALID
) {
1429 * It's safe to lock uqi since lwsrv runs asynchronously
1430 * with the upper write routines so this cannot be an
1431 * upper half thread. While holding the lqi lock and
1432 * if SM_UQVALID is set we are guaranteed that
1433 * lqi->sm_uqi will be valid.
1435 sm_dbg('I', ("sm_lwsrv: re-enabling upper queue.\n"));
1437 uwq
= SM_WQ(lqi
->sm_uqi
);
1447 * Upper read queue ioctl response handler for messages
1448 * passed from the lower half of the driver.
1451 sm_uriocack(queue_t
*rq
, mblk_t
*mp
)
1453 sm_uqi_t
*uqi
= (sm_uqi_t
*)rq
->q_ptr
;
1456 struct sm_iocinfo info
;
1458 if ((err
= sm_getiocinfo(mp
, &info
)) != 0) {
1459 sm_dbg('I', ("Unknown ioctl response\n"));
1463 if (info
.sm_id
== uqi
->sm_piocdata
.sm_iocid
) {
1464 iodp
= &uqi
->sm_piocdata
;
1465 } else if (info
.sm_id
== uqi
->sm_siocdata
.sm_iocid
) {
1466 iodp
= &uqi
->sm_siocdata
;
1468 sm_log("Unexpected ioctl response\n");
1469 sm_dbg('I', ("Unexpected ioctl response (id %d)\n",
1473 * If the response is sent up it will result in
1474 * duplicate ioctl responses. The ioctl has probably been
1475 * timed out by the stream head so dispose of the response
1476 * (since it has arrived too late.
1483 switch (DB_TYPE(mp
)) {
1488 if (iodp
->sm_flags
& flag
)
1490 iodp
->sm_flags
|= flag
;
1494 iodp
->sm_ackcnt
+= 1;
1496 if (iodp
->sm_policy
== FIRSTACK
) {
1497 if (iodp
->sm_acnt
== iodp
->sm_nacks
)
1499 if (iodp
->sm_acnt
== 1)
1504 if (iodp
->sm_acnt
== iodp
->sm_nacks
) {
1512 iodp
->sm_nakcnt
+= 1;
1514 if (iodp
->sm_acnt
== iodp
->sm_nacks
) {
1516 if (iodp
->sm_acked
== 0) {
1527 * Merge the tty settings each of the associated lower streams.
1530 (void) sm_update_ttyinfo(mp
, uqi
);
1532 if (iodp
== &uqi
->sm_piocdata
) {
1533 if (iodp
->sm_iocid
== 0) {
1534 uqi
->sm_flags
&= ~SM_IOCPENDING
;
1537 sm_dbg('I', ("sm_uriocack: forwarding response for %d.\n",
1543 sm_dbg('I', ("sm_uriocack: freeing response for %d.\n", info
.sm_id
));
1549 * Transfer a message from the lower read side of the multiplexer onto
1550 * the associated upper stream.
1553 sm_ursendup(queue_t
*q
, mblk_t
*mp
)
1555 sm_uqi_t
*uqi
= (sm_uqi_t
*)q
->q_ptr
;
1557 if (!canputnext(q
) && DB_TYPE(mp
) < QPCTL
) {
1558 sm_dbg('I', ("sm_ursendup: flow controlled.\n"));
1562 switch (DB_TYPE(mp
)) {
1567 (void) sm_uriocack(q
, mp
);
1570 if (sm_uwq_error(uqi
)) {
1571 /* there are no usable lower q's */
1572 uqi
->sm_flags
&= ~SM_CARON
;
1575 /* there are still usable q's - don't send up */
1580 if (sm_uwq_error(uqi
)) {
1581 /* there are no usable lower q's */
1582 uqi
->sm_flags
&= ~SM_CARON
;
1584 } else if (*mp
->b_rptr
== NOERROR
) {
1585 /* the error has cleared */
1586 uqi
->sm_flags
&= ~ERROR_MODE
;
1589 /* there are still usable q's - don't send up */
1594 flushq(q
, FLUSHDATA
);
1595 putnext(q
, mp
); /* time to use FLUSHR_PEND flag */
1598 /* wrong direction - must have come from sm_close */
1599 uqi
->sm_flags
|= SM_CLOSE
;
1600 sm_dbg('I', ("sm_ursrv: had SM_CLOSE.\n"));
1604 /* just pass them all up - they're harmless */
1605 uqi
->sm_flags
|= SM_CARON
;
1616 * sm_urput - put function for a lower STREAM read.
1619 sm_urput(queue_t
*q
, mblk_t
*mp
)
1621 if (sm_ursendup(q
, mp
) != 0)
1628 * Upper read side service routine.
1629 * Read side needs to be fast so only check for duplicate M_IOCTL acks.
1632 sm_ursrv(queue_t
*q
)
1634 sm_uqi_t
*uqi
= (sm_uqi_t
*)q
->q_ptr
;
1636 int flags
= uqi
->sm_flags
;
1638 while ((mp
= getq(q
))) {
1639 if (sm_ursendup(q
, mp
) != 0) {
1640 sm_dbg('I', ("sm_ursrv: flow controlled.\n"));
1641 (void) putbq(q
, mp
);
1642 uqi
->sm_flags
|= WANT_RENB
;
1648 * If the q service was called because it was no longer
1649 * flow controled then enable each of the driver queues.
1651 if ((flags
& WANT_RENB
) && !(uqi
->sm_flags
& WANT_RENB
)) {
1653 queue_t
*drq
; /* read q of linked driver */
1655 uqi
->sm_flags
&= ~WANT_RENB
;
1656 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
1657 drq
= SM_RQ(lqi
)->q_next
;
1658 if (drq
&& drq
->q_first
!= 0)
1667 * Check a message sent from a linked device for abort requests and
1671 sm_lrmsg_check(queue_t
*q
, mblk_t
*mp
)
1673 sm_lqi_t
*lqi
= (sm_lqi_t
*)q
->q_ptr
;
1675 switch (DB_TYPE(mp
)) {
1679 * check for abort - only allow abort on I/O consoles
1681 * fix it when we do polled io
1683 if ((lqi
->sm_ioflag
& (uint_t
)FORINPUT
) == 0) {
1688 if ((lqi
->sm_uqflags
& SM_OBPCNDEV
) &&
1689 lqi
->sm_ctrla_abort_on
&&
1690 abort_enable
== KIOCABORTALTERNATE
) {
1693 boolean_t aborted
= B_FALSE
;
1695 for (rxc
= mp
->b_rptr
;
1699 if (*rxc
== *lqi
->sm_nachar
) {
1701 if (*lqi
->sm_nachar
== '\0') {
1702 abort_sequence_enter(
1704 lqi
->sm_nachar
= sm_ssp
->sm_abs
;
1708 lqi
->sm_nachar
= (*rxc
== *sm_ssp
->
1722 case M_BREAK
: /* we'll eventually see this as a flush */
1725 * Only allow abort on OBP devices. When polled I/O is
1726 * supported allow abort on any console device.
1727 * Parity errors are reported upstream as breaks so
1728 * ensure that there is no data in the message before
1729 * deciding whether to abort.
1731 if ((lqi
->sm_uqflags
& SM_OBPCNDEV
) && /* console stream */
1732 (mp
->b_wptr
- mp
->b_rptr
== 0 &&
1733 msgdsize(mp
) == 0)) { /* not due to parity */
1735 if (lqi
->sm_break_abort_on
&&
1736 abort_enable
!= KIOCABORTALTERNATE
)
1737 abort_sequence_enter(NULL
);
1750 if (DB_TYPE(mp
) >= QPCTL
)
1753 LOCK_UNIT(lqi
); /* lock out the upper half */
1754 if ((lqi
->sm_uqflags
& SM_UQVALID
) && SM_RQ(lqi
->sm_uqi
)) {
1756 if (!canput(SM_RQ(lqi
->sm_uqi
))) {
1757 sm_dbg('I', ("sm_lrmsg_check: flow controlled.\n"));
1769 * sm_sendup - deliver a message to the upper read side of the multiplexer
1772 sm_sendup(queue_t
*q
, mblk_t
*mp
)
1774 sm_lqi_t
*lqi
= (sm_lqi_t
*)q
->q_ptr
;
1776 if (sm_ssp
== NULL
) {
1782 * Check for CD status change messages from driver.
1783 * (Remark: this is an se driver thread running at soft interupt
1784 * priority and the waiters are in user context).
1786 switch (DB_TYPE(mp
)) {
1788 case M_BREAK
: /* we'll eventually see this as a flush */
1791 /* high priority messages */
1794 if ((lqi
->sm_flags
& SM_IOCPENDING
) && lqi
->sm_piocid
==
1795 ((struct iocblk
*)mp
->b_rptr
)->ioc_id
) {
1797 lqi
->sm_flags
&= ~SM_IOCPENDING
;
1798 sm_issue_ioctl(lqi
);
1804 * If the driver can send an M_UNHANGUP it must be able to
1805 * accept messages from above (ie clear WERROR_MODE if set).
1807 sm_dbg('E', ("lrput: M_UNHANGUP\n"));
1808 lqi
->sm_mbits
|= TIOCM_CD
;
1809 lqi
->sm_flags
&= ~(WERROR_MODE
|HANGUP_MODE
);
1814 sm_dbg('E', ("lrput: MHANGUP\n"));
1815 lqi
->sm_mbits
&= ~TIOCM_CD
;
1816 lqi
->sm_flags
|= (WERROR_MODE
|HANGUP_MODE
);
1821 sm_dbg('E', ("lrput: MERROR\n"));
1823 * Tell the driver to flush rd/wr queue if its read/write error.
1824 * if its a read/write error flush rq/wq (type in first bytes).
1826 if ((mp
->b_wptr
- mp
->b_rptr
) == 2) {
1829 if (*mp
->b_rptr
== NOERROR
) {
1830 /* not in error anymore */
1831 lqi
->sm_flags
&= ~ERROR_MODE
;
1832 lqi
->sm_flags
|= WANT_CD
;
1834 if (*mp
->b_rptr
!= 0) {
1837 lqi
->sm_flags
|= RERROR_MODE
;
1840 if (*mp
->b_rptr
!= 0) {
1843 lqi
->sm_flags
|= WERROR_MODE
;
1847 /* has next driver done qprocsoff */
1848 if (rw
&& OTHERQ(q
)->q_next
!= NULL
) {
1849 (void) putnextctl1(OTHERQ(q
), M_FLUSH
,
1853 } else if (*mp
->b_rptr
!= 0 && OTHERQ(q
)->q_next
!= NULL
) {
1854 sm_dbg('E', ("lrput: old style MERROR (?)\n"));
1856 lqi
->sm_flags
|= (RERROR_MODE
| WERROR_MODE
);
1857 (void) putnextctl1(OTHERQ(q
), M_FLUSH
, FLUSHRW
);
1868 /* flush the read queue and pass on up */
1869 flushq(q
, FLUSHDATA
);
1875 LOCK_UNIT(lqi
); /* lock out the upper half */
1876 if (lqi
->sm_uqflags
& SM_UQVALID
&& SM_RQ(lqi
->sm_uqi
)) {
1878 (void) putq(SM_RQ(lqi
->sm_uqi
), mp
);
1881 sm_dbg('I', ("sm_sendup: uq not valid\n"));
1890 * sm_lrput - put function for a lower STREAM read.
1893 sm_lrput(queue_t
*q
, mblk_t
*mp
)
1895 if (sm_lrmsg_check(q
, mp
) == 0)
1896 (void) sm_sendup(q
, mp
);
1901 * sm_lrsrv - service function for the lower read STREAM.
1904 sm_lrsrv(queue_t
*q
)
1908 sm_dbg('I', ("sm_lrsrv: not controlled.\n"));
1909 while (mp
= getq(q
))
1910 (void) sm_sendup(q
, mp
);
1916 * Check whether a thread is allowed to open the requested device.
1919 sm_ok_to_open(sm_uqi_t
*uqi
, int protocol
, cred_t
*credp
, int *abort_waiters
)
1927 case ASYNC_DEVICE
: /* Standard async protocol */
1928 if ((uqi
->sm_protocol
== NULL_PROTOCOL
) ||
1929 (uqi
->sm_protocol
== ASYN_PROTOCOL
)) {
1931 * Lock out other incompatible protocol requests.
1933 proto
= ASYN_PROTOCOL
;
1939 case OUTLINE
: /* Outdial protocol */
1940 if ((uqi
->sm_protocol
== NULL_PROTOCOL
) ||
1941 (uqi
->sm_protocol
== OUTD_PROTOCOL
)) {
1942 proto
= OUTD_PROTOCOL
;
1944 } else if (uqi
->sm_protocol
== ASYN_PROTOCOL
) {
1946 * check for dialout request on a line that is already
1948 * kick off any thread that is waiting to fully open
1950 if (uqi
->sm_flags
& FULLY_OPEN
)
1953 proto
= OUTD_PROTOCOL
;
1964 (uqi
->sm_ttycommon
->t_flags
& TS_XCLUDE
) &&
1965 secpolicy_excl_open(credp
) != 0) {
1967 if (uqi
->sm_flags
& FULLY_OPEN
) {
1968 rval
= EBUSY
; /* exclusive device already open */
1970 /* NB TS_XCLUDE cant be set during open so NOTREACHED */
1971 /* force any waiters to yield TS_XCLUDE */
1977 uqi
->sm_protocol
= proto
;
1979 sm_dbg('A', ("ok_to_open (0x%p, %d) proto=%d rval %d (wabort=%d)",
1980 uqi
, protocol
, uqi
->sm_protocol
, rval
, *abort_waiters
));
1985 /* wait for memory to become available whilst performing a qwait */
1987 static void dummy_callback(void *arg
)
1992 sm_dump_msg(queue_t
*q
, mblk_t
*mp
)
1999 * Wait for a message to arrive - must be called with exclusive
2000 * access at the outer perimiter.
2003 sm_qwait_sig(sm_uqi_t
*uqi
, queue_t
*q
)
2007 sm_dbg('C', ("sm_qwait_sig: waiting.\n"));
2010 uqi
->sm_nwaiters
++; /* required by the close routine */
2012 if (--uqi
->sm_nwaiters
== 0)
2017 else if (q
->q_ptr
== 0) /* can happen if there are multiple waiters */
2019 else if (uqi
->sm_flags
& SM_CLOSE
) {
2020 uqi
->sm_flags
&= ~SM_CLOSE
;
2021 err
= 1; /* a different protocol has closed its stream */
2024 err
= 0; /* was worth waiting for */
2026 sm_dbg('C', ("sm_qwait_sig: rval %d\n", err
));
2031 * Defer the opening of one the drivers devices until the state of each
2032 * associated lower stream is known.
2035 sm_defer_open(sm_uqi_t
*uqi
, queue_t
*q
)
2037 uint_t cmdflags
= WANT_CDSTAT
;
2040 while ((nqs
= sm_good_qs(uqi
)) == 0) {
2041 sm_dbg('C', ("sm_defer_open: no good qs\n"));
2042 if (err
= sm_qwait_sig(uqi
, q
))
2046 while ((uqi
->sm_flags
& SM_CARON
) == 0) {
2050 sm_dbg('C', ("sm_defer_open: flags 0x%x cmdflags 0x%x\n",
2051 uqi
->sm_flags
, cmdflags
));
2052 if (cmdflags
== 0) {
2053 if (err
= sm_qwait_sig(uqi
, q
))
2055 continue; /* waiting for an M_UNHANGUP */
2056 } else if (cmdflags
& WANT_SC
) {
2057 cmdflags
&= ~WANT_SC
;
2058 iocmd
= TIOCGSOFTCAR
;
2059 } else if (cmdflags
& WANT_CD
) {
2060 cmdflags
&= ~WANT_CD
;
2062 } else if (cmdflags
& WANT_CL
) {
2063 cmdflags
&= ~WANT_CL
;
2067 if (uqi
->sm_piocdata
.sm_iocid
== 0) {
2068 while ((pioc
= mkiocb(iocmd
)) == 0) {
2070 qbufcall(q
, sizeof (struct iocblk
),
2071 BPRI_MED
, dummy_callback
, 0);
2072 if (err
= sm_qwait_sig(uqi
, q
)) {
2073 /* wait for the bufcall */
2080 uqi
->sm_flags
|= SM_IOCPENDING
;
2082 uqi
->sm_piocdata
.sm_iocid
=
2083 ((struct iocblk
*)pioc
->b_rptr
)->ioc_id
;
2084 uqi
->sm_piocdata
.sm_acked
= 0;
2085 uqi
->sm_piocdata
.sm_nacks
= nqs
;
2086 uqi
->sm_piocdata
.sm_acnt
= 0;
2087 uqi
->sm_piocdata
.sm_ackcnt
= uqi
->
2088 sm_piocdata
.sm_nakcnt
= 0;
2089 uqi
->sm_piocdata
.sm_policy
= uqi
->sm_policy
;
2090 uqi
->sm_piocdata
.sm_flags
= SM_INTERNALIOC
;
2091 if (sm_putqs(WR(q
), pioc
, sm_dump_msg
) != 0) {
2092 uqi
->sm_piocdata
.sm_iocid
= 0;
2093 sm_log("sm_defer_open: bad putqs\n");
2098 sm_dbg('C', ("sm_defer_open: flags 0x%x\n", uqi
->sm_flags
));
2099 while ((uqi
->sm_flags
& SM_CARON
) == 0 &&
2100 (uqi
->sm_flags
& SM_IOCPENDING
) != 0)
2101 if (err
= sm_qwait_sig(uqi
, q
))
2104 sm_dbg('C', ("defer_open: uq flags 0x%x.\n", uqi
->sm_flags
));
2106 sm_dbg('C', ("defer_open: return 0.\n"));
2111 sm_open(queue_t
*rq
, dev_t
*devp
, int flag
, int sflag
, cred_t
*credp
)
2122 * sflag = 0 => streams device.
2124 if (sflag
!= 0 || DEV_TO_UNIT(*devp
) >= NLUNITS
) {
2125 sm_dbg('C', ("open: sflag=%d or bad dev_t.\n", sflag
));
2129 unit
= DEV_TO_UNIT(*devp
);
2130 protocol
= DEV_TO_PROTOBITS(*devp
);
2132 uqi
= get_uqi(sm_ssp
, unit
);
2134 sm_dbg('C', ("open(0x%p, %d, 0x%x) :- unit=%d, proto=%d, uqi=0x%p\n",
2135 rq
, *devp
, flag
, unit
, protocol
, uqi
));
2140 if (sm_refuse_opens
&& unit
> smctlunit
&& uqi
->sm_nlqs
== 0)
2143 if (uqi
->sm_flags
& EXCL_OPEN
&& (flag
& FEXCL
)) {
2144 return (EBUSY
); /* device in use */
2147 if ((flag
& FEXCL
)) {
2148 if (secpolicy_excl_open(credp
) != 0)
2151 if ((uqi
->sm_flags
& FULLY_OPEN
) || uqi
->sm_nwaiters
> 0)
2152 return (EBUSY
); /* device in use */
2154 uqi
->sm_flags
|= EXCL_OPEN
;
2157 if (uqi
->sm_protocol
== NULL_PROTOCOL
) {
2158 struct termios
*termiosp
;
2161 if (ddi_getlongprop(DDI_DEV_T_ANY
, ddi_root_node(),
2162 DDI_PROP_NOTPROM
, "ttymodes", (caddr_t
)&termiosp
, &len
)
2163 == DDI_PROP_SUCCESS
&&
2164 (len
== sizeof (struct termios
))) {
2166 sm_dbg('C', ("open: c_cflag=0x%x\n",
2167 termiosp
->c_cflag
));
2169 uqi
->sm_ttycommon
->t_iflag
= termiosp
->c_iflag
;
2170 uqi
->sm_ttycommon
->t_cflag
= termiosp
->c_cflag
;
2171 uqi
->sm_ttycommon
->t_stopc
= termiosp
->c_cc
[VSTOP
];
2172 uqi
->sm_ttycommon
->t_startc
= termiosp
->c_cc
[VSTART
];
2175 * IGNBRK,BRKINT,INPCK,IXON,IXANY,IXOFF - drivers
2176 * PARMRK,IGNPAR,ISTRIP - how to report parity
2177 * INLCR,IGNCR,ICRNL,IUCLC - ldterm (sophisticated I/O)
2178 * IXON, IXANY, IXOFF - flow control input
2179 * CBAUD,CSIZE,CS5-8,CSTOPB,PARENB,PARODD,HUPCL,
2180 * RCV1EN,XMT1EN,LOBLK,XCLUDE,CRTSXOFF,CRTSCTS,
2181 * CIBAUD,PAREXT,CBAUDEXT,CIBAUDEXT,CREAD,CLOCAL
2184 kmem_free(termiosp
, len
);
2187 bzero((caddr_t
)uqi
->sm_ttycommon
,
2188 sizeof (uqi
->sm_ttycommon
));
2190 if (*devp
== rconsdev
) {
2191 uqi
->sm_cmask
= sm_cmask
;
2192 uqi
->sm_ttycommon
->t_flags
|= TS_SOFTCAR
;
2194 uqi
->sm_ttycommon
->t_flags
&= ~TS_SOFTCAR
;
2198 * Clear the default CLOCAL and TS_SOFTCAR flags since
2199 * they must correspond to the settings on the real devices.
2202 uqi
->sm_ttycommon
->t_cflag
&= ~(uqi
->sm_cmask
|CLOCAL
);
2204 uqi
->sm_policy
= FIRSTACK
;
2205 if (unit
== 0 && sm_ssp
->sm_ms
== 0)
2206 sm_ssp
->sm_ms
= (sm_mux_state_t
*)
2207 space_fetch(TTYMUXPTR
);
2208 if (sm_ssp
->sm_ms
) {
2209 if (sm_ssp
->sm_ms
->sm_cons_stdin
.sm_dev
== *devp
||
2210 sm_ssp
->sm_ms
->sm_cons_stdout
.sm_dev
== *devp
)
2211 sm_ssp
->sm_lconsole
= uqi
;
2216 * Does this thread need to wait?
2219 sm_dbg('C', ("sm_open: %d %d 0x%p 0x%x\n",
2220 !(flag
& (FNDELAY
|FNONBLOCK
)), !(protocol
== OUTLINE
), uqi
->sm_lqs
,
2226 if (ftstat
= sm_ok_to_open(uqi
, protocol
, credp
, &abort_waiters
)) {
2227 sm_dbg('C', ("open failed stat=%d.\n", ftstat
));
2229 if ((uqi
->sm_flags
& FULLY_OPEN
) == 0 && uqi
->sm_nwaiters
== 0)
2230 uqi
->sm_protocol
= NULL_PROTOCOL
;
2232 uqi
->sm_flags
&= ~EXCL_OPEN
;
2236 if (abort_waiters
) {
2237 uqi
->sm_dev
= *devp
;
2238 /* different device wants to use the unit */
2240 SM_WQ(uqi
) = WR(rq
);
2242 if (rq
->q_ptr
== 0) {
2245 uqi
->sm_dev
= *devp
;
2246 rq
->q_ptr
= WR(rq
)->q_ptr
= uqi
;
2248 SM_WQ(uqi
) = WR(rq
);
2250 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
2252 lqi
->sm_uqflags
|= SM_UQVALID
;
2256 sm_dbg('C', ("sm_open: SM_UQVALID set on lqs.\n"));
2259 if (*devp
!= rconsdev
&& BLOCKING(uqi
, protocol
, flag
)) {
2261 uqi
->sm_flags
|= WANT_CDSTAT
;
2265 * Wait for notifications of changes in the CLOCAL
2266 * and TS_SOFTCAR flags and a TIOCM_CD flag of a
2267 * TIOCMGET request (come in on the write side queue).
2270 if ((ftstat
= sm_defer_open(uqi
, rq
)) != EINTR
) {
2278 if (uqi
->sm_nwaiters
== 0) { /* clean up */
2280 * only opens on an asynchronous
2281 * protocols reach here so checking
2282 * nwaiters == 0 is sufficient to
2283 * ensure that no other thread
2284 * is waiting on this logical unit
2286 if ((uqi
->sm_flags
& FULLY_OPEN
) == 0) {
2290 uqi
->sm_dev
= NODEV
;
2291 sm_dbg('C', ("sm_open FULLY_OPEN=0\n"));
2292 for (lqi
= uqi
->sm_lqs
; lqi
!= 0;
2293 lqi
= lqi
->sm_nlqi
) {
2295 lqi
->sm_uqflags
&= ~SM_UQVALID
;
2300 rq
->q_ptr
= WR(rq
)->q_ptr
= 0;
2305 if ((uqi
->sm_flags
& FULLY_OPEN
) == 0 &&
2306 uqi
->sm_nwaiters
== 0)
2307 uqi
->sm_protocol
= NULL_PROTOCOL
;
2309 uqi
->sm_flags
&= ~EXCL_OPEN
;
2310 sm_dbg('C', ("sm_open: done (ret %d).\n", ftstat
));
2312 } while (BLOCKING(uqi
, protocol
, flag
));
2315 uqi
->sm_flags
|= FULLY_OPEN
;
2317 sm_dbg('C', ("sm_open done (ret %d).\n", ftstat
));
2322 * Multiplexer device close routine.
2326 sm_close(queue_t
*rq
, int flag
, cred_t
*credp
)
2328 sm_uqi_t
*uqi
= (sm_uqi_t
*)rq
->q_ptr
;
2335 sm_dbg('C', ("close: WARN:- q 0x%p already closed.\n", rq
));
2339 sm_dbg('C', ("close: uqi=0x%p unit=%d q=0x%p)\n", uqi
, uqi
->sm_lunit
,
2342 if (SM_RQ(uqi
) != rq
)
2343 sm_dbg('C', ("sm_close: rq != current uqi queue\n"));
2345 if (uqi
->sm_ttybid
) {
2346 qunbufcall(SM_RQ(uqi
), uqi
->sm_ttybid
);
2351 * Tell all the linked queues that the upper queue has gone
2352 * Note close will never get called on a stream while there is a
2353 * thread blocked trying to open the same stream.
2354 * If there is a blocked open on a different stream but on
2355 * the same logical unit it will reset the lower queue flags.
2357 for (lqi
= uqi
->sm_lqs
; lqi
!= 0; lqi
= lqi
->sm_nlqi
) {
2359 lqi
->sm_uqflags
&= ~SM_UQVALID
;
2364 * Turn off the STREAMs queue processing for this queue.
2369 * Similarly we will never get here if there is thread trying to
2373 if (uqi
->sm_waitq
== 0)
2374 uqi
->sm_flags
= (uqi
->sm_flags
& SM_OBPCNDEV
) ? SM_OBPCNDEV
:
2377 uqi
->sm_dev
= NODEV
;
2378 uqi
->sm_protocol
= NULL_PROTOCOL
;
2379 ttycommon_close(uqi
->sm_ttycommon
);
2380 /* it just frees any pending ioctl */
2382 uqi
->sm_ttycommon
->t_cflag
= 0;
2383 uqi
->sm_ttycommon
->t_flags
= 0;
2386 * Reset the queue pointers to NULL.
2387 * If a thread is qwaiting in the open routine it will recheck
2391 WR(rq
)->q_ptr
= NULL
;
2394 if (sm_ssp
->sm_lconsole
== uqi
) {
2395 /* this will never be the outdial device closing */
2396 sm_ssp
->sm_lconsole
= 0;
2399 * If there is another thread waiting for this close then unblock
2400 * the thread by putting a message on its read queue.
2402 if (uqi
->sm_waitq
) {
2403 sm_dbg('C', ("close(0x%p): doing putctl on 0x%p\n",
2404 rq
, uqi
->sm_waitq
));
2405 if (rq
== uqi
->sm_waitq
)
2406 sm_log("close: waitq and closeq are same q\n");
2407 (void) putctl(uqi
->sm_waitq
, M_CTL
);
2410 uqi
->sm_flags
&= ~(EXCL_OPEN
| FULLY_OPEN
);
2411 sm_dbg('C', ("close: returning ok.\n"));
2416 * Initialise the software abort sequence for use when one of the
2417 * driver's nodes provides the system console.
2422 char ds
[3] = { '\r', '~', CNTRL('b') };
2423 char as
[SM_MAX_ABSLEN
];
2424 int len
= SM_MAX_ABSLEN
;
2426 if (ddi_prop_op(DDI_DEV_T_ANY
, sm_ssp
->sm_dip
, PROP_LEN_AND_VAL_BUF
, 0,
2427 "abort-str", as
, &len
) != DDI_PROP_SUCCESS
||
2428 (len
= strlen(as
)) < SM_MIN_ABSLEN
) {
2429 (void) strcpy(as
, ds
);
2435 for (s
= as
, i
= 0; i
< len
-1; i
++, s
++) {
2436 if (as
[i
] == '^' && as
[i
+1] >= 'a' && as
[i
+1] <= 'z') {
2437 *s
= as
[i
+1] - 'a' + 1;
2448 if (len
< SM_MIN_ABSLEN
)
2449 (void) strcpy(sm_ssp
->sm_abs
, ds
);
2451 (void) strcpy(sm_ssp
->sm_abs
, as
);
2456 * sm_attach - initialisation routine per driver instance.
2459 sm_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
2467 * Is this an attach?
2469 if (cmd
!= DDI_ATTACH
) {
2470 return (DDI_FAILURE
);
2474 * Validate the instance number (sm is a single instance driver).
2476 if (sm_ssp
) { /* only one instance allowed */
2477 return (DDI_FAILURE
);
2480 sm_instance
= ddi_get_instance(dip
);
2483 * Create the default minor node which will become the console.
2484 * (create it with three different names).:
2485 * con which appears in the /dev filesystem;
2486 * input which matches the prom /multiplexer:input node;
2487 * output which matches the prom /multiplexer:input node
2488 * Create a minor node for control operations.
2490 if (ddi_create_minor_node(dip
, "con", S_IFCHR
, 0,
2491 DDI_PSEUDO
, 0) != DDI_SUCCESS
||
2492 ddi_create_minor_node(dip
, "input", S_IFCHR
, 0,
2493 DDI_PSEUDO
, 0) != DDI_SUCCESS
||
2494 ddi_create_minor_node(dip
, "output", S_IFCHR
, 0,
2495 DDI_PSEUDO
, 0) != DDI_SUCCESS
||
2496 ddi_create_minor_node(dip
, "ctl", S_IFCHR
, 1,
2497 DDI_PSEUDO
, 0) != DDI_SUCCESS
) {
2499 cmn_err(CE_WARN
, "sm_attach: create minors failed.\n");
2500 ddi_remove_minor_node(dip
, NULL
);
2501 return (DDI_FAILURE
);
2507 * Allocate private state for this instance.
2509 sm_ssp
= (sm_ss_t
*)kmem_zalloc(sizeof (sm_ss_t
), KM_SLEEP
);
2512 * Initialise per instance data.
2514 sm_ssp
->sm_dip
= dip
;
2517 * Get required debug level.
2519 sm_ssp
->sm_trflag
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2520 DDI_PROP_DONTPASS
, "sm-trlv", sm_default_trflag
);
2522 sm_max_units
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2523 DDI_PROP_DONTPASS
, "sm-max-units", sm_max_units
);
2524 sm_minor_cnt
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2525 DDI_PROP_DONTPASS
, "sm-minor-cnt", 0);
2527 sm_refuse_opens
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2528 DDI_PROP_DONTPASS
, "sm-refuse-opens", sm_refuse_opens
);
2530 sm_ssp
->sm_ctrla_abort_on
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2531 DDI_PROP_DONTPASS
, "sm-ctrla-abort-on", 1);
2532 sm_ssp
->sm_break_abort_on
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
2533 DDI_PROP_DONTPASS
, "sm-break-abort-on", 0);
2537 sm_ssp
->sm_lqs
= (sm_lqi_t
*)kmem_zalloc(sizeof (sm_lqi_t
) * MAX_LQS
,
2539 sm_ssp
->sm_uqs
= (sm_uqi_t
*)kmem_zalloc(sizeof (sm_uqi_t
) * NLUNITS
,
2542 for (unit
= 2; unit
< NLUNITS
&& unit
< sm_minor_cnt
+ 2; unit
++) {
2544 if (snprintf(name
, sizeof (name
), "sm%c", 'a' + unit
-2) >
2547 "sm_attach: create device for unit %d failed.\n",
2549 } else if (ddi_create_minor_node(dip
, name
, S_IFCHR
,
2550 unit
, DDI_NT_SERIAL
, NULL
) != DDI_SUCCESS
) {
2551 ddi_remove_minor_node(dip
, NULL
);
2552 return (DDI_FAILURE
);
2555 if (snprintf(name
, sizeof (name
), "sm%c,cu", 'a' + unit
-2) >
2558 "sm_attach: create cu device for unit %d failed.\n",
2561 } else if (ddi_create_minor_node(dip
, name
, S_IFCHR
,
2562 unit
|OUTLINE
, DDI_NT_SERIAL_DO
, NULL
) != DDI_SUCCESS
) {
2563 ddi_remove_minor_node(dip
, NULL
);
2564 return (DDI_FAILURE
);
2568 for (unit
= 0; unit
< NLUNITS
; unit
++) {
2570 uqi
= get_uqi(sm_ssp
, unit
);
2572 uqi
->sm_dev
= NODEV
;
2574 uqi
->sm_lunit
= unit
;
2575 uqi
->sm_protocol
= NULL_PROTOCOL
;
2576 mutex_init(uqi
->sm_umutex
, NULL
, MUTEX_DRIVER
, NULL
);
2577 cv_init(uqi
->sm_ucv
, NULL
, CV_DRIVER
, NULL
);
2578 mutex_init(&uqi
->sm_ttycommon
->t_excl
, NULL
,
2579 MUTEX_DRIVER
, NULL
);
2582 for (unit
= 0; unit
< MAX_LQS
; unit
++) {
2583 lqip
= get_lqi(sm_ssp
, unit
);
2584 lqip
->sm_unit
= unit
;
2585 lqip
->sm_hadkadbchar
= 0;
2586 lqip
->sm_nachar
= sm_ssp
->sm_abs
;
2587 lqip
->sm_ioflag
= FORIO
;
2588 lqip
->sm_ctrla_abort_on
= sm_ssp
->sm_ctrla_abort_on
;
2589 lqip
->sm_break_abort_on
= sm_ssp
->sm_break_abort_on
;
2590 mutex_init(lqip
->sm_umutex
, NULL
, MUTEX_DRIVER
, NULL
);
2591 cv_init(lqip
->sm_ucv
, NULL
, CV_DRIVER
, NULL
);
2592 mutex_init(&lqip
->sm_ttycommon
->t_excl
, NULL
,
2593 MUTEX_DRIVER
, NULL
);
2596 return (DDI_SUCCESS
);
2601 * sm_detach - detach routine per driver instance.
2604 sm_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
2611 * Is this a detach request for instance 0 (single instance driver).
2613 if (cmd
!= DDI_DETACH
)
2614 return (DDI_FAILURE
);
2617 return (DDI_FAILURE
);
2619 sm_dbg('V', ("detach ..."));
2623 * Check that all the upper and lower queues are closed.
2626 for (unit
= 0; unit
< NLUNITS
; unit
++) {
2627 lu
= &sm_ssp
->sm_uqs
[unit
];
2628 if (lu
&& lu
->sm_protocol
!= NULL_PROTOCOL
) {
2629 sm_dbg('V', ("detach: upper unit still open.\n"));
2630 return (DDI_FAILURE
);
2633 for (unit
= 0; unit
< MAX_LQS
; unit
++) {
2634 pu
= &sm_ssp
->sm_lqs
[unit
];
2635 if (pu
&& pu
->sm_linkid
!= 0) {
2636 sm_dbg('V', ("detach: lower unit still linked (%d)\n",
2638 return (DDI_FAILURE
);
2642 for (unit
= 0; unit
< NLUNITS
; unit
++) {
2643 lu
= &sm_ssp
->sm_uqs
[unit
];
2644 mutex_destroy(lu
->sm_umutex
);
2645 cv_destroy(lu
->sm_ucv
);
2646 mutex_destroy(&lu
->sm_ttycommon
->t_excl
);
2648 for (unit
= 0; unit
< MAX_LQS
; unit
++) {
2649 pu
= &sm_ssp
->sm_lqs
[unit
];
2650 mutex_destroy(pu
->sm_umutex
);
2651 cv_destroy(pu
->sm_ucv
);
2652 mutex_destroy(&pu
->sm_ttycommon
->t_excl
);
2656 * Tidy up per instance state.
2658 kmem_free(sm_ssp
->sm_lqs
, sizeof (sm_lqi_t
) * MAX_LQS
);
2659 kmem_free(sm_ssp
->sm_uqs
, sizeof (sm_uqi_t
) * NLUNITS
);
2660 kmem_free(sm_ssp
, sizeof (sm_ss_t
));
2665 * Remove all of the devices created in attach.
2667 ddi_remove_minor_node(dip
, NULL
);
2669 return (DDI_SUCCESS
);
2674 * Driver interface to the OS.
2678 * The driver is responsible for managing the mapping between the file system
2679 * device types (major/minor pairs) and the corresponding instance of the driver
2680 * or device information pointer (dip).
2681 * sm_info - return the instance or dip corresponding to the dev_t.
2685 sm_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
2687 int res
= DDI_SUCCESS
;
2690 case DDI_INFO_DEVT2DEVINFO
:
2694 *result
= (void *)sm_ssp
->sm_dip
;
2697 case DDI_INFO_DEVT2INSTANCE
:
2698 *result
= NULL
; /* single instance driver */
2710 * End of driver implementation
2714 * Loadable module interface to the kernel
2718 * Firstly the Streams specific interface
2722 * Solaris driver/STREAM initialisation structures.
2724 static struct module_info uinfo
=
2728 0, /* min packet size */
2729 INFPSZ
, /* max packet size */
2730 2048, /* high water mark */
2731 256, /* low water mark */
2735 * Use zero water marks becuase the lower queues are used only for flow control.
2737 static struct module_info linfo
=
2741 0, /* min packet size */
2742 INFPSZ
, /* max packet size */
2743 0, /* high water mark */
2744 0 /* low water mark */
2749 * Solaris upper read STREAM initialisation structure.
2751 static struct qinit urinit
=
2754 sm_ursrv
, /* service */
2756 sm_close
, /* close */
2758 &uinfo
, /* module info */
2763 * Solaris upper write STREAM initialisation structure.
2765 static struct qinit uwinit
=
2777 * Solaris lower read STREAM initialisation structure.
2779 static struct qinit lrinit
=
2790 * Solaris lower write STREAM initialisation structure.
2792 static struct qinit lwinit
=
2804 * Multiplexing STREAM structure.
2806 struct streamtab sm_streamtab
=
2815 * Driver operations structure (struct cb_ops) and
2816 * driver dynamic loading functions (struct dev_ops).
2820 * Fold the Stream interface to the kernel into the driver interface
2824 DDI_DEFINE_STREAM_OPS(sm_ops
, \
2826 sm_attach
, sm_detach
, nodev
, \
2827 sm_info
, (D_NEW
| D_MTQPAIR
|D_MTOUTPERIM
|D_MTOCEXCL
| D_MP
),
2828 &sm_streamtab
, ddi_quiesce_not_supported
);
2831 * Driver module information.
2833 extern struct mod_ops mod_driverops
;
2834 static struct modldrv modldrv
=
2837 "serial mux driver",
2841 static struct modlinkage modlinkage
=
2849 * Define the body of our interface to the OS.
2853 * '_init' is called by Solaris to initialise any driver
2854 * specific state and to install the driver.
2859 return (mod_install(&modlinkage
));
2863 * _info - return this drivers interface to the kernel.
2866 _info(struct modinfo
*modinfop
)
2868 return (mod_info(&modlinkage
, modinfop
));
2872 * _fini - the OS is finished with the services provided by the driver.
2873 * remove ourself and then remove any footprint that remains.
2878 return (mod_remove(&modlinkage
));