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 }