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