blob: 615cd61cd25f34bafa5ede433cb7e5237f81332d [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
edp8ec5a142006-04-28 18:39:47 -07005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
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 */
edp8ec5a142006-04-28 18:39:47 -070021
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070022/*
Sherry Moore19397402008-09-22 16:30:26 -070023 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070024 * Use is subject to license terms.
25 */
26
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070027
28/*
edp8ec5a142006-04-28 18:39:47 -070029 * workstation console redirecting driver
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070030 *
31 * Redirects all I/O through a given device instance to the device designated
32 * as the current target, as given by the vnode associated with the first
33 * entry in the list of redirections for the given device instance. The
34 * implementation assumes that this vnode denotes a STREAMS device; this is
35 * perhaps a bug.
36 *
37 * Supports the SRIOCSREDIR ioctl for designating a new redirection target.
38 * The new target is added to the front of a list of potentially active
39 * designees. Should the device at the front of this list be closed, the new
40 * front entry assumes active duty. (Stated differently, redirection targets
41 * stack, except that it's possible for entries in the interior of the stack
42 * to go away.)
43 *
44 * Supports the SRIOCISREDIR ioctl for inquiring whether the descriptor given
45 * as argument is the current front of the redirection list associated with
46 * the descriptor on which the ioctl was issued.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070047 */
48
49#include <sys/types.h>
50#include <sys/sysmacros.h>
51#include <sys/open.h>
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/signal.h>
55#include <sys/cred.h>
56#include <sys/user.h>
57#include <sys/proc.h>
58#include <sys/vnode.h>
59#include <sys/uio.h>
60#include <sys/file.h>
61#include <sys/kmem.h>
62#include <sys/stat.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070063#include <sys/stream.h>
64#include <sys/stropts.h>
65#include <sys/strsubr.h>
66#include <sys/poll.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070067#include <sys/debug.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070068#include <sys/strredir.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070069#include <sys/conf.h>
70#include <sys/ddi.h>
71#include <sys/sunddi.h>
edp8ec5a142006-04-28 18:39:47 -070072#include <sys/errno.h>
73#include <sys/modctl.h>
74#include <sys/sunldi.h>
75#include <sys/consdev.h>
76#include <sys/fs/snode.h>
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070077
78/*
edp8ec5a142006-04-28 18:39:47 -070079 * Global data
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070080 */
81static dev_info_t *iwscn_dip;
82
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070083/*
edp8ec5a142006-04-28 18:39:47 -070084 * We record the list of redirections as a linked list of iwscn_list_t
85 * structures. We need to keep track of the target's vp, so that
86 * we can vector reads, writes, etc. off to the current designee.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070087 */
edp8ec5a142006-04-28 18:39:47 -070088typedef struct _iwscn_list {
89 struct _iwscn_list *wl_next; /* next entry */
90 vnode_t *wl_vp; /* target's vnode */
91 int wl_ref_cnt; /* operation in progress */
92 boolean_t wl_is_console; /* is the real console */
93} iwscn_list_t;
94static iwscn_list_t *iwscn_list;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070095
96/*
edp8ec5a142006-04-28 18:39:47 -070097 * iwscn_list_lock serializes modifications to the global iwscn_list list.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070098 *
edp8ec5a142006-04-28 18:39:47 -070099 * iwscn_list_cv is used when freeing an entry from iwscn_list to allow
100 * the caller to wait till the wl_ref_cnt field is zero.
101 *
102 * iwscn_redirect_lock is used to serialize redirection requests. This
103 * is required to ensure that all active redirection streams have
104 * the redirection streams module (redirmod) pushed on them.
105 *
106 * If both iwscn_redirect_lock and iwscn_list_lock must be held then
amwda6c28a2007-10-25 16:34:29 -0700107 * iwscn_redirect_lock must be acquired first.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700108 */
edp8ec5a142006-04-28 18:39:47 -0700109static kcondvar_t iwscn_list_cv;
110static kmutex_t iwscn_list_lock;
111static kmutex_t iwscn_redirect_lock;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700112
113/*
edp8ec5a142006-04-28 18:39:47 -0700114 * Routines for managing iwscn_list
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700115 */
edp8ec5a142006-04-28 18:39:47 -0700116static vnode_t *
117str_vp(vnode_t *vp)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700118{
edp8ec5a142006-04-28 18:39:47 -0700119 /*
120 * Here we switch to using the vnode that is linked
121 * to from the stream queue. (In the case of device
122 * streams this will correspond to the common vnode
123 * for the device.) The reason we use this vnode
124 * is that when wcmclose() calls srpop(), this is the
125 * only vnode that it has access to.
126 */
127 ASSERT(vp->v_stream != NULL);
128 return (vp->v_stream->sd_vnode);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700129}
130
131/*
ns92644e493d0f2006-08-02 08:27:50 -0700132 * Interrupt any operations that may be outstanding against this vnode.
133 * optionally, wait for them to complete.
134 */
135static void
136srinterrupt(iwscn_list_t *lp, boolean_t wait)
137{
138 ASSERT(MUTEX_HELD(&iwscn_list_lock));
139
140 while (lp->wl_ref_cnt != 0) {
141 strsetrerror(lp->wl_vp, EINTR, 0, NULL);
142 strsetwerror(lp->wl_vp, EINTR, 0, NULL);
143 if (!wait)
144 break;
145 cv_wait(&iwscn_list_cv, &iwscn_list_lock);
146 }
147}
148
149/*
edp8ec5a142006-04-28 18:39:47 -0700150 * Remove vp from the redirection list rooted at iwscn_list, should it
ns92644e493d0f2006-08-02 08:27:50 -0700151 * be there. Return a pointer to the removed entry.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700152 */
edp8ec5a142006-04-28 18:39:47 -0700153static iwscn_list_t *
ns92644e493d0f2006-08-02 08:27:50 -0700154srrm(vnode_t *vp)
edp8ec5a142006-04-28 18:39:47 -0700155{
156 iwscn_list_t *lp, **lpp;
157
158 ASSERT(MUTEX_HELD(&iwscn_list_lock));
159
160 /* Get the stream vnode */
161 vp = str_vp(vp);
162 ASSERT(vp);
163
164 /* Look for this vnode on the redirection list */
165 for (lpp = &iwscn_list; (lp = *lpp) != NULL; lpp = &lp->wl_next) {
166 if (lp->wl_vp == vp)
167 break;
168 }
ns92644e493d0f2006-08-02 08:27:50 -0700169 if (lp != NULL)
170 /* Found it, remove this entry from the redirection list */
171 *lpp = lp->wl_next;
edp8ec5a142006-04-28 18:39:47 -0700172
ns92644e493d0f2006-08-02 08:27:50 -0700173 return (lp);
edp8ec5a142006-04-28 18:39:47 -0700174}
175
176/*
177 * Push vp onto the redirection list.
178 * If it's already there move it to the front position.
179 */
180static void
181srpush(vnode_t *vp, boolean_t is_console)
182{
183 iwscn_list_t *lp;
184
185 ASSERT(MUTEX_HELD(&iwscn_list_lock));
186
187 /* Get the stream vnode */
188 vp = str_vp(vp);
189 ASSERT(vp);
190
191 /* Check if it's already on the redirection list */
ns92644e493d0f2006-08-02 08:27:50 -0700192 if ((lp = srrm(vp)) == NULL) {
edp8ec5a142006-04-28 18:39:47 -0700193 lp = kmem_zalloc(sizeof (*lp), KM_SLEEP);
194 lp->wl_vp = vp;
ns92644e493d0f2006-08-02 08:27:50 -0700195 lp->wl_is_console = is_console;
edp8ec5a142006-04-28 18:39:47 -0700196 }
edp8ec5a142006-04-28 18:39:47 -0700197 /*
198 * Note that if this vnode was already somewhere on the redirection
199 * list then we removed it above and are now bumping it up to the
ns92644e493d0f2006-08-02 08:27:50 -0700200 * front of the redirection list.
edp8ec5a142006-04-28 18:39:47 -0700201 */
202 lp->wl_next = iwscn_list;
203 iwscn_list = lp;
204}
205
206/*
ns92644e493d0f2006-08-02 08:27:50 -0700207 * This vnode is no longer a valid redirection target. Terminate any current
208 * operations. If closing, wait for them to complete, then free the entry.
209 * If called because a hangup has occurred, just deprecate the entry to ensure
210 * it won't become the target again.
edp8ec5a142006-04-28 18:39:47 -0700211 */
212void
ns92644e493d0f2006-08-02 08:27:50 -0700213srpop(vnode_t *vp, boolean_t close)
edp8ec5a142006-04-28 18:39:47 -0700214{
ns92644e493d0f2006-08-02 08:27:50 -0700215 iwscn_list_t *tlp; /* This target's entry */
216 iwscn_list_t *lp, **lpp;
217
edp8ec5a142006-04-28 18:39:47 -0700218 mutex_enter(&iwscn_list_lock);
ns92644e493d0f2006-08-02 08:27:50 -0700219
220 /*
221 * Ensure no further operations are directed at the target
222 * by removing it from the redirection list.
223 */
224 if ((tlp = srrm(vp)) == NULL) {
225 /* vnode wasn't in the list */
226 mutex_exit(&iwscn_list_lock);
227 return;
228 }
229 /*
230 * Terminate any current operations.
231 * If we're closing, wait until they complete.
232 */
233 srinterrupt(tlp, close);
234
235 if (close) {
236 /* We're finished with this target */
237 kmem_free(tlp, sizeof (*tlp));
238 } else {
239 /*
240 * Deprecate the entry. There's no need for a flag to indicate
241 * this state, it just needs to be moved to the back of the list
242 * behind the underlying console device. Since the underlying
243 * device anchors the list and is never removed, this entry can
244 * never return to the front again to become the target.
245 */
246 for (lpp = &iwscn_list; (lp = *lpp) != NULL; )
247 lpp = &lp->wl_next;
248 tlp->wl_next = NULL;
249 *lpp = tlp;
250 }
edp8ec5a142006-04-28 18:39:47 -0700251 mutex_exit(&iwscn_list_lock);
252}
253
254/* Get a hold on the current target */
255static iwscn_list_t *
256srhold()
257{
258 iwscn_list_t *lp;
259
260 mutex_enter(&iwscn_list_lock);
261 ASSERT(iwscn_list != NULL);
262 lp = iwscn_list;
263 ASSERT(lp->wl_ref_cnt >= 0);
264 lp->wl_ref_cnt++;
265 mutex_exit(&iwscn_list_lock);
266
267 return (lp);
268}
269
270/* Release a hold on an entry from the redirection list */
271static void
272srrele(iwscn_list_t *lp)
273{
274 ASSERT(lp != NULL);
275 mutex_enter(&iwscn_list_lock);
276 ASSERT(lp->wl_ref_cnt > 0);
277 lp->wl_ref_cnt--;
278 cv_broadcast(&iwscn_list_cv);
279 mutex_exit(&iwscn_list_lock);
280}
281
282static int
283iwscnread(dev_t dev, uio_t *uio, cred_t *cred)
284{
285 iwscn_list_t *lp;
286 int error;
287
288 ASSERT(getminor(dev) == 0);
289
290 lp = srhold();
291 error = strread(lp->wl_vp, uio, cred);
292 srrele(lp);
293
294 return (error);
295}
296
297static int
298iwscnwrite(dev_t dev, uio_t *uio, cred_t *cred)
299{
300 iwscn_list_t *lp;
301 int error;
302
303 ASSERT(getminor(dev) == 0);
304
305 lp = srhold();
306 error = strwrite(lp->wl_vp, uio, cred);
307 srrele(lp);
308
309 return (error);
310}
311
312static int
313iwscnpoll(dev_t dev, short events, int anyyet, short *reventsp,
314 struct pollhead **phpp)
315{
316 iwscn_list_t *lp;
317 int error;
318
319 ASSERT(getminor(dev) == 0);
320
321 lp = srhold();
amwda6c28a2007-10-25 16:34:29 -0700322 error = VOP_POLL(lp->wl_vp, events, anyyet, reventsp, phpp, NULL);
edp8ec5a142006-04-28 18:39:47 -0700323 srrele(lp);
324
325 return (error);
326}
327
328static int
329iwscnioctl(dev_t dev, int cmd, intptr_t arg, int flag,
330 cred_t *cred, int *rvalp)
331{
332 iwscn_list_t *lp;
333 file_t *f;
334 char modname[FMNAMESZ + 1] = " ";
335 int error = 0;
336
337 ASSERT(getminor(dev) == 0);
338
339 switch (cmd) {
340 case SRIOCSREDIR:
341 /* Serialize all pushes of the redirection module */
342 mutex_enter(&iwscn_redirect_lock);
343
344 /*
345 * Find the vnode corresponding to the file descriptor
346 * argument and verify that it names a stream.
347 */
348 if ((f = getf((int)arg)) == NULL) {
349 mutex_exit(&iwscn_redirect_lock);
350 return (EBADF);
351 }
352 if (f->f_vnode->v_stream == NULL) {
353 releasef((int)arg);
354 mutex_exit(&iwscn_redirect_lock);
355 return (ENOSTR);
356 }
357
358 /*
359 * If the user is trying to redirect console output
360 * back to the underlying console via SRIOCSREDIR
361 * then they are evil and we'll stop them here.
362 */
363 if (str_vp(f->f_vnode) == str_vp(rwsconsvp)) {
364 releasef((int)arg);
365 mutex_exit(&iwscn_redirect_lock);
366 return (EINVAL);
367 }
368
369 /*
370 * Check if this stream already has the redirection
371 * module pushed onto it. I_LOOK returns an error
372 * if there are no modules pushed onto the stream.
373 */
374 (void) strioctl(f->f_vnode, I_LOOK, (intptr_t)modname,
375 FKIOCTL, K_TO_K, cred, rvalp);
376 if (strcmp(modname, STRREDIR_MOD) != 0) {
377
378 /*
379 * Push a new instance of the redirecting module onto
380 * the stream, so that its close routine can notify
381 * us when the overall stream is closed. (In turn,
382 * we'll then remove it from the redirection list.)
383 */
384 error = strioctl(f->f_vnode, I_PUSH,
385 (intptr_t)STRREDIR_MOD, FKIOCTL, K_TO_K,
386 cred, rvalp);
387
388 if (error != 0) {
389 releasef((int)arg);
390 mutex_exit(&iwscn_redirect_lock);
391 return (error);
392 }
393 }
394
395 /* Push it onto the redirection stack */
396 mutex_enter(&iwscn_list_lock);
397 srpush(f->f_vnode, B_FALSE);
398 mutex_exit(&iwscn_list_lock);
399
400 releasef((int)arg);
401 mutex_exit(&iwscn_redirect_lock);
402 return (0);
403
404 case SRIOCISREDIR:
405 /*
406 * Find the vnode corresponding to the file descriptor
407 * argument and verify that it names a stream.
408 */
409 if ((f = getf((int)arg)) == NULL) {
410 return (EBADF);
411 }
412 if (f->f_vnode->v_stream == NULL) {
413 releasef((int)arg);
414 return (ENOSTR);
415 }
416
417 lp = srhold();
418 *rvalp = (str_vp(f->f_vnode) == lp->wl_vp);
419 srrele(lp);
420 releasef((int)arg);
421 return (0);
422
423 case I_POP:
424 /*
425 * We need to serialize I_POP operations with
426 * SRIOCSREDIR operations so we don't accidently
427 * remove the redirection module from a stream.
428 */
429 mutex_enter(&iwscn_redirect_lock);
430 lp = srhold();
431
432 /*
433 * Here we need to protect against process that might
434 * try to pop off the redirection module from the
435 * redirected stream. Popping other modules is allowed.
436 *
437 * It's ok to hold iwscn_list_lock while doing the
438 * I_LOOK since it's such a simple operation.
439 */
440 (void) strioctl(lp->wl_vp, I_LOOK, (intptr_t)modname,
441 FKIOCTL, K_TO_K, cred, rvalp);
442
443 if (strcmp(STRREDIR_MOD, modname) == 0) {
444 srrele(lp);
445 mutex_exit(&iwscn_redirect_lock);
446 return (EINVAL);
447 }
448
449 /* Process the ioctl normally */
amwda6c28a2007-10-25 16:34:29 -0700450 error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
edp8ec5a142006-04-28 18:39:47 -0700451
452 srrele(lp);
453 mutex_exit(&iwscn_redirect_lock);
454 return (error);
455 }
456
457 /* Process the ioctl normally */
458 lp = srhold();
amwda6c28a2007-10-25 16:34:29 -0700459 error = VOP_IOCTL(lp->wl_vp, cmd, arg, flag, cred, rvalp, NULL);
edp8ec5a142006-04-28 18:39:47 -0700460 srrele(lp);
461 return (error);
462}
463
464/* ARGSUSED */
465static int
466iwscnopen(dev_t *devp, int flag, int state, cred_t *cred)
467{
468 iwscn_list_t *lp;
469 vnode_t *vp = rwsconsvp;
470
471 if (state != OTYP_CHR)
472 return (ENXIO);
473
474 if (getminor(*devp) != 0)
475 return (ENXIO);
476
477 /*
478 * You can't really open us until the console subsystem
479 * has been configured.
480 */
481 if (rwsconsvp == NULL)
482 return (ENXIO);
483
484 /*
485 * Check if this is the first open of this device or if
486 * there is currently no redirection going on. (Ie, we're
487 * sending output to underlying console device.)
488 */
489 mutex_enter(&iwscn_list_lock);
490 if ((iwscn_list == NULL) || (iwscn_list->wl_vp == str_vp(vp))) {
491 int error = 0;
492
493 /* Don't hold the list lock across an VOP_OPEN */
494 mutex_exit(&iwscn_list_lock);
495
496 /*
497 * There is currently no redirection going on.
498 * pass this open request onto the console driver
499 */
amwda6c28a2007-10-25 16:34:29 -0700500 error = VOP_OPEN(&vp, flag, cred, NULL);
edp8ec5a142006-04-28 18:39:47 -0700501 if (error != 0)
502 return (error);
503
amwda6c28a2007-10-25 16:34:29 -0700504 /* Re-acquire the list lock */
edp8ec5a142006-04-28 18:39:47 -0700505 mutex_enter(&iwscn_list_lock);
506
507 if (iwscn_list == NULL) {
508 /* Save this vnode on the redirection list */
509 srpush(vp, B_TRUE);
510 } else {
511 /*
512 * In this case there must already be a copy of
513 * this vnode on the list, so we can free up this one.
514 */
amwda6c28a2007-10-25 16:34:29 -0700515 (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
edp8ec5a142006-04-28 18:39:47 -0700516 }
517 }
518
519 /*
520 * XXX This is an ugly legacy hack that has been around
521 * forever. This code is here because this driver (the
522 * iwscn driver) is a character driver layered over a
523 * streams driver.
524 *
525 * Normally streams recieve notification whenever a process
526 * closes its last reference to that stream so that it can
527 * clean up any signal handling related configuration. (Ie,
528 * when a stream is configured to deliver a signal to a
529 * process upon certain events.) This is a feature supported
530 * by the streams framework.
531 *
532 * But character/block drivers don't recieve this type
533 * of notification. A character/block driver's close routine
534 * is only invoked upon the last close of the device. This
535 * is an artifact of the multiple open/single close driver
536 * model currently supported by solaris.
537 *
538 * So a problem occurs when a character driver layers itself
539 * on top of a streams driver. Since this driver doesn't always
540 * receive a close notification when a process closes its
541 * last reference to it, this driver can't tell the stream
542 * it's layered upon to clean up any signal handling
543 * configuration for that process.
544 *
545 * So here we hack around that by manually cleaning up the
546 * signal handling list upon each open. It doesn't guarantee
547 * that the signaling handling data stored in the stream will
548 * always be up to date, but it'll be more up to date than
549 * it would be if we didn't do this.
550 *
551 * The real way to solve this problem would be to change
552 * the device framework from an multiple open/single close
553 * model to a multiple open/multiple close model. Then
554 * character/block drivers could pass on close requests
555 * to streams layered underneath.
556 */
557 str_cn_clean(VTOS(rwsconsvp)->s_commonvp);
558 for (lp = iwscn_list; lp != NULL; lp = lp->wl_next) {
559 ASSERT(lp->wl_vp->v_stream != NULL);
560 str_cn_clean(lp->wl_vp);
561 }
562
563 mutex_exit(&iwscn_list_lock);
564 return (0);
565}
566
567/* ARGSUSED */
568static int
569iwscnclose(dev_t dev, int flag, int state, cred_t *cred)
570{
ns92644e493d0f2006-08-02 08:27:50 -0700571 iwscn_list_t *lp;
572
edp8ec5a142006-04-28 18:39:47 -0700573 ASSERT(getminor(dev) == 0);
574
575 if (state != OTYP_CHR)
576 return (ENXIO);
577
578 mutex_enter(&iwscn_list_lock);
ns92644e493d0f2006-08-02 08:27:50 -0700579 /*
580 * Remove each entry from the redirection list, terminate any
581 * current operations, wait for them to finish, then free the entry.
582 */
583 while (iwscn_list != NULL) {
584 lp = srrm(iwscn_list->wl_vp);
585 ASSERT(lp != NULL);
586 srinterrupt(lp, B_TRUE);
edp8ec5a142006-04-28 18:39:47 -0700587
ns92644e493d0f2006-08-02 08:27:50 -0700588 if (lp->wl_is_console == B_TRUE)
589 /* Close the underlying console device. */
amwda6c28a2007-10-25 16:34:29 -0700590 (void) VOP_CLOSE(lp->wl_vp, 0, 1, (offset_t)0, kcred,
591 NULL);
edp8ec5a142006-04-28 18:39:47 -0700592
ns92644e493d0f2006-08-02 08:27:50 -0700593 kmem_free(lp, sizeof (*lp));
594 }
edp8ec5a142006-04-28 18:39:47 -0700595 mutex_exit(&iwscn_list_lock);
596 return (0);
597}
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700598
599/*ARGSUSED*/
600static int
601iwscnattach(dev_info_t *devi, ddi_attach_cmd_t cmd)
602{
edp8ec5a142006-04-28 18:39:47 -0700603 /*
604 * This is a pseudo device so there will never be more than
605 * one instance attached at a time
606 */
607 ASSERT(iwscn_dip == NULL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700608
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700609 if (ddi_create_minor_node(devi, "iwscn", S_IFCHR,
610 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
edp8ec5a142006-04-28 18:39:47 -0700611 return (DDI_FAILURE);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700612 }
edp8ec5a142006-04-28 18:39:47 -0700613
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700614 iwscn_dip = devi;
edp8ec5a142006-04-28 18:39:47 -0700615 mutex_init(&iwscn_list_lock, NULL, MUTEX_DRIVER, NULL);
616 mutex_init(&iwscn_redirect_lock, NULL, MUTEX_DRIVER, NULL);
617 cv_init(&iwscn_list_cv, NULL, CV_DRIVER, NULL);
618
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700619 return (DDI_SUCCESS);
620}
621
622/* ARGSUSED */
623static int
624iwscninfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
625{
626 int error;
627
628 switch (infocmd) {
629 case DDI_INFO_DEVT2DEVINFO:
630 if (iwscn_dip == NULL) {
631 error = DDI_FAILURE;
632 } else {
633 *result = (void *)iwscn_dip;
634 error = DDI_SUCCESS;
635 }
636 break;
637 case DDI_INFO_DEVT2INSTANCE:
638 *result = (void *)0;
639 error = DDI_SUCCESS;
640 break;
641 default:
642 error = DDI_FAILURE;
643 }
644 return (error);
645}
646
edp8ec5a142006-04-28 18:39:47 -0700647struct cb_ops iwscn_cb_ops = {
648 iwscnopen, /* open */
649 iwscnclose, /* close */
650 nodev, /* strategy */
651 nodev, /* print */
652 nodev, /* dump */
653 iwscnread, /* read */
654 iwscnwrite, /* write */
655 iwscnioctl, /* ioctl */
656 nodev, /* devmap */
657 nodev, /* mmap */
658 nodev, /* segmap */
659 iwscnpoll, /* poll */
660 ddi_prop_op, /* cb_prop_op */
661 NULL, /* streamtab */
662 D_MP /* Driver compatibility flag */
663};
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700664
edp8ec5a142006-04-28 18:39:47 -0700665struct dev_ops iwscn_ops = {
666 DEVO_REV, /* devo_rev, */
667 0, /* refcnt */
668 iwscninfo, /* info */
669 nulldev, /* identify */
670 nulldev, /* probe */
671 iwscnattach, /* attach */
672 nodev, /* detach */
673 nodev, /* reset */
674 &iwscn_cb_ops, /* driver operations */
Sherry Moore19397402008-09-22 16:30:26 -0700675 NULL, /* bus operations */
676 NULL, /* power */
677 ddi_quiesce_not_needed, /* quiesce */
edp8ec5a142006-04-28 18:39:47 -0700678};
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700679
680/*
edp8ec5a142006-04-28 18:39:47 -0700681 * Module linkage information for the kernel.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700682 */
edp8ec5a142006-04-28 18:39:47 -0700683static struct modldrv modldrv = {
684 &mod_driverops, /* Type of module. This one is a pseudo driver */
Sherry Moore19397402008-09-22 16:30:26 -0700685 "Workstation Redirection driver",
edp8ec5a142006-04-28 18:39:47 -0700686 &iwscn_ops, /* driver ops */
687};
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700688
edp8ec5a142006-04-28 18:39:47 -0700689static struct modlinkage modlinkage = {
690 MODREV_1,
691 &modldrv,
692 NULL
693};
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700694
edp8ec5a142006-04-28 18:39:47 -0700695int
696_init(void)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700697{
edp8ec5a142006-04-28 18:39:47 -0700698 return (mod_install(&modlinkage));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700699}
700
edp8ec5a142006-04-28 18:39:47 -0700701int
702_fini(void)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700703{
edp8ec5a142006-04-28 18:39:47 -0700704 return (EBUSY);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700705}
706
edp8ec5a142006-04-28 18:39:47 -0700707int
708_info(struct modinfo *modinfop)
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700709{
edp8ec5a142006-04-28 18:39:47 -0700710 return (mod_info(&modlinkage, modinfop));
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700711}