14667Smh27603 /*
24667Smh27603 * CDDL HEADER START
34667Smh27603 *
44667Smh27603 * The contents of this file are subject to the terms of the
54667Smh27603 * Common Development and Distribution License (the "License").
64667Smh27603 * You may not use this file except in compliance with the License.
74667Smh27603 *
84667Smh27603 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94667Smh27603 * or http://www.opensolaris.org/os/licensing.
104667Smh27603 * See the License for the specific language governing permissions
114667Smh27603 * and limitations under the License.
124667Smh27603 *
134667Smh27603 * When distributing Covered Code, include this CDDL HEADER in each
144667Smh27603 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154667Smh27603 * If applicable, add the following below this CDDL HEADER, with the
164667Smh27603 * fields enclosed by brackets "[]" replaced with your own identifying
174667Smh27603 * information: Portions Copyright [yyyy] [name of copyright owner]
184667Smh27603 *
194667Smh27603 * CDDL HEADER END
204667Smh27603 */
21*11311SSurya.Prakki@Sun.COM
224667Smh27603 /*
23*11311SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
244667Smh27603 * Use is subject to license terms.
254667Smh27603 */
264667Smh27603
274667Smh27603 /*
284667Smh27603 * common code for ppm drivers
294667Smh27603 */
304667Smh27603 #include <sys/modctl.h>
314667Smh27603 #include <sys/ddi.h>
324667Smh27603 #include <sys/sunddi.h>
334667Smh27603 #include <sys/ddi_impldefs.h>
344667Smh27603 #include <sys/ppmvar.h>
354667Smh27603 #include <sys/ppmio.h>
364667Smh27603 #include <sys/epm.h>
374667Smh27603 #include <sys/open.h>
384667Smh27603 #include <sys/file.h>
394667Smh27603 #include <sys/policy.h>
404667Smh27603
414667Smh27603
424667Smh27603 #ifdef DEBUG
434667Smh27603 uint_t ppm_debug = 0;
444667Smh27603 #endif
454667Smh27603
464667Smh27603 int ppm_inst = -1;
474667Smh27603 char *ppm_prefix;
484667Smh27603 void *ppm_statep;
494667Smh27603
504667Smh27603
514667Smh27603 /*
524667Smh27603 * common module _init
534667Smh27603 */
544667Smh27603 int
ppm_init(struct modlinkage * mlp,size_t size,char * prefix)554667Smh27603 ppm_init(struct modlinkage *mlp, size_t size, char *prefix)
564667Smh27603 {
574667Smh27603 #ifdef DEBUG
584667Smh27603 char *str = "ppm_init";
594667Smh27603 #endif
604667Smh27603 int error;
614667Smh27603
624667Smh27603 ppm_prefix = prefix;
634667Smh27603
644667Smh27603 error = ddi_soft_state_init(&ppm_statep, size, 1);
654667Smh27603 DPRINTF(D_INIT, ("%s: ss init %d\n", str, error));
664667Smh27603 if (error != DDI_SUCCESS)
674667Smh27603 return (error);
684667Smh27603
694667Smh27603 if (error = mod_install(mlp))
704667Smh27603 ddi_soft_state_fini(&ppm_statep);
714667Smh27603 DPRINTF(D_INIT, ("%s: mod_install %d\n", str, error));
724667Smh27603
734667Smh27603 return (error);
744667Smh27603 }
754667Smh27603
764667Smh27603
774667Smh27603 /* ARGSUSED */
784667Smh27603 int
ppm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)794667Smh27603 ppm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
804667Smh27603 {
814667Smh27603 struct ppm_unit *overlay;
824667Smh27603 int rval;
834667Smh27603
844667Smh27603 if (ppm_inst == -1)
854667Smh27603 return (DDI_FAILURE);
864667Smh27603
874667Smh27603 switch (cmd) {
884667Smh27603 case DDI_INFO_DEVT2DEVINFO:
894667Smh27603 if (overlay = ddi_get_soft_state(ppm_statep, ppm_inst)) {
904667Smh27603 *resultp = overlay->dip;
914667Smh27603 rval = DDI_SUCCESS;
924667Smh27603 } else
934667Smh27603 rval = DDI_FAILURE;
944667Smh27603 return (rval);
954667Smh27603
964667Smh27603 case DDI_INFO_DEVT2INSTANCE:
974667Smh27603 *resultp = (void *)(uintptr_t)ppm_inst;
984667Smh27603 return (DDI_SUCCESS);
994667Smh27603
1004667Smh27603 default:
1014667Smh27603 return (DDI_FAILURE);
1024667Smh27603 }
1034667Smh27603 }
1044667Smh27603
1054667Smh27603
1064667Smh27603 /* ARGSUSED */
1074667Smh27603 int
ppm_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)1084667Smh27603 ppm_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
1094667Smh27603 {
1104667Smh27603 if (otyp != OTYP_CHR)
1114667Smh27603 return (EINVAL);
1124667Smh27603 DPRINTF(D_OPEN, ("ppm_open: \"%s\", devp 0x%p, flag 0x%x, otyp %d\n",
113*11311SSurya.Prakki@Sun.COM ppm_prefix, (void *)devp, flag, otyp));
1144667Smh27603 return (0);
1154667Smh27603 }
1164667Smh27603
1174667Smh27603
1184667Smh27603 /* ARGSUSED */
1194667Smh27603 int
ppm_close(dev_t dev,int flag,int otyp,cred_t * credp)1204667Smh27603 ppm_close(dev_t dev, int flag, int otyp, cred_t *credp)
1214667Smh27603 {
1224667Smh27603 DPRINTF(D_CLOSE, ("ppm_close: \"%s\", dev 0x%lx, flag 0x%x, otyp %d\n",
1234667Smh27603 ppm_prefix, dev, flag, otyp));
1244667Smh27603 return (DDI_SUCCESS);
1254667Smh27603 }
1264667Smh27603
1274667Smh27603
1284667Smh27603 /*
1294667Smh27603 * lookup arrays of strings from configuration data (XXppm.conf)
1304667Smh27603 */
1314667Smh27603 static int
ppm_get_confdata(struct ppm_cdata ** cdp,dev_info_t * dip)1324667Smh27603 ppm_get_confdata(struct ppm_cdata **cdp, dev_info_t *dip)
1334667Smh27603 {
1344667Smh27603 struct ppm_cdata *cinfo;
1354667Smh27603 int err;
1364667Smh27603
1374667Smh27603 for (; (cinfo = *cdp) != NULL; cdp++) {
1384667Smh27603 err = ddi_prop_lookup_string_array(
1394667Smh27603 DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1404667Smh27603 cinfo->name, &cinfo->strings, &cinfo->cnt);
1414667Smh27603 if (err != DDI_PROP_SUCCESS) {
1424667Smh27603 DPRINTF(D_ERROR,
1434667Smh27603 ("ppm_get_confdata: no %s found\n", cinfo->name));
1444667Smh27603 break;
1454667Smh27603 }
1464667Smh27603 }
1474667Smh27603 return (err);
1484667Smh27603 }
1494667Smh27603
1504667Smh27603
1514667Smh27603 /*
1524667Smh27603 * free allocated ddi prop strings, and free
1534667Smh27603 * ppm_db_t lists where there's an error.
1544667Smh27603 */
1554667Smh27603 static int
ppm_attach_err(struct ppm_cdata ** cdp,int err)1564667Smh27603 ppm_attach_err(struct ppm_cdata **cdp, int err)
1574667Smh27603 {
1584667Smh27603 ppm_domain_t **dompp;
1594667Smh27603 ppm_db_t *db, *tmp;
1604667Smh27603
1614667Smh27603 if (cdp) {
1624667Smh27603 for (; *cdp; cdp++) {
1634667Smh27603 if ((*cdp)->strings) {
1644667Smh27603 ddi_prop_free((*cdp)->strings);
1654667Smh27603 (*cdp)->strings = NULL;
1664667Smh27603 }
1674667Smh27603 }
1684667Smh27603 }
1694667Smh27603
1704667Smh27603 if (err != DDI_SUCCESS) {
1714667Smh27603 for (dompp = ppm_domains; *dompp; dompp++) {
1724667Smh27603 for (db = (*dompp)->conflist; (tmp = db) != NULL; ) {
1734667Smh27603 db = db->next;
1744667Smh27603 kmem_free(tmp->name, strlen(tmp->name) + 1);
1754667Smh27603 kmem_free(tmp, sizeof (*tmp));
1764667Smh27603 }
1774667Smh27603 (*dompp)->conflist = NULL;
1784667Smh27603 }
1794667Smh27603 err = DDI_FAILURE;
1804667Smh27603 }
1814667Smh27603
1824667Smh27603 return (err);
1834667Smh27603 }
1844667Smh27603
1854667Smh27603
1864667Smh27603 ppm_domain_t *
ppm_lookup_domain(char * dname)1874667Smh27603 ppm_lookup_domain(char *dname)
1884667Smh27603 {
1894667Smh27603 ppm_domain_t **dompp;
1904667Smh27603
1914667Smh27603 for (dompp = ppm_domains; *dompp; dompp++)
1924667Smh27603 if (strcmp(dname, (*dompp)->name) == 0)
1934667Smh27603 break;
1944667Smh27603 return (*dompp);
1954667Smh27603 }
1964667Smh27603
1974667Smh27603
1984667Smh27603 /*
1994667Smh27603 * create a ppm-private database from parsed .conf data; we start with
2004667Smh27603 * two string arrays (device pathnames and domain names) and treat them
2014667Smh27603 * as matched pairs where device[N] is part of domain[N]
2024667Smh27603 */
2034667Smh27603 int
ppm_create_db(dev_info_t * dip)2044667Smh27603 ppm_create_db(dev_info_t *dip)
2054667Smh27603 {
2064667Smh27603 #ifdef DEBUG
2074667Smh27603 char *str = "ppm_create_db";
2084667Smh27603 #endif
2094667Smh27603 struct ppm_cdata devdata, domdata, *cdata[3];
2104667Smh27603 ppm_domain_t *domp;
2114667Smh27603 ppm_db_t *new;
2124667Smh27603 char **dev_namep, **dom_namep;
2134667Smh27603 char *wild;
2144667Smh27603 int err;
2154667Smh27603
2164667Smh27603 bzero(&devdata, sizeof (devdata));
2174667Smh27603 bzero(&domdata, sizeof (domdata));
2184667Smh27603 devdata.name = "ppm-devices";
2194667Smh27603 domdata.name = "ppm-domains";
2204667Smh27603 cdata[0] = &devdata;
2214667Smh27603 cdata[1] = &domdata;
2224667Smh27603 cdata[2] = NULL;
2234667Smh27603 if (err = ppm_get_confdata(cdata, dip))
2244667Smh27603 return (ppm_attach_err(cdata, err));
2254667Smh27603 else if (devdata.cnt != domdata.cnt) {
2264667Smh27603 DPRINTF(D_ERROR,
2274667Smh27603 ("%s: %sppm.conf has a mismatched number of %s and %s\n",
2284667Smh27603 str, ppm_prefix, devdata.name, domdata.name));
2294667Smh27603 return (ppm_attach_err(cdata, DDI_FAILURE));
2304667Smh27603 }
2314667Smh27603
2324667Smh27603 /*
2334667Smh27603 * loop through device/domain pairs and build
2344667Smh27603 * a linked list of devices within known domains
2354667Smh27603 */
2364667Smh27603 for (dev_namep = devdata.strings, dom_namep = domdata.strings;
2374667Smh27603 *dev_namep; dev_namep++, dom_namep++) {
2384667Smh27603 domp = ppm_lookup_domain(*dom_namep);
2394667Smh27603 if (domp == NULL) {
2404667Smh27603 DPRINTF(D_ERROR, ("%s: invalid domain \"%s\" for "
2414667Smh27603 "device \"%s\"\n", str, *dom_namep, *dev_namep));
2424667Smh27603 return (ppm_attach_err(cdata, DDI_FAILURE));
2434667Smh27603 }
2444667Smh27603
2454667Smh27603 /*
2464667Smh27603 * allocate a new ppm db entry and link it to
2474667Smh27603 * the front of conflist within this domain
2484667Smh27603 */
2494667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
2504667Smh27603 new->name = kmem_zalloc(strlen(*dev_namep) + 1, KM_SLEEP);
2514667Smh27603 (void) strcpy(new->name, *dev_namep);
2524667Smh27603 new->next = domp->conflist;
2534667Smh27603 domp->conflist = new;
2544667Smh27603
2554667Smh27603 /*
2564667Smh27603 * when the device name contains a wildcard,
2574667Smh27603 * save the length of the preceding string
2584667Smh27603 */
2594667Smh27603 if (wild = strchr(new->name, '*'))
2604667Smh27603 new->plen = (wild - new->name);
2614667Smh27603 DPRINTF(D_CREATEDB, ("%s: \"%s\", added \"%s\"\n",
2624667Smh27603 str, domp->name, new->name));
2634667Smh27603 }
2644667Smh27603
2654667Smh27603 return (ppm_attach_err(cdata, DDI_SUCCESS));
2664667Smh27603 }
2674667Smh27603
2684667Smh27603
2694667Smh27603 /*
2704667Smh27603 * scan conf devices within each domain for a matching device name
2714667Smh27603 */
2724667Smh27603 ppm_domain_t *
ppm_lookup_dev(dev_info_t * dip)2734667Smh27603 ppm_lookup_dev(dev_info_t *dip)
2744667Smh27603 {
2754667Smh27603 char path[MAXNAMELEN];
2764667Smh27603 ppm_domain_t **dompp;
2774667Smh27603 ppm_db_t *dbp;
2784667Smh27603
2794667Smh27603 (void) ddi_pathname(dip, path);
2804667Smh27603 for (dompp = ppm_domains; *dompp; dompp++) {
2814667Smh27603 for (dbp = (*dompp)->conflist; dbp; dbp = dbp->next) {
2824667Smh27603 if (dbp->plen == 0) {
2834667Smh27603 if (strcmp(path, dbp->name) == 0)
2844667Smh27603 return (*dompp);
2854667Smh27603 } else if (strncmp(path, dbp->name, dbp->plen) == 0)
2864667Smh27603 return (*dompp);
2874667Smh27603 }
2884667Smh27603 }
2894667Smh27603
2904667Smh27603 return (NULL);
2914667Smh27603 }
2924667Smh27603
2934667Smh27603
2944667Smh27603 /*
2954667Smh27603 * returns 1 (claimed), 0 (not claimed)
2964667Smh27603 */
2974667Smh27603 int
ppm_claim_dev(dev_info_t * dip)2984667Smh27603 ppm_claim_dev(dev_info_t *dip)
2994667Smh27603 {
3004667Smh27603 ppm_domain_t *domp;
3014667Smh27603
3024667Smh27603 domp = ppm_lookup_dev(dip);
3034667Smh27603
3044667Smh27603 #ifdef DEBUG
3054667Smh27603 if (domp) {
3064667Smh27603 char path[MAXNAMELEN];
3074667Smh27603 DPRINTF(D_CLAIMDEV,
3084667Smh27603 ("ppm_claim_dev: \"%s\", matched \"%s\"\n",
3094667Smh27603 domp->name, ddi_pathname(dip, path)));
3104667Smh27603 }
3114667Smh27603
3124667Smh27603 #endif
3134667Smh27603
3144667Smh27603 return (domp != NULL);
3154667Smh27603 }
3164667Smh27603
3174667Smh27603
3184667Smh27603 /*
3194667Smh27603 * create/init a new ppm device and link into the domain
3204667Smh27603 */
3214667Smh27603 ppm_dev_t *
ppm_add_dev(dev_info_t * dip,ppm_domain_t * domp)3224667Smh27603 ppm_add_dev(dev_info_t *dip, ppm_domain_t *domp)
3234667Smh27603 {
3244667Smh27603 char path[MAXNAMELEN];
3254667Smh27603 ppm_dev_t *new = NULL;
3264667Smh27603 int cmpt;
3274667Smh27603
3284667Smh27603 ASSERT(MUTEX_HELD(&domp->lock));
3294667Smh27603 (void) ddi_pathname(dip, path);
3304667Smh27603 /*
3314667Smh27603 * For devs which have exported "pm-components" we want to create
3324667Smh27603 * a data structure for each component. When a driver chooses not
3334667Smh27603 * to export the prop we treat its device as having a single
3344667Smh27603 * component and build a structure for it anyway. All other ppm
3354667Smh27603 * logic will act as if this device were always up and can thus
3364667Smh27603 * make correct decisions about it in relation to other devices
3374667Smh27603 * in its domain.
3384667Smh27603 */
3394667Smh27603 for (cmpt = PM_GET_PM_INFO(dip) ? PM_NUMCMPTS(dip) : 1; cmpt--; ) {
3404667Smh27603 new = kmem_zalloc(sizeof (*new), KM_SLEEP);
3414667Smh27603 new->path = kmem_zalloc(strlen(path) + 1, KM_SLEEP);
3424667Smh27603 (void) strcpy(new->path, path);
3434667Smh27603 new->domp = domp;
3444667Smh27603 new->dip = dip;
3454667Smh27603 new->cmpt = cmpt;
3464667Smh27603 if (ppmf.dev_init)
3474667Smh27603 (*ppmf.dev_init)(new);
3484667Smh27603 new->next = domp->devlist;
3494667Smh27603 domp->devlist = new;
3504667Smh27603 DPRINTF(D_ADDDEV,
3514667Smh27603 ("ppm_add_dev: \"%s\", \"%s\", ppm_dev 0x%p\n",
352*11311SSurya.Prakki@Sun.COM new->path, domp->name, (void *)new));
3534667Smh27603 }
3544667Smh27603
3554667Smh27603 ASSERT(new != NULL);
3564667Smh27603 /*
3574667Smh27603 * devi_pm_ppm_private should be set only after all
3584667Smh27603 * ppm_dev s related to all components have been
3594667Smh27603 * initialized and domain's pwr_cnt is incremented
3604667Smh27603 * for each of them.
3614667Smh27603 */
3624667Smh27603 PPM_SET_PRIVATE(dip, new);
3634667Smh27603
3644667Smh27603 return (new);
3654667Smh27603 }
3664667Smh27603
3674667Smh27603
3684667Smh27603 /*
3694667Smh27603 * returns an existing or newly created ppm device reference
3704667Smh27603 */
3714667Smh27603 ppm_dev_t *
ppm_get_dev(dev_info_t * dip,ppm_domain_t * domp)3724667Smh27603 ppm_get_dev(dev_info_t *dip, ppm_domain_t *domp)
3734667Smh27603 {
3744667Smh27603 ppm_dev_t *pdp;
3754667Smh27603
3764667Smh27603 mutex_enter(&domp->lock);
3774667Smh27603 pdp = PPM_GET_PRIVATE(dip);
3784667Smh27603 if (pdp == NULL)
3794667Smh27603 pdp = ppm_add_dev(dip, domp);
3804667Smh27603 mutex_exit(&domp->lock);
3814667Smh27603
3824667Smh27603 return (pdp);
3834667Smh27603 }
3844667Smh27603
3854667Smh27603
3864667Smh27603 /*
3874667Smh27603 * scan a domain's device list and remove those with .dip
3884667Smh27603 * matching the arg *dip; we need to scan the entire list
3894667Smh27603 * for the case of devices with multiple components
3904667Smh27603 */
3914667Smh27603 void
ppm_rem_dev(dev_info_t * dip)3924667Smh27603 ppm_rem_dev(dev_info_t *dip)
3934667Smh27603 {
3944667Smh27603 ppm_dev_t *pdp, **devpp;
3954667Smh27603 ppm_domain_t *domp;
3964667Smh27603
3974667Smh27603 pdp = PPM_GET_PRIVATE(dip);
3984667Smh27603 ASSERT(pdp);
3994667Smh27603 domp = pdp->domp;
4004667Smh27603 ASSERT(domp);
4014667Smh27603
4024667Smh27603 mutex_enter(&domp->lock);
4034667Smh27603 for (devpp = &domp->devlist; (pdp = *devpp) != NULL; ) {
4044667Smh27603 if (pdp->dip != dip) {
4054667Smh27603 devpp = &pdp->next;
4064667Smh27603 continue;
4074667Smh27603 }
4084667Smh27603
4094667Smh27603 DPRINTF(D_REMDEV, ("ppm_rem_dev: path \"%s\", ppm_dev 0x%p\n",
410*11311SSurya.Prakki@Sun.COM pdp->path, (void *)pdp));
4114667Smh27603
4124667Smh27603 PPM_SET_PRIVATE(dip, NULL);
4134667Smh27603 *devpp = pdp->next;
4144667Smh27603 if (ppmf.dev_fini)
4154667Smh27603 (*ppmf.dev_fini)(pdp);
4164667Smh27603 kmem_free(pdp->path, strlen(pdp->path) + 1);
4174667Smh27603 kmem_free(pdp, sizeof (*pdp));
4184667Smh27603 }
4194667Smh27603 mutex_exit(&domp->lock);
4204667Smh27603 }
4214667Smh27603
4224667Smh27603
4234667Smh27603 /* ARGSUSED */
4244667Smh27603 int
ppm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)4254667Smh27603 ppm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
4264667Smh27603 cred_t *cred_p, int *rval_p)
4274667Smh27603 {
4284667Smh27603 #ifdef DEBUG
4294667Smh27603 char *str = "ppm_ioctl";
4304667Smh27603 char *rwfmt = "%s: mode error: 0x%x is missing %s perm, cmd 0x%x\n";
4314667Smh27603 char *iofmt = "%s: copy%s error, arg 0x%p\n";
4324667Smh27603 #endif
4334667Smh27603 ppmreq_t req;
4344667Smh27603 uint8_t level;
4354667Smh27603
4364667Smh27603 DPRINTF(D_IOCTL, ("%s: dev 0x%lx, cmd 0x%x, arg 0x%lx, mode 0x%x\n",
4374667Smh27603 str, dev, cmd, arg, mode));
4384667Smh27603
4394667Smh27603 if (ddi_copyin((caddr_t)arg, &req, sizeof (req), mode)) {
4404667Smh27603 DPRINTF(D_IOCTL, (iofmt, str, "in", arg));
4414667Smh27603 return (EFAULT);
4424667Smh27603 }
4434667Smh27603
4444667Smh27603 /*
4454667Smh27603 * Currently, only PPM_INTERNAL_DEVICE_POWER device type is supported
4464667Smh27603 */
4474667Smh27603 if (req.ppmdev != PPM_INTERNAL_DEVICE_POWER) {
4484667Smh27603 DPRINTF(D_IOCTL, ("%s: unrecognized device type %d\n",
4494667Smh27603 str, req.ppmdev));
4504667Smh27603 return (EINVAL);
4514667Smh27603 }
4524667Smh27603
4534667Smh27603 switch (cmd) {
4544667Smh27603 case PPMIOCSET:
4554667Smh27603 if (secpolicy_power_mgmt(cred_p) != 0) {
4564667Smh27603 DPRINTF(D_IOCTL, ("%s: bad cred for cmd 0x%x\n",
4574667Smh27603 str, cmd));
4584667Smh27603 return (EPERM);
4594667Smh27603 } else if (!(mode & FWRITE)) {
4604667Smh27603 DPRINTF(D_IOCTL, (rwfmt, str, mode, "write"));
4614667Smh27603 return (EPERM);
4624667Smh27603 }
4634667Smh27603
4644667Smh27603 level = req.ppmop.idev_power.level;
4654667Smh27603 if ((level != PPM_IDEV_POWER_ON) &&
4664667Smh27603 (level != PPM_IDEV_POWER_OFF)) {
4674667Smh27603 DPRINTF(D_IOCTL,
4684667Smh27603 ("%s: invalid power level %d, cmd 0x%x\n",
4694667Smh27603 str, level, cmd));
4704667Smh27603 return (EINVAL);
4714667Smh27603 }
4724667Smh27603 if (ppmf.iocset == NULL)
4734667Smh27603 return (ENOTSUP);
4744667Smh27603 (*ppmf.iocset)(level);
4754667Smh27603 break;
4764667Smh27603
4774667Smh27603 case PPMIOCGET:
4784667Smh27603 if (!(mode & FREAD)) {
4794667Smh27603 DPRINTF(D_IOCTL, (rwfmt, str, mode, "read"));
4804667Smh27603 return (EPERM);
4814667Smh27603 }
4824667Smh27603
4834667Smh27603 if (ppmf.iocget == NULL)
4844667Smh27603 return (ENOTSUP);
4854667Smh27603 req.ppmop.idev_power.level = (*ppmf.iocget)();
4864667Smh27603 if (ddi_copyout((const void *)&req, (void *)arg,
4874667Smh27603 sizeof (req), mode)) {
4884667Smh27603 DPRINTF(D_ERROR, (iofmt, str, "out", arg));
4894667Smh27603 return (EFAULT);
4904667Smh27603 }
4914667Smh27603 break;
4924667Smh27603
4934667Smh27603 default:
4944667Smh27603 DPRINTF(D_IOCTL, ("%s: unrecognized cmd 0x%x\n", str, cmd));
4954667Smh27603 return (EINVAL);
4964667Smh27603 }
4974667Smh27603
4984667Smh27603 return (0);
4994667Smh27603 }
5004667Smh27603
5014667Smh27603
5024667Smh27603 #ifdef DEBUG
5034667Smh27603 #define FLINTSTR(flags, sym) { flags, sym, #sym }
5044667Smh27603 #define PMR_UNKNOWN -1
5054667Smh27603 /*
5064667Smh27603 * convert a ctlop integer to a char string. this helps printing
5074667Smh27603 * meaningful info when cltops are received from the pm framework.
5084667Smh27603 * since some ctlops are so frequent, we use mask to limit output:
5094667Smh27603 * a valid string is returned when ctlop is found and when
5104667Smh27603 * (cmd.flags & mask) is true; otherwise NULL is returned.
5114667Smh27603 */
5124667Smh27603 char *
ppm_get_ctlstr(int ctlop,uint_t mask)5134667Smh27603 ppm_get_ctlstr(int ctlop, uint_t mask)
5144667Smh27603 {
5154667Smh27603 struct ctlop_cmd {
5164667Smh27603 uint_t flags;
5174667Smh27603 int ctlop;
5184667Smh27603 char *str;
5194667Smh27603 };
5204667Smh27603
5214667Smh27603 struct ctlop_cmd *ccp;
5224667Smh27603 static struct ctlop_cmd cmds[] = {
5234667Smh27603 FLINTSTR(D_SETPWR, PMR_SET_POWER),
5244667Smh27603 FLINTSTR(D_CTLOPS2, PMR_SUSPEND),
5254667Smh27603 FLINTSTR(D_CTLOPS2, PMR_RESUME),
5264667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PRE_SET_POWER),
5274667Smh27603 FLINTSTR(D_CTLOPS2, PMR_POST_SET_POWER),
5284667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_SET_POWER),
5294667Smh27603 FLINTSTR(0, PMR_PPM_ATTACH),
5304667Smh27603 FLINTSTR(0, PMR_PPM_DETACH),
5314667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_POWER_CHANGE_NOTIFY),
5324667Smh27603 FLINTSTR(D_CTLOPS1, PMR_REPORT_PMCAP),
5334667Smh27603 FLINTSTR(D_CTLOPS1, PMR_CHANGED_POWER),
5344667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_PROBE),
5354667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_PROBE),
5364667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_ATTACH),
5374667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_ATTACH),
5384667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_DETACH),
5394667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_POST_DETACH),
5404667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_UNMANAGE),
5414667Smh27603 FLINTSTR(D_CTLOPS2, PMR_PPM_PRE_RESUME),
5424667Smh27603 FLINTSTR(D_CTLOPS1, PMR_PPM_ALL_LOWEST),
5434667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_LOCK_POWER),
5444667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER),
5454667Smh27603 FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER),
5464667Smh27603 FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN),
5474667Smh27603 };
5484667Smh27603
5494667Smh27603 for (ccp = cmds; ccp->ctlop != PMR_UNKNOWN; ccp++)
5504667Smh27603 if (ctlop == ccp->ctlop)
5514667Smh27603 break;
5524667Smh27603
5534667Smh27603 if (ccp->flags & mask)
5544667Smh27603 return (ccp->str);
5554667Smh27603 return (NULL);
5564667Smh27603 }
5574667Smh27603 #endif
558