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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * srn Provide apm-like interfaces to Xorg 30 */ 31 32 #include <sys/types.h> 33 #include <sys/errno.h> 34 #include <sys/modctl.h> 35 #include <sys/conf.h> /* driver flags and functions */ 36 #include <sys/open.h> /* OTYP_CHR definition */ 37 #include <sys/stat.h> /* S_IFCHR definition */ 38 #include <sys/pathname.h> /* name -> dev_info xlation */ 39 #include <sys/kmem.h> /* memory alloc stuff */ 40 #include <sys/debug.h> 41 #include <sys/pm.h> 42 #include <sys/ddi.h> 43 #include <sys/sunddi.h> 44 #include <sys/epm.h> 45 #include <sys/vfs.h> 46 #include <sys/mode.h> 47 #include <sys/mkdev.h> 48 #include <sys/promif.h> 49 #include <sys/consdev.h> 50 #include <sys/ddi_impldefs.h> 51 #include <sys/poll.h> 52 #include <sys/note.h> 53 #include <sys/taskq.h> 54 #include <sys/policy.h> 55 #include <sys/srn.h> 56 57 /* 58 * Minor number is instance<<8 + clone minor from range 1-255; 59 * But only one will be allocated 60 */ 61 #define SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1)) 62 #define SU 0x002 63 #define SG 0x004 64 65 extern kmutex_t srn_clone_lock; /* protects srn_clones array */ 66 extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 67 extern uint_t srn_poll_cnt[SRN_MAX_CLONE]; 68 69 /* 70 * The soft state of the srn driver. Since there will only be 71 * one of these, just reference it through a static struct. 72 */ 73 static struct srnstate { 74 dev_info_t *srn_dip; /* ptr to our dev_info node */ 75 int srn_instance; /* for ddi_get_instance() */ 76 uchar_t srn_clones[SRN_MAX_CLONE]; /* unique opens */ 77 struct cred *srn_cred[SRN_MAX_CLONE]; /* cred for each open */ 78 int srn_type[SRN_MAX_CLONE]; /* type of handshake */ 79 int srn_delivered[SRN_MAX_CLONE]; 80 srn_event_info_t srn_pending[SRN_MAX_CLONE]; 81 int srn_fault[SRN_MAX_CLONE]; 82 } srn = { NULL, -1}; 83 typedef struct srnstate *srn_state_t; 84 85 kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 86 uint_t srn_poll_cnt[SRN_MAX_CLONE]; /* count of events for poll */ 87 int srn_apm_count; 88 int srn_autosx_count; 89 /* Number of seconds to wait for clients to ack a poll */ 90 int srn_timeout = 10; 91 92 struct pollhead srn_pollhead[SRN_MAX_CLONE]; 93 94 static int srn_open(dev_t *, int, int, cred_t *); 95 static int srn_close(dev_t, int, int, cred_t *); 96 static int srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 97 static int srn_chpoll(dev_t, short, int, short *, struct pollhead **); 98 99 static struct cb_ops srn_cb_ops = { 100 srn_open, /* open */ 101 srn_close, /* close */ 102 nodev, /* strategy */ 103 nodev, /* print */ 104 nodev, /* dump */ 105 nodev, /* read */ 106 nodev, /* write */ 107 srn_ioctl, /* ioctl */ 108 nodev, /* devmap */ 109 nodev, /* mmap */ 110 nodev, /* segmap */ 111 srn_chpoll, /* poll */ 112 ddi_prop_op, /* prop_op */ 113 NULL, /* streamtab */ 114 D_NEW | D_MP /* driver compatibility flag */ 115 }; 116 117 static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 118 void **result); 119 static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 120 static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 121 static void srn_notify(int type, int event); 122 123 static struct dev_ops srn_ops = { 124 DEVO_REV, /* devo_rev */ 125 0, /* refcnt */ 126 srn_getinfo, /* info */ 127 nulldev, /* identify */ 128 nulldev, /* probe */ 129 srn_attach, /* attach */ 130 srn_detach, /* detach */ 131 nodev, /* reset */ 132 &srn_cb_ops, /* driver operations */ 133 NULL, /* bus operations */ 134 NULL, /* power */ 135 ddi_quiesce_not_needed, /* quiesce */ 136 }; 137 138 static struct modldrv modldrv = { 139 &mod_driverops, 140 "srn driver", 141 &srn_ops 142 }; 143 144 static struct modlinkage modlinkage = { 145 MODREV_1, { &modldrv, NULL } 146 }; 147 148 /* Local functions */ 149 150 int 151 _init(void) 152 { 153 return (mod_install(&modlinkage)); 154 } 155 156 int 157 _fini(void) 158 { 159 return (mod_remove(&modlinkage)); 160 } 161 162 int 163 _info(struct modinfo *modinfop) 164 { 165 return (mod_info(&modlinkage, modinfop)); 166 } 167 168 static int 169 srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 170 { 171 int i; 172 extern void (*srn_signal)(int, int); 173 174 switch (cmd) { 175 176 case DDI_ATTACH: 177 if (srn.srn_instance != -1) /* Only allow one instance */ 178 return (DDI_FAILURE); 179 srn.srn_instance = ddi_get_instance(dip); 180 if (ddi_create_minor_node(dip, "srn", S_IFCHR, 181 (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0) 182 != DDI_SUCCESS) { 183 return (DDI_FAILURE); 184 } 185 srn.srn_dip = dip; /* srn_init and getinfo depend on it */ 186 187 for (i = 0; i < SRN_MAX_CLONE; i++) 188 cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL); 189 190 srn.srn_instance = ddi_get_instance(dip); 191 mutex_enter(&srn_clone_lock); 192 srn_signal = srn_notify; 193 mutex_exit(&srn_clone_lock); 194 ddi_report_dev(dip); 195 return (DDI_SUCCESS); 196 197 default: 198 return (DDI_FAILURE); 199 } 200 } 201 202 /* ARGSUSED */ 203 static int 204 srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 205 { 206 int i; 207 extern int srn_inuse; 208 extern void (*srn_signal)(int, int); 209 210 switch (cmd) { 211 case DDI_DETACH: 212 213 mutex_enter(&srn_clone_lock); 214 while (srn_inuse) { 215 mutex_exit(&srn_clone_lock); 216 delay(1); 217 mutex_enter(&srn_clone_lock); 218 } 219 srn_signal = NULL; 220 mutex_exit(&srn_clone_lock); 221 222 for (i = 0; i < SRN_MAX_CLONE; i++) 223 cv_destroy(&srn_clones_cv[i]); 224 225 ddi_remove_minor_node(dip, NULL); 226 srn.srn_instance = -1; 227 return (DDI_SUCCESS); 228 229 default: 230 return (DDI_FAILURE); 231 } 232 } 233 234 235 #ifdef DEBUG 236 char *srn_cmd_string; 237 int srn_cmd; 238 #endif 239 240 /* 241 * Returns true if permission granted by credentials 242 * XXX 243 */ 244 static int 245 srn_perms(int perm, cred_t *cr) 246 { 247 if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ 248 return (1); 249 if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */ 250 return (1); 251 return (0); 252 } 253 254 static int 255 srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 256 struct pollhead **phpp) 257 { 258 extern struct pollhead srn_pollhead[]; 259 int clone; 260 261 clone = SRN_MINOR_TO_CLONE(getminor(dev)); 262 if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) { 263 *reventsp |= (POLLIN | POLLRDNORM); 264 } else { 265 *reventsp = 0; 266 if (!anyyet) { 267 *phpp = &srn_pollhead[clone]; 268 } 269 } 270 return (0); 271 } 272 273 /*ARGSUSED*/ 274 static int 275 srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 276 { 277 dev_t dev; 278 int instance; 279 280 switch (infocmd) { 281 case DDI_INFO_DEVT2DEVINFO: 282 if (srn.srn_instance == -1) 283 return (DDI_FAILURE); 284 *result = srn.srn_dip; 285 return (DDI_SUCCESS); 286 287 case DDI_INFO_DEVT2INSTANCE: 288 dev = (dev_t)arg; 289 instance = getminor(dev) >> 8; 290 *result = (void *)(uintptr_t)instance; 291 return (DDI_SUCCESS); 292 293 default: 294 return (DDI_FAILURE); 295 } 296 } 297 298 299 /*ARGSUSED1*/ 300 static int 301 srn_open(dev_t *devp, int flag, int otyp, cred_t *cr) 302 { 303 int clone; 304 305 if (otyp != OTYP_CHR) 306 return (EINVAL); 307 308 mutex_enter(&srn_clone_lock); 309 for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++) 310 if (!srn.srn_clones[clone]) 311 break; 312 313 if (clone == SRN_MAX_CLONE) { 314 mutex_exit(&srn_clone_lock); 315 return (ENXIO); 316 } 317 srn.srn_cred[clone] = cr; 318 ASSERT(srn_apm_count >= 0); 319 srn_apm_count++; 320 srn.srn_type[clone] = SRN_TYPE_APM; 321 crhold(cr); 322 323 *devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) + 324 clone); 325 srn.srn_clones[clone] = 1; 326 srn.srn_cred[clone] = cr; 327 crhold(cr); 328 mutex_exit(&srn_clone_lock); 329 PMD(PMD_SX, ("srn open OK\n")) 330 return (0); 331 } 332 333 /*ARGSUSED1*/ 334 static int 335 srn_close(dev_t dev, int flag, int otyp, cred_t *cr) 336 { 337 int clone; 338 339 if (otyp != OTYP_CHR) 340 return (EINVAL); 341 342 clone = SRN_MINOR_TO_CLONE(getminor(dev)); 343 PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev), 344 clone)) 345 mutex_enter(&srn_clone_lock); 346 crfree(srn.srn_cred[clone]); 347 srn.srn_cred[clone] = 0; 348 srn_poll_cnt[clone] = 0; 349 srn.srn_fault[clone] = 0; 350 if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) { 351 srn.srn_pending[clone].ae_type = 0; 352 srn.srn_delivered[clone] = 0; 353 cv_signal(&srn_clones_cv[clone]); 354 } 355 switch (srn.srn_type[clone]) { 356 case SRN_TYPE_AUTOSX: 357 ASSERT(srn_autosx_count); 358 srn_autosx_count--; 359 break; 360 case SRN_TYPE_APM: 361 ASSERT(srn_apm_count); 362 srn_apm_count--; 363 break; 364 default: 365 ASSERT(0); 366 return (EINVAL); 367 } 368 srn.srn_clones[clone] = 0; 369 mutex_exit(&srn_clone_lock); 370 return (0); 371 } 372 373 /*ARGSUSED*/ 374 static int 375 srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) 376 { 377 int clone = SRN_MINOR_TO_CLONE(getminor(dev)); 378 379 PMD(PMD_SX, ("ioctl: %x: begin\n", cmd)) 380 381 switch (cmd) { 382 case SRN_IOC_NEXTEVENT: 383 case SRN_IOC_SUSPEND: 384 case SRN_IOC_RESUME: 385 case SRN_IOC_AUTOSX: 386 break; 387 default: 388 return (ENOTTY); 389 } 390 391 if (!srn_perms(SU | SG, srn.srn_cred[clone])) { 392 return (EPERM); 393 } 394 switch (cmd) { 395 case SRN_IOC_AUTOSX: 396 PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n")) 397 mutex_enter(&srn_clone_lock); 398 if (!srn.srn_clones[clone]) { 399 PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n")) 400 mutex_exit(&srn_clone_lock); 401 return (EINVAL); 402 } 403 if (srn.srn_pending[clone].ae_type) { 404 PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n")) 405 mutex_exit(&srn_clone_lock); 406 return (EBUSY); 407 } 408 if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) { 409 PMD(PMD_SX, ("AUTOSX already--EBUSY\n")) 410 mutex_exit(&srn_clone_lock); 411 return (EBUSY); 412 } 413 ASSERT(srn.srn_type[clone] == SRN_TYPE_APM); 414 srn.srn_type[clone] = SRN_TYPE_AUTOSX; 415 srn.srn_fault[clone] = 0; 416 srn_apm_count--; 417 ASSERT(srn_apm_count >= 0); 418 ASSERT(srn_autosx_count >= 0); 419 srn_autosx_count++; 420 mutex_exit(&srn_clone_lock); 421 PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n")) 422 return (0); 423 424 case SRN_IOC_NEXTEVENT: 425 /* 426 * return the next suspend or resume event; there should 427 * be one, cause we only get called if we've signalled a 428 * poll data completion 429 * then wake up the kernel thread sleeping for the delivery 430 */ 431 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n")) 432 if (srn.srn_fault[clone]) { 433 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d fault " 434 "cleared\n", clone)) 435 srn.srn_fault[clone] = 0; 436 } 437 mutex_enter(&srn_clone_lock); 438 if (srn_poll_cnt[clone] == 0) { 439 mutex_exit(&srn_clone_lock); 440 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d " 441 "EWOULDBLOCK\n", clone)) 442 return (EWOULDBLOCK); 443 } 444 ASSERT(srn.srn_pending[clone].ae_type); 445 if (ddi_copyout(&srn.srn_pending[clone], (void *)arg, 446 sizeof (srn_event_info_t), mode) != 0) { 447 mutex_exit(&srn_clone_lock); 448 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n", 449 clone)) 450 return (EFAULT); 451 } 452 if (srn.srn_type[clone] == SRN_TYPE_APM) 453 srn.srn_delivered[clone] = 454 srn.srn_pending[clone].ae_type; 455 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n", 456 clone, srn.srn_pending[clone].ae_type)) 457 srn_poll_cnt[clone] = 0; 458 mutex_exit(&srn_clone_lock); 459 return (0); 460 461 case SRN_IOC_SUSPEND: 462 /* ack suspend */ 463 PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone)) 464 if (srn.srn_fault[clone]) { 465 PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d fault " 466 "cleared\n", clone)) 467 srn.srn_fault[clone] = 0; 468 } 469 mutex_enter(&srn_clone_lock); 470 if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) { 471 mutex_exit(&srn_clone_lock); 472 PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n")) 473 return (EINVAL); 474 } 475 srn.srn_delivered[clone] = 0; 476 srn.srn_pending[clone].ae_type = 0; 477 /* notify the kernel suspend thread to continue */ 478 PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone)) 479 cv_signal(&srn_clones_cv[clone]); 480 mutex_exit(&srn_clone_lock); 481 return (0); 482 483 case SRN_IOC_RESUME: 484 /* ack resume */ 485 PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone)) 486 if (srn.srn_fault[clone]) { 487 PMD(PMD_SX, ("SRN_IOC_RESUME clone %d fault " 488 "cleared\n", clone)) 489 srn.srn_fault[clone] = 0; 490 } 491 mutex_enter(&srn_clone_lock); 492 if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) { 493 mutex_exit(&srn_clone_lock); 494 PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n")) 495 return (EINVAL); 496 } 497 srn.srn_delivered[clone] = 0; 498 srn.srn_pending[clone].ae_type = 0; 499 /* notify the kernel resume thread to continue */ 500 PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone)) 501 cv_signal(&srn_clones_cv[clone]); 502 mutex_exit(&srn_clone_lock); 503 return (0); 504 505 default: 506 PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n")) 507 return (EINVAL); 508 } 509 } 510 /* 511 * A very simple handshake with the srn driver, 512 * only one outstanding event at a time. 513 * The OS delivers the event and depending on type, 514 * either blocks waiting for the ack, or drives on 515 */ 516 void 517 srn_notify(int type, int event) 518 { 519 int clone, count; 520 PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n", 521 type, event)); 522 ASSERT(mutex_owned(&srn_clone_lock)); 523 switch (type) { 524 case SRN_TYPE_APM: 525 if (srn_apm_count == 0) { 526 PMD(PMD_SX, ("no apm types\n")) 527 return; 528 } 529 count = srn_apm_count; 530 break; 531 case SRN_TYPE_AUTOSX: 532 if (srn_autosx_count == 0) { 533 PMD(PMD_SX, ("no autosx types\n")) 534 return; 535 } 536 count = srn_autosx_count; 537 break; 538 default: 539 ASSERT(0); 540 break; 541 } 542 ASSERT(count > 0); 543 PMD(PMD_SX, ("count %d\n", count)) 544 for (clone = 0; clone < SRN_MAX_CLONE; clone++) { 545 if (srn.srn_type[clone] == type) { 546 #ifdef DEBUG 547 if (type == SRN_TYPE_APM && !srn.srn_fault[clone]) { 548 ASSERT(srn.srn_pending[clone].ae_type == 0); 549 ASSERT(srn_poll_cnt[clone] == 0); 550 ASSERT(srn.srn_delivered[clone] == 0); 551 } 552 #endif 553 srn.srn_pending[clone].ae_type = event; 554 srn_poll_cnt[clone] = 1; 555 PMD(PMD_SX, ("pollwake %d\n", clone)) 556 pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN)); 557 count--; 558 if (count == 0) 559 break; 560 } 561 } 562 if (type == SRN_TYPE_AUTOSX) { /* we don't wait */ 563 PMD(PMD_SX, ("Not waiting for AUTOSX ack\n")) 564 return; 565 } 566 ASSERT(type == SRN_TYPE_APM); 567 /* otherwise wait for acks */ 568 restart: 569 /* 570 * We wait until all of the pending events are cleared. 571 * We have to start over every time we do a cv_wait because 572 * we give up the mutex and can be re-entered 573 */ 574 for (clone = 1; clone < SRN_MAX_CLONE; clone++) { 575 if (srn.srn_clones[clone] == 0 || 576 srn.srn_type[clone] != SRN_TYPE_APM) 577 continue; 578 if (srn.srn_pending[clone].ae_type && !srn.srn_fault[clone]) { 579 PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, " 580 "event %x\n", clone, event)) 581 if (cv_timedwait(&srn_clones_cv[clone], 582 &srn_clone_lock, ddi_get_lbolt() + 583 drv_usectohz(srn_timeout * 1000000)) == -1) { 584 /* 585 * Client didn't respond, mark it as faulted 586 * and continue as if a regular signal. 587 */ 588 PMD(PMD_SX, ("srn_notify: clone %d did not " 589 "ack event %x\n", clone, event)) 590 cmn_err(CE_WARN, "srn_notify: clone %d did " 591 "not ack event %x\n", clone, event); 592 srn.srn_fault[clone] = 1; 593 } 594 goto restart; 595 } 596 } 597 PMD(PMD_SX, ("srn_notify done with %x\n", event)) 598 }