Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/cons.c
+++ new/usr/src/uts/common/io/cons.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Indirect console driver for Sun.
28 28 *
29 29 * Redirects all I/O to the device designated as the underlying "hardware"
30 30 * console, as given by the value of rconsvp. The implementation assumes that
31 31 * rconsvp denotes a STREAMS device; the assumption is justified since
32 32 * consoles must be capable of effecting tty semantics.
33 33 *
34 34 * rconsvp is set in autoconf.c:consconfig(), based on information obtained
35 35 * from the EEPROM.
36 36 *
37 37 * XXX: The driver still needs to be converted to use ANSI C consistently
38 38 * throughout.
39 39 */
40 40
41 41 #include <sys/types.h>
42 42 #include <sys/open.h>
43 43 #include <sys/param.h>
44 44 #include <sys/systm.h>
45 45 #include <sys/signal.h>
46 46 #include <sys/cred.h>
47 47 #include <sys/user.h>
48 48 #include <sys/proc.h>
49 49 #include <sys/disp.h>
50 50 #include <sys/file.h>
51 51 #include <sys/taskq.h>
52 52 #include <sys/log.h>
53 53 #include <sys/vnode.h>
54 54 #include <sys/uio.h>
55 55 #include <sys/stat.h>
56 56
57 57 #include <sys/console.h>
58 58 #include <sys/consdev.h>
59 59
60 60 #include <sys/stream.h>
61 61 #include <sys/strsubr.h>
62 62 #include <sys/poll.h>
63 63
64 64 #include <sys/debug.h>
65 65
66 66 #include <sys/conf.h>
67 67 #include <sys/ddi.h>
68 68 #include <sys/sunddi.h>
69 69 #include <sys/vt.h>
70 70
71 71 static int cnopen(dev_t *, int, int, struct cred *);
72 72 static int cnclose(dev_t, int, int, struct cred *);
73 73 static int cnread(dev_t, struct uio *, struct cred *);
74 74 static int cnwrite(dev_t, struct uio *, struct cred *);
75 75 static int cnioctl(dev_t, int, intptr_t, int, struct cred *, int *);
76 76 static int cnpoll(dev_t, short, int, short *, struct pollhead **);
77 77 static int cn_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
78 78 static int cn_attach(dev_info_t *, ddi_attach_cmd_t);
79 79 static int cn_detach(dev_info_t *, ddi_detach_cmd_t);
80 80
81 81 static dev_info_t *cn_dip; /* private copy of devinfo pointer */
82 82
83 83 static struct cb_ops cn_cb_ops = {
84 84
85 85 cnopen, /* open */
86 86 cnclose, /* close */
87 87 nodev, /* strategy */
88 88 nodev, /* print */
89 89 nodev, /* dump */
90 90 cnread, /* read */
91 91 cnwrite, /* write */
92 92 cnioctl, /* ioctl */
93 93 nodev, /* devmap */
94 94 nodev, /* mmap */
95 95 nodev, /* segmap */
96 96 cnpoll, /* poll */
97 97 ddi_prop_op, /* cb_prop_op */
98 98 0, /* streamtab */
99 99 D_NEW | D_MP /* Driver compatibility flag */
100 100
101 101 };
102 102
103 103 static struct dev_ops cn_ops = {
104 104
105 105 DEVO_REV, /* devo_rev, */
106 106 0, /* refcnt */
107 107 cn_info, /* info */
108 108 nulldev, /* identify */
109 109 nulldev, /* probe */
110 110 cn_attach, /* attach */
111 111 cn_detach, /* detach */
112 112 nodev, /* reset */
113 113 &cn_cb_ops, /* driver operations */
114 114 (struct bus_ops *)0, /* bus operations */
115 115 NULL, /* power */
116 116 ddi_quiesce_not_needed, /* quiesce */
117 117
118 118 };
119 119
120 120 /*
121 121 * Global variables associated with the console device:
122 122 *
123 123 * XXX: There are too many of these!
124 124 * moved to space.c to become resident in the kernel so that cons
125 125 * can be loadable.
126 126 */
127 127
128 128 extern dev_t rconsdev; /* "hardware" console */
129 129 extern vnode_t *rconsvp; /* pointer to vnode for that device */
130 130
131 131 /*
132 132 * XXX: consulted in prsubr.c, for /proc entry point for obtaining ps info.
133 133 */
134 134 extern dev_t uconsdev; /* What the user thinks is the console device */
135 135
136 136 /*
137 137 * Private driver state:
138 138 */
139 139
140 140 /*
141 141 * The underlying console device potentially can be opened through (at least)
142 142 * two paths: through this driver and through the underlying device's driver.
143 143 * To ensure that reference counts are meaningful and therefore that close
144 144 * routines are called at the right time, it's important to make sure that
145 145 * rconsvp's s_count field (i.e., the count on the underlying device) never
146 146 * has a contribution of more than one through this driver, regardless of how
147 147 * many times this driver's been opened. rconsopen keeps track of the
148 148 * necessary information to ensure this property.
149 149 */
150 150 static uint_t rconsopen;
151 151
152 152
153 153 #include <sys/types.h>
154 154 #include <sys/conf.h>
155 155 #include <sys/param.h>
156 156 #include <sys/systm.h>
157 157 #include <sys/errno.h>
158 158 #include <sys/modctl.h>
159 159
160 160
161 161 extern int nodev(), nulldev();
162 162 extern int dseekneg_flag;
163 163 extern struct mod_ops mod_driverops;
164 164 extern struct dev_ops cn_ops;
165 165
166 166 /*
167 167 * Module linkage information for the kernel.
↓ open down ↓ |
167 lines elided |
↑ open up ↑ |
168 168 */
169 169
170 170 static struct modldrv modldrv = {
171 171 &mod_driverops, /* Type of module. This one is a pseudo driver */
172 172 "Console redirection driver",
173 173 &cn_ops, /* driver ops */
174 174 };
175 175
176 176 static struct modlinkage modlinkage = {
177 177 MODREV_1,
178 - &modldrv,
179 - NULL
178 + { &modldrv, NULL }
180 179 };
181 180
182 181 int
183 182 _init(void)
184 183 {
185 184 return (mod_install(&modlinkage));
186 185 }
187 186
188 187 int
189 188 _fini(void)
190 189 {
191 190 return (EBUSY);
192 191 }
193 192
194 193 int
195 194 _info(struct modinfo *modinfop)
196 195 {
197 196 return (mod_info(&modlinkage, modinfop));
198 197 }
199 198
200 199 /*
201 200 * DDI glue routines
202 201 */
203 202 static int
204 203 cn_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
205 204 {
206 205 if (cmd != DDI_ATTACH)
207 206 return (DDI_FAILURE);
208 207
209 208 if (ddi_create_minor_node(devi, "syscon", S_IFCHR,
210 209 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
211 210 return (DDI_FAILURE);
212 211 }
213 212 if (ddi_create_minor_node(devi, "systty", S_IFCHR,
214 213 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
215 214 ddi_remove_minor_node(devi, NULL);
216 215 return (DDI_FAILURE);
217 216 }
218 217 if (ddi_create_minor_node(devi, "console", S_IFCHR,
219 218 0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
220 219 ddi_remove_minor_node(devi, NULL);
221 220 return (DDI_FAILURE);
222 221 }
223 222
224 223 cn_dip = devi;
225 224 return (DDI_SUCCESS);
226 225 }
227 226
228 227 static int
229 228 cn_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
230 229 {
231 230 if (cmd != DDI_DETACH)
232 231 return (DDI_FAILURE);
233 232 ddi_remove_minor_node(devi, NULL);
234 233 uconsdev = NODEV;
235 234 return (DDI_SUCCESS);
236 235 }
237 236
238 237 /* ARGSUSED */
239 238 static int
240 239 cn_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
241 240 {
242 241 int error = DDI_FAILURE;
243 242
244 243 switch (infocmd) {
245 244 case DDI_INFO_DEVT2DEVINFO:
246 245 if (getminor((dev_t)arg) == 0 && cn_dip != NULL) {
247 246 *result = (void *) cn_dip;
248 247 error = DDI_SUCCESS;
249 248 }
250 249 break;
251 250
252 251 case DDI_INFO_DEVT2INSTANCE:
253 252 if (getminor((dev_t)arg) == 0) {
254 253 *result = (void *)0;
255 254 error = DDI_SUCCESS;
256 255 }
257 256 break;
258 257
259 258 default:
260 259 break;
261 260 }
262 261
263 262 return (error);
264 263 }
265 264
266 265 /*
267 266 * XXX Caution: before allowing more than 256 minor devices on the
268 267 * console, make sure you understand the 'compatibility' hack
269 268 * in ufs_iget() that translates old dev_t's to new dev_t's.
270 269 * See bugid 1098104 for the sordid details.
271 270 */
272 271
273 272 /* ARGSUSED */
274 273 static int
275 274 cnopen(dev_t *dev, int flag, int state, struct cred *cred)
276 275 {
277 276 int err;
278 277 static int been_here;
279 278 vnode_t *vp = rconsvp;
280 279
281 280 ASSERT(cred != NULL);
282 281
283 282 if (rconsvp == NULL)
284 283 return (0);
285 284
286 285 /*
287 286 * Enable virtual console I/O for console logging if needed.
288 287 */
289 288 if (vsconsvp != NULL && vsconsvp->v_stream == NULL) {
290 289 if (VOP_OPEN(&vsconsvp, FREAD | FWRITE, cred, NULL) != 0) {
291 290 cmn_err(CE_WARN, "cnopen: failed to open vsconsvp "
292 291 "for virtual console logging");
293 292 }
294 293 }
295 294
296 295 /*
297 296 * XXX: Clean up inactive PIDs from previous opens if any.
298 297 * These would have been created as a result of an I_SETSIG
299 298 * issued against console. This is a workaround, and
300 299 * console driver must be correctly redesigned not to need
301 300 * this hook.
302 301 */
303 302 if (vp->v_stream) {
304 303 str_cn_clean(vp);
305 304 }
306 305
307 306 /*
308 307 * XXX: Set hook to tell /proc about underlying console. (There's
309 308 * gotta be a better way...)
310 309 */
311 310 if (state != OTYP_CHR || getminor(*dev) != 0)
312 311 return (ENXIO);
313 312 if (been_here == 0) {
314 313 uconsdev = *dev;
315 314 been_here = 1;
316 315 if (vn_open("/dev/console", UIO_SYSSPACE, FWRITE | FNOCTTY,
317 316 0, &console_vnode, 0, 0) == 0)
318 317 console_taskq = taskq_create("console_taskq",
319 318 1, maxclsyspri - 1, LOG_LOWAT / LOG_MSGSIZE,
320 319 LOG_HIWAT / LOG_MSGSIZE, TASKQ_PREPOPULATE);
321 320 }
322 321
323 322 if ((err = VOP_OPEN(&vp, flag, cred, NULL)) != 0)
324 323 return (err);
325 324
326 325 /*
327 326 * The underlying driver is not allowed to have cloned itself
328 327 * for this open.
329 328 */
330 329 if (vp != rconsvp) {
331 330 /*
332 331 * It might happen that someone set rconsvp to NULL
333 332 * whilst we were in the middle of the open.
334 333 */
335 334 if (rconsvp == NULL) {
336 335 (void) VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
337 336 return (0);
338 337 }
339 338 cmn_err(CE_PANIC, "cnopen: cloned open");
340 339 }
341 340
342 341 rconsopen++;
343 342
344 343 return (0);
345 344 }
346 345
347 346 /* ARGSUSED */
348 347 static int
349 348 cnclose(dev_t dev, int flag, int state, struct cred *cred)
350 349 {
351 350 int err = 0;
352 351 vnode_t *vp;
353 352
354 353 /*
355 354 * Since this is the _last_ close, it's our last chance to close the
356 355 * underlying device. (Note that if someone else has the underlying
357 356 * hardware console device open, we won't get here, since spec_close
358 357 * will see s_count > 1.)
359 358 */
360 359 if (state != OTYP_CHR)
361 360 return (ENXIO);
362 361
363 362 if (rconsvp == NULL)
364 363 return (0);
365 364
366 365 while ((rconsopen != 0) && ((vp = rconsvp) != NULL)) {
367 366 err = VOP_CLOSE(vp, flag, 1, (offset_t)0, cred, NULL);
368 367 if (!err) {
369 368 rconsopen--;
370 369 }
371 370 }
372 371 return (err);
373 372 }
374 373
375 374 /* ARGSUSED */
376 375 static int
377 376 cnread(dev_t dev, struct uio *uio, struct cred *cred)
378 377 {
379 378 kcondvar_t sleep_forever;
380 379 kmutex_t sleep_forever_mutex;
381 380
382 381 if (rconsvp == NULL) {
383 382 /*
384 383 * Go to sleep forever. This seems like the least
385 384 * harmful thing to do if there's no console.
386 385 * EOF might be better if we're ending up single-user
387 386 * mode.
388 387 */
389 388 cv_init(&sleep_forever, NULL, CV_DRIVER, NULL);
390 389 mutex_init(&sleep_forever_mutex, NULL, MUTEX_DRIVER, NULL);
391 390 mutex_enter(&sleep_forever_mutex);
392 391 (void) cv_wait_sig(&sleep_forever, &sleep_forever_mutex);
393 392 mutex_exit(&sleep_forever_mutex);
394 393 return (EIO);
395 394 }
396 395
397 396 if (rconsvp->v_stream != NULL)
398 397 return (strread(rconsvp, uio, cred));
399 398 else
400 399 return (cdev_read(rconsdev, uio, cred));
401 400 }
402 401
403 402 /* ARGSUSED */
404 403 static int
405 404 cnwrite(dev_t dev, struct uio *uio, struct cred *cred)
406 405 {
407 406 if (rconsvp == NULL) {
408 407 uio->uio_resid = 0;
409 408 return (0);
410 409 }
411 410
412 411 /*
413 412 * Output to virtual console for logging if enabled.
414 413 */
415 414 if (vsconsvp != NULL && vsconsvp->v_stream != NULL) {
416 415 struiod_t uiod;
417 416
418 417 /*
419 418 * strwrite modifies uio so need to make copy.
420 419 */
421 420 (void) uiodup(uio, &uiod.d_uio, uiod.d_iov,
422 421 sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
423 422
424 423 (void) strwrite(vsconsvp, &uiod.d_uio, cred);
425 424 }
426 425
427 426 if (rconsvp->v_stream != NULL)
428 427 return (strwrite(rconsvp, uio, cred));
429 428 else
430 429 return (cdev_write(rconsdev, uio, cred));
431 430 }
432 431
433 432 /* ARGSUSED */
434 433 static int
435 434 cnprivateioc(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
436 435 int *rvalp)
437 436 {
438 437
439 438 /* currently we only support one ioctl */
440 439 if (cmd != CONS_GETTERM)
441 440 return (EINVAL);
442 441
443 442 /* Confirm iwscn is immediate target of cn redirection */
444 443 if (rconsvp != wsconsvp)
445 444 return (ENODEV);
446 445
447 446 /*
448 447 * If the redirection client is not wc, it should return
449 448 * error upon receiving the CONS_GETTERM ioctl.
450 449 *
451 450 * if it is wc, we know that the target supports the CONS_GETTERM
452 451 * ioctl, which very conviently has the exact same data
453 452 * format as this ioctl... so let's just pass it on.
454 453 */
455 454 return (cdev_ioctl(rconsdev, CONS_GETTERM, arg, flag, cred, rvalp));
456 455 }
457 456
458 457 /* ARGSUSED */
459 458 static int
460 459 cnioctl(dev_t dev, int cmd, intptr_t arg, int flag, struct cred *cred,
461 460 int *rvalp)
462 461 {
463 462 if (rconsvp == NULL)
464 463 return (0);
465 464
466 465 /*
467 466 * In wc, VT_SET_CONSUSER which comes from minor node 0
468 467 * has two sources -- either /dev/console or /dev/vt/0 .
469 468 * We need a way to differentiate them, so here we
470 469 * change VT_SET_CONSUSER to a private VT_RESET_CONSUSER
471 470 * ioctl.
472 471 */
473 472 if (cmd == VT_SET_CONSUSER)
474 473 cmd = VT_RESET_CONSUSER;
475 474
476 475 if ((cmd & _CNIOC_MASK) == _CNIOC)
477 476 return (cnprivateioc(dev, cmd, arg, flag, cred, rvalp));
478 477
479 478 if (rconsvp->v_stream != NULL)
480 479 return (strioctl(rconsvp, cmd, arg, flag, U_TO_K,
481 480 cred, rvalp));
482 481
483 482 return (cdev_ioctl(rconsdev, cmd, arg, flag, cred, rvalp));
484 483 }
485 484
486 485 /* ARGSUSED */
487 486 static int
488 487 cnpoll(dev_t dev, short events, int anyyet, short *reventsp,
489 488 struct pollhead **phpp)
490 489 {
491 490 if (rconsvp == NULL)
492 491 return (nochpoll(dev, events, anyyet, reventsp, phpp));
493 492
494 493 if (rconsvp->v_stream != NULL)
495 494 return (strpoll(rconsvp->v_stream, events, anyyet, reventsp,
496 495 phpp));
497 496 else
498 497 return (cdev_poll(rconsdev, events, anyyet, reventsp, phpp));
499 498 }
↓ open down ↓ |
310 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX