12df1fe9cSrandyf /* 22df1fe9cSrandyf * CDDL HEADER START 32df1fe9cSrandyf * 42df1fe9cSrandyf * The contents of this file are subject to the terms of the 52df1fe9cSrandyf * Common Development and Distribution License (the "License"). 62df1fe9cSrandyf * You may not use this file except in compliance with the License. 72df1fe9cSrandyf * 82df1fe9cSrandyf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92df1fe9cSrandyf * or http://www.opensolaris.org/os/licensing. 102df1fe9cSrandyf * See the License for the specific language governing permissions 112df1fe9cSrandyf * and limitations under the License. 122df1fe9cSrandyf * 132df1fe9cSrandyf * When distributing Covered Code, include this CDDL HEADER in each 142df1fe9cSrandyf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152df1fe9cSrandyf * If applicable, add the following below this CDDL HEADER, with the 162df1fe9cSrandyf * fields enclosed by brackets "[]" replaced with your own identifying 172df1fe9cSrandyf * information: Portions Copyright [yyyy] [name of copyright owner] 182df1fe9cSrandyf * 192df1fe9cSrandyf * CDDL HEADER END 202df1fe9cSrandyf */ 212df1fe9cSrandyf 222df1fe9cSrandyf /* 23*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242df1fe9cSrandyf * Use is subject to license terms. 252df1fe9cSrandyf */ 262df1fe9cSrandyf 272df1fe9cSrandyf 282df1fe9cSrandyf /* 292df1fe9cSrandyf * srn Provide apm-like interfaces to Xorg 302df1fe9cSrandyf */ 312df1fe9cSrandyf 322df1fe9cSrandyf #include <sys/types.h> 332df1fe9cSrandyf #include <sys/errno.h> 342df1fe9cSrandyf #include <sys/modctl.h> 352df1fe9cSrandyf #include <sys/conf.h> /* driver flags and functions */ 362df1fe9cSrandyf #include <sys/open.h> /* OTYP_CHR definition */ 372df1fe9cSrandyf #include <sys/stat.h> /* S_IFCHR definition */ 382df1fe9cSrandyf #include <sys/pathname.h> /* name -> dev_info xlation */ 392df1fe9cSrandyf #include <sys/kmem.h> /* memory alloc stuff */ 402df1fe9cSrandyf #include <sys/debug.h> 412df1fe9cSrandyf #include <sys/pm.h> 422df1fe9cSrandyf #include <sys/ddi.h> 432df1fe9cSrandyf #include <sys/sunddi.h> 442df1fe9cSrandyf #include <sys/epm.h> 452df1fe9cSrandyf #include <sys/vfs.h> 462df1fe9cSrandyf #include <sys/mode.h> 472df1fe9cSrandyf #include <sys/mkdev.h> 482df1fe9cSrandyf #include <sys/promif.h> 492df1fe9cSrandyf #include <sys/consdev.h> 502df1fe9cSrandyf #include <sys/ddi_impldefs.h> 512df1fe9cSrandyf #include <sys/poll.h> 522df1fe9cSrandyf #include <sys/note.h> 532df1fe9cSrandyf #include <sys/taskq.h> 542df1fe9cSrandyf #include <sys/policy.h> 552df1fe9cSrandyf #include <sys/srn.h> 562df1fe9cSrandyf 572df1fe9cSrandyf /* 582df1fe9cSrandyf * Minor number is instance<<8 + clone minor from range 1-255; 592df1fe9cSrandyf * But only one will be allocated 602df1fe9cSrandyf */ 612df1fe9cSrandyf #define SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1)) 622df1fe9cSrandyf #define SU 0x002 632df1fe9cSrandyf #define SG 0x004 642df1fe9cSrandyf 652df1fe9cSrandyf extern kmutex_t srn_clone_lock; /* protects srn_clones array */ 662df1fe9cSrandyf extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 672df1fe9cSrandyf extern uint_t srn_poll_cnt[SRN_MAX_CLONE]; 682df1fe9cSrandyf 692df1fe9cSrandyf /* 702df1fe9cSrandyf * The soft state of the srn driver. Since there will only be 712df1fe9cSrandyf * one of these, just reference it through a static struct. 722df1fe9cSrandyf */ 732df1fe9cSrandyf static struct srnstate { 742df1fe9cSrandyf dev_info_t *srn_dip; /* ptr to our dev_info node */ 752df1fe9cSrandyf int srn_instance; /* for ddi_get_instance() */ 762df1fe9cSrandyf uchar_t srn_clones[SRN_MAX_CLONE]; /* unique opens */ 772df1fe9cSrandyf struct cred *srn_cred[SRN_MAX_CLONE]; /* cred for each open */ 782df1fe9cSrandyf int srn_type[SRN_MAX_CLONE]; /* type of handshake */ 792df1fe9cSrandyf int srn_delivered[SRN_MAX_CLONE]; 802df1fe9cSrandyf srn_event_info_t srn_pending[SRN_MAX_CLONE]; 812df1fe9cSrandyf } srn = { NULL, -1}; 822df1fe9cSrandyf typedef struct srnstate *srn_state_t; 832df1fe9cSrandyf 842df1fe9cSrandyf kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 852df1fe9cSrandyf uint_t srn_poll_cnt[SRN_MAX_CLONE]; /* count of events for poll */ 862df1fe9cSrandyf int srn_apm_count; 872df1fe9cSrandyf int srn_autosx_count; 882df1fe9cSrandyf struct pollhead srn_pollhead[SRN_MAX_CLONE]; 892df1fe9cSrandyf 902df1fe9cSrandyf static int srn_open(dev_t *, int, int, cred_t *); 912df1fe9cSrandyf static int srn_close(dev_t, int, int, cred_t *); 922df1fe9cSrandyf static int srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 932df1fe9cSrandyf static int srn_chpoll(dev_t, short, int, short *, struct pollhead **); 942df1fe9cSrandyf 952df1fe9cSrandyf static struct cb_ops srn_cb_ops = { 962df1fe9cSrandyf srn_open, /* open */ 972df1fe9cSrandyf srn_close, /* close */ 982df1fe9cSrandyf nodev, /* strategy */ 992df1fe9cSrandyf nodev, /* print */ 1002df1fe9cSrandyf nodev, /* dump */ 1012df1fe9cSrandyf nodev, /* read */ 1022df1fe9cSrandyf nodev, /* write */ 1032df1fe9cSrandyf srn_ioctl, /* ioctl */ 1042df1fe9cSrandyf nodev, /* devmap */ 1052df1fe9cSrandyf nodev, /* mmap */ 1062df1fe9cSrandyf nodev, /* segmap */ 1072df1fe9cSrandyf srn_chpoll, /* poll */ 1082df1fe9cSrandyf ddi_prop_op, /* prop_op */ 1092df1fe9cSrandyf NULL, /* streamtab */ 1102df1fe9cSrandyf D_NEW | D_MP /* driver compatibility flag */ 1112df1fe9cSrandyf }; 1122df1fe9cSrandyf 1132df1fe9cSrandyf static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1142df1fe9cSrandyf void **result); 1152df1fe9cSrandyf static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1162df1fe9cSrandyf static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1172df1fe9cSrandyf static void srn_notify(int type, int event); 1182df1fe9cSrandyf 1192df1fe9cSrandyf static struct dev_ops srn_ops = { 1202df1fe9cSrandyf DEVO_REV, /* devo_rev */ 1212df1fe9cSrandyf 0, /* refcnt */ 1222df1fe9cSrandyf srn_getinfo, /* info */ 1232df1fe9cSrandyf nulldev, /* identify */ 1242df1fe9cSrandyf nulldev, /* probe */ 1252df1fe9cSrandyf srn_attach, /* attach */ 1262df1fe9cSrandyf srn_detach, /* detach */ 1272df1fe9cSrandyf nodev, /* reset */ 1282df1fe9cSrandyf &srn_cb_ops, /* driver operations */ 1292df1fe9cSrandyf NULL, /* bus operations */ 130*19397407SSherry Moore NULL, /* power */ 131*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1322df1fe9cSrandyf }; 1332df1fe9cSrandyf 1342df1fe9cSrandyf static struct modldrv modldrv = { 1352df1fe9cSrandyf &mod_driverops, 136*19397407SSherry Moore "srn driver", 1372df1fe9cSrandyf &srn_ops 1382df1fe9cSrandyf }; 1392df1fe9cSrandyf 1402df1fe9cSrandyf static struct modlinkage modlinkage = { 1412df1fe9cSrandyf MODREV_1, &modldrv, 0 1422df1fe9cSrandyf }; 1432df1fe9cSrandyf 1442df1fe9cSrandyf /* Local functions */ 1452df1fe9cSrandyf 1462df1fe9cSrandyf int 1472df1fe9cSrandyf _init(void) 1482df1fe9cSrandyf { 1492df1fe9cSrandyf return (mod_install(&modlinkage)); 1502df1fe9cSrandyf } 1512df1fe9cSrandyf 1522df1fe9cSrandyf int 1532df1fe9cSrandyf _fini(void) 1542df1fe9cSrandyf { 1552df1fe9cSrandyf return (mod_remove(&modlinkage)); 1562df1fe9cSrandyf } 1572df1fe9cSrandyf 1582df1fe9cSrandyf int 1592df1fe9cSrandyf _info(struct modinfo *modinfop) 1602df1fe9cSrandyf { 1612df1fe9cSrandyf return (mod_info(&modlinkage, modinfop)); 1622df1fe9cSrandyf } 1632df1fe9cSrandyf 1642df1fe9cSrandyf static int 1652df1fe9cSrandyf srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1662df1fe9cSrandyf { 1672df1fe9cSrandyf int i; 1682df1fe9cSrandyf extern void (*srn_signal)(int, int); 1692df1fe9cSrandyf 1702df1fe9cSrandyf switch (cmd) { 1712df1fe9cSrandyf 1722df1fe9cSrandyf case DDI_ATTACH: 1732df1fe9cSrandyf if (srn.srn_instance != -1) /* Only allow one instance */ 1742df1fe9cSrandyf return (DDI_FAILURE); 1752df1fe9cSrandyf srn.srn_instance = ddi_get_instance(dip); 1762df1fe9cSrandyf if (ddi_create_minor_node(dip, "srn", S_IFCHR, 1772df1fe9cSrandyf (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0) 1782df1fe9cSrandyf != DDI_SUCCESS) { 1792df1fe9cSrandyf return (DDI_FAILURE); 1802df1fe9cSrandyf } 1812df1fe9cSrandyf srn.srn_dip = dip; /* srn_init and getinfo depend on it */ 1822df1fe9cSrandyf 1832df1fe9cSrandyf for (i = 0; i < SRN_MAX_CLONE; i++) 1842df1fe9cSrandyf cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL); 1852df1fe9cSrandyf 1862df1fe9cSrandyf srn.srn_instance = ddi_get_instance(dip); 1872df1fe9cSrandyf mutex_enter(&srn_clone_lock); 1882df1fe9cSrandyf srn_signal = srn_notify; 1892df1fe9cSrandyf mutex_exit(&srn_clone_lock); 1902df1fe9cSrandyf ddi_report_dev(dip); 1912df1fe9cSrandyf return (DDI_SUCCESS); 1922df1fe9cSrandyf 1932df1fe9cSrandyf default: 1942df1fe9cSrandyf return (DDI_FAILURE); 1952df1fe9cSrandyf } 1962df1fe9cSrandyf } 1972df1fe9cSrandyf 1982df1fe9cSrandyf /* ARGSUSED */ 1992df1fe9cSrandyf static int 2002df1fe9cSrandyf srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2012df1fe9cSrandyf { 2022df1fe9cSrandyf int i; 2032df1fe9cSrandyf extern int srn_inuse; 2042df1fe9cSrandyf extern void (*srn_signal)(int, int); 2052df1fe9cSrandyf 2062df1fe9cSrandyf switch (cmd) { 2072df1fe9cSrandyf case DDI_DETACH: 2082df1fe9cSrandyf 2092df1fe9cSrandyf mutex_enter(&srn_clone_lock); 2102df1fe9cSrandyf while (srn_inuse) { 2112df1fe9cSrandyf mutex_exit(&srn_clone_lock); 2122df1fe9cSrandyf delay(1); 2132df1fe9cSrandyf mutex_enter(&srn_clone_lock); 2142df1fe9cSrandyf } 2152df1fe9cSrandyf srn_signal = NULL; 2162df1fe9cSrandyf mutex_exit(&srn_clone_lock); 2172df1fe9cSrandyf 2182df1fe9cSrandyf for (i = 0; i < SRN_MAX_CLONE; i++) 2192df1fe9cSrandyf cv_destroy(&srn_clones_cv[i]); 2202df1fe9cSrandyf 2212df1fe9cSrandyf ddi_remove_minor_node(dip, NULL); 2222df1fe9cSrandyf srn.srn_instance = -1; 2232df1fe9cSrandyf return (DDI_SUCCESS); 2242df1fe9cSrandyf 2252df1fe9cSrandyf default: 2262df1fe9cSrandyf return (DDI_FAILURE); 2272df1fe9cSrandyf } 2282df1fe9cSrandyf } 2292df1fe9cSrandyf 2302df1fe9cSrandyf 2312df1fe9cSrandyf #ifdef DEBUG 2322df1fe9cSrandyf char *srn_cmd_string; 2332df1fe9cSrandyf int srn_cmd; 2342df1fe9cSrandyf #endif 2352df1fe9cSrandyf 2362df1fe9cSrandyf /* 2372df1fe9cSrandyf * Returns true if permission granted by credentials 2382df1fe9cSrandyf * XXX 2392df1fe9cSrandyf */ 2402df1fe9cSrandyf static int 2412df1fe9cSrandyf srn_perms(int perm, cred_t *cr) 2422df1fe9cSrandyf { 2432df1fe9cSrandyf if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ 2442df1fe9cSrandyf return (1); 2452df1fe9cSrandyf if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */ 2462df1fe9cSrandyf return (1); 2472df1fe9cSrandyf return (0); 2482df1fe9cSrandyf } 2492df1fe9cSrandyf 2502df1fe9cSrandyf static int 2512df1fe9cSrandyf srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 2522df1fe9cSrandyf struct pollhead **phpp) 2532df1fe9cSrandyf { 2542df1fe9cSrandyf extern struct pollhead srn_pollhead[]; /* common/os/sunpm.c */ 2552df1fe9cSrandyf int clone; 2562df1fe9cSrandyf 2572df1fe9cSrandyf clone = SRN_MINOR_TO_CLONE(getminor(dev)); 2582df1fe9cSrandyf if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) { 2592df1fe9cSrandyf *reventsp |= (POLLIN | POLLRDNORM); 2602df1fe9cSrandyf } else { 2612df1fe9cSrandyf *reventsp = 0; 2622df1fe9cSrandyf if (!anyyet) { 2632df1fe9cSrandyf *phpp = &srn_pollhead[clone]; 2642df1fe9cSrandyf } 2652df1fe9cSrandyf } 2662df1fe9cSrandyf return (0); 2672df1fe9cSrandyf } 2682df1fe9cSrandyf 2692df1fe9cSrandyf /*ARGSUSED*/ 2702df1fe9cSrandyf static int 2712df1fe9cSrandyf srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2722df1fe9cSrandyf { 2732df1fe9cSrandyf dev_t dev; 2742df1fe9cSrandyf int instance; 2752df1fe9cSrandyf 2762df1fe9cSrandyf switch (infocmd) { 2772df1fe9cSrandyf case DDI_INFO_DEVT2DEVINFO: 2782df1fe9cSrandyf if (srn.srn_instance == -1) 2792df1fe9cSrandyf return (DDI_FAILURE); 2802df1fe9cSrandyf *result = srn.srn_dip; 2812df1fe9cSrandyf return (DDI_SUCCESS); 2822df1fe9cSrandyf 2832df1fe9cSrandyf case DDI_INFO_DEVT2INSTANCE: 2842df1fe9cSrandyf dev = (dev_t)arg; 2852df1fe9cSrandyf instance = getminor(dev) >> 8; 2862df1fe9cSrandyf *result = (void *)(uintptr_t)instance; 2872df1fe9cSrandyf return (DDI_SUCCESS); 2882df1fe9cSrandyf 2892df1fe9cSrandyf default: 2902df1fe9cSrandyf return (DDI_FAILURE); 2912df1fe9cSrandyf } 2922df1fe9cSrandyf } 2932df1fe9cSrandyf 2942df1fe9cSrandyf 2952df1fe9cSrandyf /*ARGSUSED1*/ 2962df1fe9cSrandyf static int 2972df1fe9cSrandyf srn_open(dev_t *devp, int flag, int otyp, cred_t *cr) 2982df1fe9cSrandyf { 2992df1fe9cSrandyf int clone; 3002df1fe9cSrandyf 3012df1fe9cSrandyf if (otyp != OTYP_CHR) 3022df1fe9cSrandyf return (EINVAL); 3032df1fe9cSrandyf 3042df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3052df1fe9cSrandyf for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++) 3062df1fe9cSrandyf if (!srn.srn_clones[clone]) 3072df1fe9cSrandyf break; 3082df1fe9cSrandyf 3092df1fe9cSrandyf if (clone == SRN_MAX_CLONE) { 3102df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3112df1fe9cSrandyf return (ENXIO); 3122df1fe9cSrandyf } 3132df1fe9cSrandyf srn.srn_cred[clone] = cr; 3142df1fe9cSrandyf ASSERT(srn_apm_count >= 0); 3152df1fe9cSrandyf srn_apm_count++; 3162df1fe9cSrandyf srn.srn_type[clone] = SRN_TYPE_APM; 3172df1fe9cSrandyf crhold(cr); 3182df1fe9cSrandyf 3192df1fe9cSrandyf *devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) + 3202df1fe9cSrandyf clone); 3212df1fe9cSrandyf srn.srn_clones[clone] = 1; 3222df1fe9cSrandyf srn.srn_cred[clone] = cr; 3232df1fe9cSrandyf crhold(cr); 3242df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3252df1fe9cSrandyf PMD(PMD_SX, ("srn open OK\n")) 3262df1fe9cSrandyf return (0); 3272df1fe9cSrandyf } 3282df1fe9cSrandyf 3292df1fe9cSrandyf /*ARGSUSED1*/ 3302df1fe9cSrandyf static int 3312df1fe9cSrandyf srn_close(dev_t dev, int flag, int otyp, cred_t *cr) 3322df1fe9cSrandyf { 3332df1fe9cSrandyf int clone; 3342df1fe9cSrandyf 3352df1fe9cSrandyf if (otyp != OTYP_CHR) 3362df1fe9cSrandyf return (EINVAL); 3372df1fe9cSrandyf 3382df1fe9cSrandyf clone = SRN_MINOR_TO_CLONE(getminor(dev)); 3392df1fe9cSrandyf PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev), 3402df1fe9cSrandyf clone)) 3412df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3422df1fe9cSrandyf crfree(srn.srn_cred[clone]); 3432df1fe9cSrandyf srn.srn_cred[clone] = 0; 3442df1fe9cSrandyf srn_poll_cnt[clone] = 0; 3452df1fe9cSrandyf if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) { 3462df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 3472df1fe9cSrandyf srn.srn_delivered[clone] = 0; 3482df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 3492df1fe9cSrandyf } 3502df1fe9cSrandyf switch (srn.srn_type[clone]) { 3512df1fe9cSrandyf case SRN_TYPE_AUTOSX: 3522df1fe9cSrandyf ASSERT(srn_autosx_count); 3532df1fe9cSrandyf srn_autosx_count--; 3542df1fe9cSrandyf break; 3552df1fe9cSrandyf case SRN_TYPE_APM: 3562df1fe9cSrandyf ASSERT(srn_apm_count); 3572df1fe9cSrandyf srn_apm_count--; 3582df1fe9cSrandyf break; 3592df1fe9cSrandyf default: 3602df1fe9cSrandyf ASSERT(0); 3612df1fe9cSrandyf return (EINVAL); 3622df1fe9cSrandyf } 3632df1fe9cSrandyf srn.srn_clones[clone] = 0; 3642df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3652df1fe9cSrandyf return (0); 3662df1fe9cSrandyf } 3672df1fe9cSrandyf 3682df1fe9cSrandyf /*ARGSUSED*/ 3692df1fe9cSrandyf static int 3702df1fe9cSrandyf srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) 3712df1fe9cSrandyf { 3722df1fe9cSrandyf int clone = SRN_MINOR_TO_CLONE(getminor(dev)); 3732df1fe9cSrandyf 3742df1fe9cSrandyf PMD(PMD_SX, ("ioctl: %x: begin\n", cmd)) 3752df1fe9cSrandyf 3762df1fe9cSrandyf switch (cmd) { 3772df1fe9cSrandyf case SRN_IOC_NEXTEVENT: 3782df1fe9cSrandyf case SRN_IOC_SUSPEND: 3792df1fe9cSrandyf case SRN_IOC_RESUME: 3802df1fe9cSrandyf case SRN_IOC_AUTOSX: 3812df1fe9cSrandyf break; 3822df1fe9cSrandyf default: 3832df1fe9cSrandyf return (ENOTTY); 3842df1fe9cSrandyf } 3852df1fe9cSrandyf 3862df1fe9cSrandyf if (!srn_perms(SU | SG, srn.srn_cred[clone])) { 3872df1fe9cSrandyf return (EPERM); 3882df1fe9cSrandyf } 3892df1fe9cSrandyf switch (cmd) { 3902df1fe9cSrandyf case SRN_IOC_AUTOSX: 3912df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n")) 3922df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3932df1fe9cSrandyf if (!srn.srn_clones[clone]) { 3942df1fe9cSrandyf PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n")) 3952df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3962df1fe9cSrandyf return (EINVAL); 3972df1fe9cSrandyf } 3982df1fe9cSrandyf if (srn.srn_pending[clone].ae_type) { 3992df1fe9cSrandyf PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n")) 4002df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4012df1fe9cSrandyf return (EBUSY); 4022df1fe9cSrandyf } 4032df1fe9cSrandyf if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) { 4042df1fe9cSrandyf PMD(PMD_SX, ("AUTOSX already--EBUSY\n")) 4052df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4062df1fe9cSrandyf return (EBUSY); 4072df1fe9cSrandyf } 4082df1fe9cSrandyf ASSERT(srn.srn_type[clone] == SRN_TYPE_APM); 4092df1fe9cSrandyf srn.srn_type[clone] = SRN_TYPE_AUTOSX; 4102df1fe9cSrandyf srn_apm_count--; 4112df1fe9cSrandyf ASSERT(srn_apm_count >= 0); 4122df1fe9cSrandyf ASSERT(srn_autosx_count >= 0); 4132df1fe9cSrandyf srn_autosx_count++; 4142df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4152df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n")) 4162df1fe9cSrandyf return (0); 4172df1fe9cSrandyf 4182df1fe9cSrandyf case SRN_IOC_NEXTEVENT: 4192df1fe9cSrandyf /* 4202df1fe9cSrandyf * return the next suspend or resume event; there should 4212df1fe9cSrandyf * be one, cause we only get called if we've signalled a 4222df1fe9cSrandyf * poll data completion 4232df1fe9cSrandyf * then wake up the kernel thread sleeping for the delivery 4242df1fe9cSrandyf */ 4252df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n")) 4262df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4272df1fe9cSrandyf if (srn_poll_cnt[clone] == 0) { 4282df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4292df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d " 4302df1fe9cSrandyf "EWOULDBLOCK\n", clone)) 4312df1fe9cSrandyf return (EWOULDBLOCK); 4322df1fe9cSrandyf } 4332df1fe9cSrandyf ASSERT(srn.srn_pending[clone].ae_type); 4342df1fe9cSrandyf if (ddi_copyout(&srn.srn_pending[clone], (void *)arg, 4352df1fe9cSrandyf sizeof (srn_event_info_t), mode) != 0) { 4362df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4372df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n", 4382df1fe9cSrandyf clone)) 4392df1fe9cSrandyf return (EFAULT); 4402df1fe9cSrandyf } 4412df1fe9cSrandyf if (srn.srn_type[clone] == SRN_TYPE_APM) 4422df1fe9cSrandyf srn.srn_delivered[clone] = 4432df1fe9cSrandyf srn.srn_pending[clone].ae_type; 4442df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n", 4452df1fe9cSrandyf clone, srn.srn_pending[clone].ae_type)) 4462df1fe9cSrandyf srn_poll_cnt[clone] = 0; 4472df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4482df1fe9cSrandyf return (0); 4492df1fe9cSrandyf 4502df1fe9cSrandyf case SRN_IOC_SUSPEND: 4512df1fe9cSrandyf /* ack suspend */ 4522df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone)) 4532df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4542df1fe9cSrandyf if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) { 4552df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4562df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n")) 4572df1fe9cSrandyf return (EINVAL); 4582df1fe9cSrandyf } 4592df1fe9cSrandyf srn.srn_delivered[clone] = 0; 4602df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 4612df1fe9cSrandyf /* notify the kernel suspend thread to continue */ 4622df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone)) 4632df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 4642df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4652df1fe9cSrandyf return (0); 4662df1fe9cSrandyf 4672df1fe9cSrandyf case SRN_IOC_RESUME: 4682df1fe9cSrandyf /* ack resume */ 4692df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone)) 4702df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4712df1fe9cSrandyf if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) { 4722df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4732df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n")) 4742df1fe9cSrandyf return (EINVAL); 4752df1fe9cSrandyf } 4762df1fe9cSrandyf srn.srn_delivered[clone] = 0; 4772df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 4782df1fe9cSrandyf /* notify the kernel resume thread to continue */ 4792df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone)) 4802df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 4812df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4822df1fe9cSrandyf return (0); 4832df1fe9cSrandyf 4842df1fe9cSrandyf default: 4852df1fe9cSrandyf PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n")) 4862df1fe9cSrandyf return (EINVAL); 4872df1fe9cSrandyf } 4882df1fe9cSrandyf } 4892df1fe9cSrandyf /* 4902df1fe9cSrandyf * A very simple handshake with the srn driver, 4912df1fe9cSrandyf * only one outstanding event at a time. 4922df1fe9cSrandyf * The OS delivers the event and depending on type, 4932df1fe9cSrandyf * either blocks waiting for the ack, or drives on 4942df1fe9cSrandyf */ 4952df1fe9cSrandyf void 4962df1fe9cSrandyf srn_notify(int type, int event) 4972df1fe9cSrandyf { 4982df1fe9cSrandyf int clone, count; 4992df1fe9cSrandyf PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n", 5002df1fe9cSrandyf type, event)); 5012df1fe9cSrandyf ASSERT(mutex_owned(&srn_clone_lock)); 5022df1fe9cSrandyf switch (type) { 5032df1fe9cSrandyf case SRN_TYPE_APM: 5042df1fe9cSrandyf if (srn_apm_count == 0) { 5052df1fe9cSrandyf PMD(PMD_SX, ("no apm types\n")) 5062df1fe9cSrandyf return; 5072df1fe9cSrandyf } 5082df1fe9cSrandyf count = srn_apm_count; 5092df1fe9cSrandyf break; 5102df1fe9cSrandyf case SRN_TYPE_AUTOSX: 5112df1fe9cSrandyf if (srn_autosx_count == 0) { 5122df1fe9cSrandyf PMD(PMD_SX, ("no autosx types\n")) 5132df1fe9cSrandyf return; 5142df1fe9cSrandyf } 5152df1fe9cSrandyf count = srn_autosx_count; 5162df1fe9cSrandyf break; 5172df1fe9cSrandyf default: 5182df1fe9cSrandyf ASSERT(0); 5192df1fe9cSrandyf break; 5202df1fe9cSrandyf } 5212df1fe9cSrandyf ASSERT(count > 0); 5222df1fe9cSrandyf PMD(PMD_SX, ("count %d\n", count)) 5232df1fe9cSrandyf for (clone = 0; clone < SRN_MAX_CLONE; clone++) { 5242df1fe9cSrandyf if (srn.srn_type[clone] == type) { 5252df1fe9cSrandyf if (type == SRN_TYPE_APM) { 5262df1fe9cSrandyf ASSERT(srn.srn_pending[clone].ae_type == 0); 5272df1fe9cSrandyf ASSERT(srn_poll_cnt[clone] == 0); 5282df1fe9cSrandyf ASSERT(srn.srn_delivered[clone] == 0); 5292df1fe9cSrandyf } 5302df1fe9cSrandyf srn.srn_pending[clone].ae_type = event; 5312df1fe9cSrandyf srn_poll_cnt[clone] = 1; 5322df1fe9cSrandyf PMD(PMD_SX, ("pollwake %d\n", clone)) 5332df1fe9cSrandyf pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN)); 5342df1fe9cSrandyf count--; 5352df1fe9cSrandyf if (count == 0) 5362df1fe9cSrandyf break; 5372df1fe9cSrandyf } 5382df1fe9cSrandyf } 5392df1fe9cSrandyf if (type == SRN_TYPE_AUTOSX) { /* we don't wait */ 5402df1fe9cSrandyf PMD(PMD_SX, ("Not waiting for AUTOSX ack\n")) 5412df1fe9cSrandyf return; 5422df1fe9cSrandyf } 5432df1fe9cSrandyf ASSERT(type == SRN_TYPE_APM); 5442df1fe9cSrandyf /* otherwise wait for acks */ 5452df1fe9cSrandyf restart: 5462df1fe9cSrandyf /* 5472df1fe9cSrandyf * We wait untill all of the pending events are cleared. 5482df1fe9cSrandyf * We have to start over every time we do a cv_wait because 5492df1fe9cSrandyf * we give up the mutex and can be re-entered 5502df1fe9cSrandyf */ 5512df1fe9cSrandyf for (clone = 1; clone < SRN_MAX_CLONE; clone++) { 5522df1fe9cSrandyf if (srn.srn_clones[clone] == 0 || 5532df1fe9cSrandyf srn.srn_type[clone] != SRN_TYPE_APM) 5542df1fe9cSrandyf continue; 5552df1fe9cSrandyf if (srn.srn_pending[clone].ae_type) { 5562df1fe9cSrandyf PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, " 5572df1fe9cSrandyf "event %x\n", clone, event)) 5582df1fe9cSrandyf cv_wait(&srn_clones_cv[clone], &srn_clone_lock); 5592df1fe9cSrandyf goto restart; 5602df1fe9cSrandyf } 5612df1fe9cSrandyf } 5622df1fe9cSrandyf PMD(PMD_SX, ("srn_notify done with %x\n", event)) 5632df1fe9cSrandyf } 564