1*4667Smh27603 /* 2*4667Smh27603 * CDDL HEADER START 3*4667Smh27603 * 4*4667Smh27603 * The contents of this file are subject to the terms of the 5*4667Smh27603 * Common Development and Distribution License (the "License"). 6*4667Smh27603 * You may not use this file except in compliance with the License. 7*4667Smh27603 * 8*4667Smh27603 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4667Smh27603 * or http://www.opensolaris.org/os/licensing. 10*4667Smh27603 * See the License for the specific language governing permissions 11*4667Smh27603 * and limitations under the License. 12*4667Smh27603 * 13*4667Smh27603 * When distributing Covered Code, include this CDDL HEADER in each 14*4667Smh27603 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4667Smh27603 * If applicable, add the following below this CDDL HEADER, with the 16*4667Smh27603 * fields enclosed by brackets "[]" replaced with your own identifying 17*4667Smh27603 * information: Portions Copyright [yyyy] [name of copyright owner] 18*4667Smh27603 * 19*4667Smh27603 * CDDL HEADER END 20*4667Smh27603 */ 21*4667Smh27603 /* 22*4667Smh27603 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*4667Smh27603 * Use is subject to license terms. 24*4667Smh27603 */ 25*4667Smh27603 26*4667Smh27603 #pragma ident "%Z%%M% %I% %E% SMI" 27*4667Smh27603 28*4667Smh27603 29*4667Smh27603 /* 30*4667Smh27603 * common code for ppm drivers 31*4667Smh27603 */ 32*4667Smh27603 #include <sys/modctl.h> 33*4667Smh27603 #include <sys/ddi.h> 34*4667Smh27603 #include <sys/sunddi.h> 35*4667Smh27603 #include <sys/ddi_impldefs.h> 36*4667Smh27603 #include <sys/ppmvar.h> 37*4667Smh27603 #include <sys/ppmio.h> 38*4667Smh27603 #include <sys/epm.h> 39*4667Smh27603 #include <sys/open.h> 40*4667Smh27603 #include <sys/file.h> 41*4667Smh27603 #include <sys/policy.h> 42*4667Smh27603 43*4667Smh27603 44*4667Smh27603 #ifdef DEBUG 45*4667Smh27603 uint_t ppm_debug = 0; 46*4667Smh27603 #endif 47*4667Smh27603 48*4667Smh27603 int ppm_inst = -1; 49*4667Smh27603 char *ppm_prefix; 50*4667Smh27603 void *ppm_statep; 51*4667Smh27603 52*4667Smh27603 53*4667Smh27603 /* 54*4667Smh27603 * common module _init 55*4667Smh27603 */ 56*4667Smh27603 int 57*4667Smh27603 ppm_init(struct modlinkage *mlp, size_t size, char *prefix) 58*4667Smh27603 { 59*4667Smh27603 #ifdef DEBUG 60*4667Smh27603 char *str = "ppm_init"; 61*4667Smh27603 #endif 62*4667Smh27603 int error; 63*4667Smh27603 64*4667Smh27603 ppm_prefix = prefix; 65*4667Smh27603 66*4667Smh27603 error = ddi_soft_state_init(&ppm_statep, size, 1); 67*4667Smh27603 DPRINTF(D_INIT, ("%s: ss init %d\n", str, error)); 68*4667Smh27603 if (error != DDI_SUCCESS) 69*4667Smh27603 return (error); 70*4667Smh27603 71*4667Smh27603 if (error = mod_install(mlp)) 72*4667Smh27603 ddi_soft_state_fini(&ppm_statep); 73*4667Smh27603 DPRINTF(D_INIT, ("%s: mod_install %d\n", str, error)); 74*4667Smh27603 75*4667Smh27603 return (error); 76*4667Smh27603 } 77*4667Smh27603 78*4667Smh27603 79*4667Smh27603 /* ARGSUSED */ 80*4667Smh27603 int 81*4667Smh27603 ppm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 82*4667Smh27603 { 83*4667Smh27603 struct ppm_unit *overlay; 84*4667Smh27603 int rval; 85*4667Smh27603 86*4667Smh27603 if (ppm_inst == -1) 87*4667Smh27603 return (DDI_FAILURE); 88*4667Smh27603 89*4667Smh27603 switch (cmd) { 90*4667Smh27603 case DDI_INFO_DEVT2DEVINFO: 91*4667Smh27603 if (overlay = ddi_get_soft_state(ppm_statep, ppm_inst)) { 92*4667Smh27603 *resultp = overlay->dip; 93*4667Smh27603 rval = DDI_SUCCESS; 94*4667Smh27603 } else 95*4667Smh27603 rval = DDI_FAILURE; 96*4667Smh27603 return (rval); 97*4667Smh27603 98*4667Smh27603 case DDI_INFO_DEVT2INSTANCE: 99*4667Smh27603 *resultp = (void *)(uintptr_t)ppm_inst; 100*4667Smh27603 return (DDI_SUCCESS); 101*4667Smh27603 102*4667Smh27603 default: 103*4667Smh27603 return (DDI_FAILURE); 104*4667Smh27603 } 105*4667Smh27603 } 106*4667Smh27603 107*4667Smh27603 108*4667Smh27603 /* ARGSUSED */ 109*4667Smh27603 int 110*4667Smh27603 ppm_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 111*4667Smh27603 { 112*4667Smh27603 if (otyp != OTYP_CHR) 113*4667Smh27603 return (EINVAL); 114*4667Smh27603 DPRINTF(D_OPEN, ("ppm_open: \"%s\", devp 0x%p, flag 0x%x, otyp %d\n", 115*4667Smh27603 ppm_prefix, devp, flag, otyp)); 116*4667Smh27603 return (0); 117*4667Smh27603 } 118*4667Smh27603 119*4667Smh27603 120*4667Smh27603 /* ARGSUSED */ 121*4667Smh27603 int 122*4667Smh27603 ppm_close(dev_t dev, int flag, int otyp, cred_t *credp) 123*4667Smh27603 { 124*4667Smh27603 DPRINTF(D_CLOSE, ("ppm_close: \"%s\", dev 0x%lx, flag 0x%x, otyp %d\n", 125*4667Smh27603 ppm_prefix, dev, flag, otyp)); 126*4667Smh27603 return (DDI_SUCCESS); 127*4667Smh27603 } 128*4667Smh27603 129*4667Smh27603 130*4667Smh27603 /* 131*4667Smh27603 * lookup arrays of strings from configuration data (XXppm.conf) 132*4667Smh27603 */ 133*4667Smh27603 static int 134*4667Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip) 135*4667Smh27603 { 136*4667Smh27603 struct ppm_cdata *cinfo; 137*4667Smh27603 int err; 138*4667Smh27603 139*4667Smh27603 for (; (cinfo = *cdp) != NULL; cdp++) { 140*4667Smh27603 err = ddi_prop_lookup_string_array( 141*4667Smh27603 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 142*4667Smh27603 cinfo->name, &cinfo->strings, &cinfo->cnt); 143*4667Smh27603 if (err != DDI_PROP_SUCCESS) { 144*4667Smh27603 DPRINTF(D_ERROR, 145*4667Smh27603 ("ppm_get_confdata: no %s found\n", cinfo->name)); 146*4667Smh27603 break; 147*4667Smh27603 } 148*4667Smh27603 } 149*4667Smh27603 return (err); 150*4667Smh27603 } 151*4667Smh27603 152*4667Smh27603 153*4667Smh27603 /* 154*4667Smh27603 * free allocated ddi prop strings, and free 155*4667Smh27603 * ppm_db_t lists where there's an error. 156*4667Smh27603 */ 157*4667Smh27603 static int 158*4667Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err) 159*4667Smh27603 { 160*4667Smh27603 ppm_domain_t **dompp; 161*4667Smh27603 ppm_db_t *db, *tmp; 162*4667Smh27603 163*4667Smh27603 if (cdp) { 164*4667Smh27603 for (; *cdp; cdp++) { 165*4667Smh27603 if ((*cdp)->strings) { 166*4667Smh27603 ddi_prop_free((*cdp)->strings); 167*4667Smh27603 (*cdp)->strings = NULL; 168*4667Smh27603 } 169*4667Smh27603 } 170*4667Smh27603 } 171*4667Smh27603 172*4667Smh27603 if (err != DDI_SUCCESS) { 173*4667Smh27603 for (dompp = ppm_domains; *dompp; dompp++) { 174*4667Smh27603 for (db = (*dompp)->conflist; (tmp = db) != NULL; ) { 175*4667Smh27603 db = db->next; 176*4667Smh27603 kmem_free(tmp->name, strlen(tmp->name) + 1); 177*4667Smh27603 kmem_free(tmp, sizeof (*tmp)); 178*4667Smh27603 } 179*4667Smh27603 (*dompp)->conflist = NULL; 180*4667Smh27603 } 181*4667Smh27603 err = DDI_FAILURE; 182*4667Smh27603 } 183*4667Smh27603 184*4667Smh27603 return (err); 185*4667Smh27603 } 186*4667Smh27603 187*4667Smh27603 188*4667Smh27603 ppm_domain_t * 189*4667Smh27603 ppm_lookup_domain(char *dname) 190*4667Smh27603 { 191*4667Smh27603 ppm_domain_t **dompp; 192*4667Smh27603 193*4667Smh27603 for (dompp = ppm_domains; *dompp; dompp++) 194*4667Smh27603 if (strcmp(dname, (*dompp)->name) == 0) 195*4667Smh27603 break; 196*4667Smh27603 return (*dompp); 197*4667Smh27603 } 198*4667Smh27603 199*4667Smh27603 200*4667Smh27603 /* 201*4667Smh27603 * create a ppm-private database from parsed .conf data; we start with 202*4667Smh27603 * two string arrays (device pathnames and domain names) and treat them 203*4667Smh27603 * as matched pairs where device[N] is part of domain[N] 204*4667Smh27603 */ 205*4667Smh27603 int 206*4667Smh27603 ppm_create_db(dev_info_t *dip) 207*4667Smh27603 { 208*4667Smh27603 #ifdef DEBUG 209*4667Smh27603 char *str = "ppm_create_db"; 210*4667Smh27603 #endif 211*4667Smh27603 struct ppm_cdata devdata, domdata, *cdata[3]; 212*4667Smh27603 ppm_domain_t *domp; 213*4667Smh27603 ppm_db_t *new; 214*4667Smh27603 char **dev_namep, **dom_namep; 215*4667Smh27603 char *wild; 216*4667Smh27603 int err; 217*4667Smh27603 218*4667Smh27603 bzero(&devdata, sizeof (devdata)); 219*4667Smh27603 bzero(&domdata, sizeof (domdata)); 220*4667Smh27603 devdata.name = "ppm-devices"; 221*4667Smh27603 domdata.name = "ppm-domains"; 222*4667Smh27603 cdata[0] = &devdata; 223*4667Smh27603 cdata[1] = &domdata; 224*4667Smh27603 cdata[2] = NULL; 225*4667Smh27603 if (err = ppm_get_confdata(cdata, dip)) 226*4667Smh27603 return (ppm_attach_err(cdata, err)); 227*4667Smh27603 else if (devdata.cnt != domdata.cnt) { 228*4667Smh27603 DPRINTF(D_ERROR, 229*4667Smh27603 ("%s: %sppm.conf has a mismatched number of %s and %s\n", 230*4667Smh27603 str, ppm_prefix, devdata.name, domdata.name)); 231*4667Smh27603 return (ppm_attach_err(cdata, DDI_FAILURE)); 232*4667Smh27603 } 233*4667Smh27603 234*4667Smh27603 /* 235*4667Smh27603 * loop through device/domain pairs and build 236*4667Smh27603 * a linked list of devices within known domains 237*4667Smh27603 */ 238*4667Smh27603 for (dev_namep = devdata.strings, dom_namep = domdata.strings; 239*4667Smh27603 *dev_namep; dev_namep++, dom_namep++) { 240*4667Smh27603 domp = ppm_lookup_domain(*dom_namep); 241*4667Smh27603 if (domp == NULL) { 242*4667Smh27603 DPRINTF(D_ERROR, ("%s: invalid domain \"%s\" for " 243*4667Smh27603 "device \"%s\"\n", str, *dom_namep, *dev_namep)); 244*4667Smh27603 return (ppm_attach_err(cdata, DDI_FAILURE)); 245*4667Smh27603 } 246*4667Smh27603 247*4667Smh27603 /* 248*4667Smh27603 * allocate a new ppm db entry and link it to 249*4667Smh27603 * the front of conflist within this domain 250*4667Smh27603 */ 251*4667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 252*4667Smh27603 new->name = kmem_zalloc(strlen(*dev_namep) + 1, KM_SLEEP); 253*4667Smh27603 (void) strcpy(new->name, *dev_namep); 254*4667Smh27603 new->next = domp->conflist; 255*4667Smh27603 domp->conflist = new; 256*4667Smh27603 257*4667Smh27603 /* 258*4667Smh27603 * when the device name contains a wildcard, 259*4667Smh27603 * save the length of the preceding string 260*4667Smh27603 */ 261*4667Smh27603 if (wild = strchr(new->name, '*')) 262*4667Smh27603 new->plen = (wild - new->name); 263*4667Smh27603 DPRINTF(D_CREATEDB, ("%s: \"%s\", added \"%s\"\n", 264*4667Smh27603 str, domp->name, new->name)); 265*4667Smh27603 } 266*4667Smh27603 267*4667Smh27603 return (ppm_attach_err(cdata, DDI_SUCCESS)); 268*4667Smh27603 } 269*4667Smh27603 270*4667Smh27603 271*4667Smh27603 /* 272*4667Smh27603 * scan conf devices within each domain for a matching device name 273*4667Smh27603 */ 274*4667Smh27603 ppm_domain_t * 275*4667Smh27603 ppm_lookup_dev(dev_info_t *dip) 276*4667Smh27603 { 277*4667Smh27603 char path[MAXNAMELEN]; 278*4667Smh27603 ppm_domain_t **dompp; 279*4667Smh27603 ppm_db_t *dbp; 280*4667Smh27603 281*4667Smh27603 (void) ddi_pathname(dip, path); 282*4667Smh27603 for (dompp = ppm_domains; *dompp; dompp++) { 283*4667Smh27603 for (dbp = (*dompp)->conflist; dbp; dbp = dbp->next) { 284*4667Smh27603 if (dbp->plen == 0) { 285*4667Smh27603 if (strcmp(path, dbp->name) == 0) 286*4667Smh27603 return (*dompp); 287*4667Smh27603 } else if (strncmp(path, dbp->name, dbp->plen) == 0) 288*4667Smh27603 return (*dompp); 289*4667Smh27603 } 290*4667Smh27603 } 291*4667Smh27603 292*4667Smh27603 return (NULL); 293*4667Smh27603 } 294*4667Smh27603 295*4667Smh27603 296*4667Smh27603 /* 297*4667Smh27603 * returns 1 (claimed), 0 (not claimed) 298*4667Smh27603 */ 299*4667Smh27603 int 300*4667Smh27603 ppm_claim_dev(dev_info_t *dip) 301*4667Smh27603 { 302*4667Smh27603 ppm_domain_t *domp; 303*4667Smh27603 304*4667Smh27603 domp = ppm_lookup_dev(dip); 305*4667Smh27603 306*4667Smh27603 #ifdef DEBUG 307*4667Smh27603 if (domp) { 308*4667Smh27603 char path[MAXNAMELEN]; 309*4667Smh27603 DPRINTF(D_CLAIMDEV, 310*4667Smh27603 ("ppm_claim_dev: \"%s\", matched \"%s\"\n", 311*4667Smh27603 domp->name, ddi_pathname(dip, path))); 312*4667Smh27603 } 313*4667Smh27603 314*4667Smh27603 #endif 315*4667Smh27603 316*4667Smh27603 return (domp != NULL); 317*4667Smh27603 } 318*4667Smh27603 319*4667Smh27603 320*4667Smh27603 /* 321*4667Smh27603 * create/init a new ppm device and link into the domain 322*4667Smh27603 */ 323*4667Smh27603 ppm_dev_t * 324*4667Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp) 325*4667Smh27603 { 326*4667Smh27603 char path[MAXNAMELEN]; 327*4667Smh27603 ppm_dev_t *new = NULL; 328*4667Smh27603 int cmpt; 329*4667Smh27603 330*4667Smh27603 ASSERT(MUTEX_HELD(&domp->lock)); 331*4667Smh27603 (void) ddi_pathname(dip, path); 332*4667Smh27603 /* 333*4667Smh27603 * For devs which have exported "pm-components" we want to create 334*4667Smh27603 * a data structure for each component. When a driver chooses not 335*4667Smh27603 * to export the prop we treat its device as having a single 336*4667Smh27603 * component and build a structure for it anyway. All other ppm 337*4667Smh27603 * logic will act as if this device were always up and can thus 338*4667Smh27603 * make correct decisions about it in relation to other devices 339*4667Smh27603 * in its domain. 340*4667Smh27603 */ 341*4667Smh27603 for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) { 342*4667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP); 343*4667Smh27603 new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP); 344*4667Smh27603 (void) strcpy(new->path, path); 345*4667Smh27603 new->domp = domp; 346*4667Smh27603 new->dip = dip; 347*4667Smh27603 new->cmpt = cmpt; 348*4667Smh27603 if (ppmf.dev_init) 349*4667Smh27603 (*ppmf.dev_init)(new); 350*4667Smh27603 new->next = domp->devlist; 351*4667Smh27603 domp->devlist = new; 352*4667Smh27603 DPRINTF(D_ADDDEV, 353*4667Smh27603 ("ppm_add_dev: \"%s\", \"%s\", ppm_dev 0x%p\n", 354*4667Smh27603 new->path, domp->name, new)); 355*4667Smh27603 } 356*4667Smh27603 357*4667Smh27603 ASSERT(new != NULL); 358*4667Smh27603 /* 359*4667Smh27603 * devi_pm_ppm_private should be set only after all 360*4667Smh27603 * ppm_dev s related to all components have been 361*4667Smh27603 * initialized and domain's pwr_cnt is incremented 362*4667Smh27603 * for each of them. 363*4667Smh27603 */ 364*4667Smh27603 PPM_SET_PRIVATE(dip, new); 365*4667Smh27603 366*4667Smh27603 return (new); 367*4667Smh27603 } 368*4667Smh27603 369*4667Smh27603 370*4667Smh27603 /* 371*4667Smh27603 * returns an existing or newly created ppm device reference 372*4667Smh27603 */ 373*4667Smh27603 ppm_dev_t * 374*4667Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp) 375*4667Smh27603 { 376*4667Smh27603 ppm_dev_t *pdp; 377*4667Smh27603 378*4667Smh27603 mutex_enter(&domp->lock); 379*4667Smh27603 pdp = PPM_GET_PRIVATE(dip); 380*4667Smh27603 if (pdp == NULL) 381*4667Smh27603 pdp = ppm_add_dev(dip, domp); 382*4667Smh27603 mutex_exit(&domp->lock); 383*4667Smh27603 384*4667Smh27603 return (pdp); 385*4667Smh27603 } 386*4667Smh27603 387*4667Smh27603 388*4667Smh27603 /* 389*4667Smh27603 * scan a domain's device list and remove those with .dip 390*4667Smh27603 * matching the arg *dip; we need to scan the entire list 391*4667Smh27603 * for the case of devices with multiple components 392*4667Smh27603 */ 393*4667Smh27603 void 394*4667Smh27603 ppm_rem_dev(dev_info_t *dip) 395*4667Smh27603 { 396*4667Smh27603 ppm_dev_t *pdp, **devpp; 397*4667Smh27603 ppm_domain_t *domp; 398*4667Smh27603 399*4667Smh27603 pdp = PPM_GET_PRIVATE(dip); 400*4667Smh27603 ASSERT(pdp); 401*4667Smh27603 domp = pdp->domp; 402*4667Smh27603 ASSERT(domp); 403*4667Smh27603 404*4667Smh27603 mutex_enter(&domp->lock); 405*4667Smh27603 for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) { 406*4667Smh27603 if (pdp->dip != dip) { 407*4667Smh27603 devpp = &pdp->next; 408*4667Smh27603 continue; 409*4667Smh27603 } 410*4667Smh27603 411*4667Smh27603 DPRINTF(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n", 412*4667Smh27603 pdp->path, pdp)); 413*4667Smh27603 414*4667Smh27603 PPM_SET_PRIVATE(dip, NULL); 415*4667Smh27603 *devpp = pdp->next; 416*4667Smh27603 if (ppmf.dev_fini) 417*4667Smh27603 (*ppmf.dev_fini)(pdp); 418*4667Smh27603 kmem_free(pdp->path, strlen(pdp->path) + 1); 419*4667Smh27603 kmem_free(pdp, sizeof (*pdp)); 420*4667Smh27603 } 421*4667Smh27603 mutex_exit(&domp->lock); 422*4667Smh27603 } 423*4667Smh27603 424*4667Smh27603 425*4667Smh27603 /* ARGSUSED */ 426*4667Smh27603 int 427*4667Smh27603 ppm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 428*4667Smh27603 cred_t *cred_p, int *rval_p) 429*4667Smh27603 { 430*4667Smh27603 #ifdef DEBUG 431*4667Smh27603 char *str = "ppm_ioctl"; 432*4667Smh27603 char *rwfmt = "%s: mode error: 0x%x is missing %s perm, cmd 0x%x\n"; 433*4667Smh27603 char *iofmt = "%s: copy%s error, arg 0x%p\n"; 434*4667Smh27603 #endif 435*4667Smh27603 ppmreq_t req; 436*4667Smh27603 uint8_t level; 437*4667Smh27603 438*4667Smh27603 DPRINTF(D_IOCTL, ("%s: dev 0x%lx, cmd 0x%x, arg 0x%lx, mode 0x%x\n", 439*4667Smh27603 str, dev, cmd, arg, mode)); 440*4667Smh27603 441*4667Smh27603 if (ddi_copyin((caddr_t)arg, &req, sizeof (req), mode)) { 442*4667Smh27603 DPRINTF(D_IOCTL, (iofmt, str, "in", arg)); 443*4667Smh27603 return (EFAULT); 444*4667Smh27603 } 445*4667Smh27603 446*4667Smh27603 /* 447*4667Smh27603 * Currently, only PPM_INTERNAL_DEVICE_POWER device type is supported 448*4667Smh27603 */ 449*4667Smh27603 if (req.ppmdev != PPM_INTERNAL_DEVICE_POWER) { 450*4667Smh27603 DPRINTF(D_IOCTL, ("%s: unrecognized device type %d\n", 451*4667Smh27603 str, req.ppmdev)); 452*4667Smh27603 return (EINVAL); 453*4667Smh27603 } 454*4667Smh27603 455*4667Smh27603 switch (cmd) { 456*4667Smh27603 case PPMIOCSET: 457*4667Smh27603 if (secpolicy_power_mgmt(cred_p) != 0) { 458*4667Smh27603 DPRINTF(D_IOCTL, ("%s: bad cred for cmd 0x%x\n", 459*4667Smh27603 str, cmd)); 460*4667Smh27603 return (EPERM); 461*4667Smh27603 } else if (!(mode & FWRITE)) { 462*4667Smh27603 DPRINTF(D_IOCTL, (rwfmt, str, mode, "write")); 463*4667Smh27603 return (EPERM); 464*4667Smh27603 } 465*4667Smh27603 466*4667Smh27603 level = req.ppmop.idev_power.level; 467*4667Smh27603 if ((level != PPM_IDEV_POWER_ON) && 468*4667Smh27603 (level != PPM_IDEV_POWER_OFF)) { 469*4667Smh27603 DPRINTF(D_IOCTL, 470*4667Smh27603 ("%s: invalid power level %d, cmd 0x%x\n", 471*4667Smh27603 str, level, cmd)); 472*4667Smh27603 return (EINVAL); 473*4667Smh27603 } 474*4667Smh27603 if (ppmf.iocset == NULL) 475*4667Smh27603 return (ENOTSUP); 476*4667Smh27603 (*ppmf.iocset)(level); 477*4667Smh27603 break; 478*4667Smh27603 479*4667Smh27603 case PPMIOCGET: 480*4667Smh27603 if (!(mode & FREAD)) { 481*4667Smh27603 DPRINTF(D_IOCTL, (rwfmt, str, mode, "read")); 482*4667Smh27603 return (EPERM); 483*4667Smh27603 } 484*4667Smh27603 485*4667Smh27603 if (ppmf.iocget == NULL) 486*4667Smh27603 return (ENOTSUP); 487*4667Smh27603 req.ppmop.idev_power.level = (*ppmf.iocget)(); 488*4667Smh27603 if (ddi_copyout((const void *)&req, (void *)arg, 489*4667Smh27603 sizeof (req), mode)) { 490*4667Smh27603 DPRINTF(D_ERROR, (iofmt, str, "out", arg)); 491*4667Smh27603 return (EFAULT); 492*4667Smh27603 } 493*4667Smh27603 break; 494*4667Smh27603 495*4667Smh27603 default: 496*4667Smh27603 DPRINTF(D_IOCTL, ("%s: unrecognized cmd 0x%x\n", str, cmd)); 497*4667Smh27603 return (EINVAL); 498*4667Smh27603 } 499*4667Smh27603 500*4667Smh27603 return (0); 501*4667Smh27603 } 502*4667Smh27603 503*4667Smh27603 504*4667Smh27603 #ifdef DEBUG 505*4667Smh27603 #define FLINTSTR(flags, sym) { flags, sym, #sym } 506*4667Smh27603 #define PMR_UNKNOWN -1 507*4667Smh27603 /* 508*4667Smh27603 * convert a ctlop integer to a char string. this helps printing 509*4667Smh27603 * meaningful info when cltops are received from the pm framework. 510*4667Smh27603 * since some ctlops are so frequent, we use mask to limit output: 511*4667Smh27603 * a valid string is returned when ctlop is found and when 512*4667Smh27603 * (cmd.flags & mask) is true; otherwise NULL is returned. 513*4667Smh27603 */ 514*4667Smh27603 char * 515*4667Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask) 516*4667Smh27603 { 517*4667Smh27603 struct ctlop_cmd { 518*4667Smh27603 uint_t flags; 519*4667Smh27603 int ctlop; 520*4667Smh27603 char *str; 521*4667Smh27603 }; 522*4667Smh27603 523*4667Smh27603 struct ctlop_cmd *ccp; 524*4667Smh27603 static struct ctlop_cmd cmds[] = { 525*4667Smh27603 FLINTSTR(D_SETPWR, PMR_SET_POWER), 526*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_SUSPEND), 527*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_RESUME), 528*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER), 529*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER), 530*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER), 531*4667Smh27603 FLINTSTR(0, PMR_PPM_ATTACH), 532*4667Smh27603 FLINTSTR(0, PMR_PPM_DETACH), 533*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY), 534*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP), 535*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER), 536*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE), 537*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE), 538*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH), 539*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH), 540*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH), 541*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH), 542*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE), 543*4667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME), 544*4667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST), 545*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER), 546*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER), 547*4667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER), 548*4667Smh27603 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN), 549*4667Smh27603 }; 550*4667Smh27603 551*4667Smh27603 for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++) 552*4667Smh27603 if (ctlop == ccp->ctlop) 553*4667Smh27603 break; 554*4667Smh27603 555*4667Smh27603 if (ccp->flags & mask) 556*4667Smh27603 return (ccp->str); 557*4667Smh27603 return (NULL); 558*4667Smh27603 } 559*4667Smh27603 #endif 560