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