1 /*
   2  * CDDL HEADER START
   3  *
   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.
   7  *
   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.
  12  *
  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]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <sys/ddi.h>
  29 #include <sys/cmn_err.h>
  30 #include <sys/modctl.h>
  31 #include <sys/ptms.h>
  32 #include <sys/stropts.h>
  33 #include <sys/strsun.h>
  34 #include <sys/sunddi.h>
  35 
  36 #include <sys/ldlinux.h>
  37 
  38 
  39 /*
  40  * ldlinuxopen - open routine gets called when the module gets pushed onto the
  41  * stream.
  42  */
  43 /* ARGSUSED */
  44 static int
  45 ldlinuxopen(
  46         queue_t    *q,          /* pointer to the read side queue */
  47         dev_t   *devp,          /* pointer to stream tail's dev */
  48         int     oflag,          /* the user open(2) supplied flags */
  49         int     sflag,          /* open state flag */
  50         cred_t *credp)          /* credentials */
  51 {
  52         struct ldlinux *tp;     /* ldlinux entry for this module */
  53         mblk_t *mop;
  54         struct stroptions *sop;
  55         struct termios *termiosp;
  56         int len;
  57 
  58         if (sflag != MODOPEN)
  59                 return (EINVAL);
  60 
  61         if (q->q_ptr != NULL) {
  62                 /* It's already attached. */
  63                 return (0);
  64         }
  65 
  66         mop = allocb(sizeof (struct stroptions), BPRI_MED);
  67         if (mop == NULL)
  68                 return (ENOSR);
  69         mop->b_datap->db_type = M_SETOPTS;
  70         mop->b_wptr += sizeof (struct stroptions);
  71         sop = (struct stroptions *)mop->b_rptr;
  72         sop->so_flags = SO_ISTTY;
  73 
  74         /*
  75          * Allocate state structure.
  76          */
  77         tp = kmem_alloc(sizeof (*tp), KM_SLEEP);
  78 
  79         /* Stash a pointer to our private data in q_ptr. */
  80         q->q_ptr = WR(q)->q_ptr = tp;
  81 
  82         /*
  83          * Get termios defaults.  These are stored as
  84          * a property in the "options" node.
  85          */
  86         if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
  87             (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
  88             len == sizeof (struct termios)) {
  89                 if (termiosp->c_lflag & ICANON) {
  90                         tp->veof = termiosp->c_cc[VEOF];
  91                         tp->veol = termiosp->c_cc[VEOL];
  92                         tp->vmin = 1;
  93                         tp->vtime = 0;
  94                 } else {
  95                         tp->veof = 0;
  96                         tp->veol = 0;
  97                         tp->vmin = termiosp->c_cc[VMIN];
  98                         tp->vtime = termiosp->c_cc[VTIME];
  99                 }
 100                 kmem_free(termiosp, len);
 101         } else {
 102                 /*
 103                  * winge winge winge...
 104                  */
 105                 cmn_err(CE_WARN,
 106                     "ldlinuxopen: Couldn't get ttymodes property!");
 107                 bzero(tp, sizeof (*tp));
 108         }
 109 
 110         tp->state = 0;
 111 
 112         /*
 113          * Commit to the open and send the M_SETOPTS off to the stream head.
 114          */
 115         qprocson(q);
 116         putnext(q, mop);
 117 
 118         return (0);
 119 }
 120 
 121 
 122 /*
 123  * ldlinuxclose - This routine gets called when the module gets
 124  * popped off of the stream.
 125  */
 126 /* ARGSUSED */
 127 static int
 128 ldlinuxclose(queue_t *q, int flag, cred_t *credp)
 129 {
 130         struct ldlinux *tp;
 131 
 132         qprocsoff(q);
 133         tp = q->q_ptr;
 134         kmem_free(tp, sizeof (*tp));
 135         q->q_ptr = WR(q)->q_ptr = NULL;
 136         return (0);
 137 }
 138 
 139 
 140 static void
 141 do_ioctl(queue_t *q, mblk_t *mp)
 142 {
 143         struct ldlinux  *tp = q->q_ptr;
 144         struct iocblk   *iocp = (struct iocblk *)mp->b_rptr;
 145         struct lx_cc    *cb;
 146         mblk_t          *tmp;
 147         int             error;
 148 
 149         switch (iocp->ioc_cmd) {
 150         case TIOCSETLD:
 151                 /* prepare caller supplied data for access */
 152                 error = miocpullup(mp, sizeof (struct lx_cc));
 153                 if (error != 0) {
 154                         miocnak(q, mp, 0, error);
 155                         return;
 156                 }
 157 
 158                 /* get a pointer to the caller supplied data */
 159                 cb = (struct lx_cc *)mp->b_cont->b_rptr;
 160 
 161                 /* save caller supplied data in our per-stream cache */
 162                 tp->veof = cb->veof;
 163                 tp->veol = cb->veol;
 164                 tp->vmin = cb->vmin;
 165                 tp->vtime = cb->vtime;
 166 
 167                 /* initialize and send a reply indicating that we're done */
 168                 miocack(q, mp, 0, 0);
 169                 return;
 170 
 171         case TIOCGETLD:
 172                 /* allocate a reply message */
 173                 if ((tmp = allocb(sizeof (struct lx_cc), BPRI_MED)) == NULL) {
 174                         miocnak(q, mp, 0, ENOSR);
 175                         return;
 176                 }
 177 
 178                 /* initialize the reply message */
 179                 mioc2ack(mp, tmp, sizeof (struct lx_cc), 0);
 180 
 181                 /* get a pointer to the reply data */
 182                 cb = (struct lx_cc *)mp->b_cont->b_rptr;
 183 
 184                 /* copy data from our per-stream cache into the reply data */
 185                 cb->veof = tp->veof;
 186                 cb->veol = tp->veol;
 187                 cb->vmin = tp->vmin;
 188                 cb->vtime = tp->vtime;
 189 
 190                 /* send the reply indicating that we're done */
 191                 qreply(q, mp);
 192                 return;
 193 
 194         case PTSSTTY:
 195                 tp->state |= ISPTSTTY;
 196                 break;
 197 
 198         default:
 199                 break;
 200         }
 201 
 202         putnext(q, mp);
 203 }
 204 
 205 
 206 /*
 207  * ldlinuxput - Module read and write queue put procedure.
 208  */
 209 static void
 210 ldlinuxput(queue_t *q, mblk_t *mp)
 211 {
 212         struct ldlinux *tp = q->q_ptr;
 213 
 214         switch (DB_TYPE(mp)) {
 215         default:
 216                 break;
 217         case M_IOCTL:
 218                 if ((q->q_flag & QREADR) == 0) {
 219                         do_ioctl(q, mp);
 220                         return;
 221                 }
 222                 break;
 223 
 224         case M_FLUSH:
 225                 /*
 226                  * Handle read and write flushes.
 227                  */
 228                 if ((((q->q_flag & QREADR) != 0) && (*mp->b_rptr & FLUSHR)) ||
 229                     (((q->q_flag & QREADR) == 0) && (*mp->b_rptr & FLUSHW))) {
 230                         if ((tp->state & ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
 231                                 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
 232                         else
 233                                 flushq(q, FLUSHDATA);
 234                 }
 235                 break;
 236         }
 237         putnext(q, mp);
 238 }
 239 
 240 
 241 static struct module_info ldlinux_info = {
 242         LDLINUX_MODID,
 243         LDLINUX_MOD,
 244         0,
 245         INFPSZ,
 246         0,
 247         0
 248 };
 249 
 250 static struct qinit ldlinuxinit = {
 251         (int (*)()) ldlinuxput,
 252         NULL,
 253         ldlinuxopen,
 254         ldlinuxclose,
 255         NULL,
 256         &ldlinux_info
 257 };
 258 
 259 static struct streamtab ldlinuxinfo = {
 260         &ldlinuxinit,
 261         &ldlinuxinit
 262 };
 263 
 264 /*
 265  * Module linkage information for the kernel.
 266  */
 267 static struct fmodsw fsw = {
 268         LDLINUX_MOD,
 269         &ldlinuxinfo,
 270         D_MTQPAIR | D_MP
 271 };
 272 
 273 static struct modlstrmod modlstrmod = {
 274         &mod_strmodops, "termios extensions for lx brand", &fsw
 275 };
 276 
 277 static struct modlinkage modlinkage = {
 278         MODREV_1, &modlstrmod, NULL
 279 };
 280 
 281 int
 282 _init()
 283 {
 284         return (mod_install(&modlinkage));
 285 }
 286 
 287 int
 288 _fini()
 289 {
 290         return (mod_remove(&modlinkage));
 291 }
 292 
 293 int
 294 _info(struct modinfo *modinfop)
 295 {
 296         return (mod_info(&modlinkage, modinfop));
 297 }