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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/ksynch.h> 28 #include <sys/kmem.h> 29 #include <sys/file.h> 30 #include <sys/errno.h> 31 #include <sys/open.h> 32 #include <sys/cred.h> 33 #include <sys/conf.h> 34 #include <sys/uio.h> 35 #include <sys/cmn_err.h> 36 37 #define __NSC_GEN__ 38 #include "nsc_dev.h" 39 #include "nsc_ioctl.h" 40 #include "nsc_power.h" 41 #include "../nsctl.h" 42 43 extern nsc_mem_t *_nsc_local_mem; 44 static int null_power(void); 45 46 47 typedef struct _nsc_power_s { 48 struct _nsc_power_s *next; /* chain */ 49 char *name; /* module name */ 50 void (*pw_power_lost)(int); /* callback power lost(rideout) */ 51 void (*pw_power_ok)(void); /* callback power ok */ 52 void (*pw_power_down)(void); 53 /* callback power down (shutdown imminent) */ 54 } _nsc_power_t; 55 56 #define _P(x) (((long)(&((_nsc_power_t *)0)->x))/sizeof (long)) 57 58 static nsc_def_t _nsc_power_def[] = { 59 "Power_Lost", (uintptr_t)null_power, _P(pw_power_lost), 60 "Power_OK", (uintptr_t)null_power, _P(pw_power_ok), 61 "Power_Down", (uintptr_t)null_power, _P(pw_power_down), 62 0, 0, 0, 63 }; 64 65 static _nsc_power_t *_power_clients; 66 static kmutex_t _power_mutex; 67 68 69 static int null_power(void) 70 /* 71 * init null_power - dummy power routine for clients that choose not 72 * to implement all the power hooks. 73 * 74 */ 75 { 76 return (0); 77 } 78 79 /* 80 * int 81 * _nsc_power 82 * Call registered clients of the generic power ioctls. 83 * 84 * Calling/Exit State: 85 * Calls all the registered clients with a message describing the 86 * current state of the power for the system. 87 */ 88 int 89 _nsc_power(blind_t argp, int *rvp) 90 { 91 nsc_power_ctl_t opc; 92 _nsc_power_t *pp; 93 94 *rvp = 0; 95 if (copyin((void *) argp, &opc, sizeof (nsc_power_ctl_t))) 96 return (EFAULT); 97 mutex_enter(&_power_mutex); 98 99 pp = _power_clients; 100 while (pp) { 101 switch ((nsc_power_ops_t)opc.msg) { 102 103 case Power_OK: 104 (*pp->pw_power_ok)(); 105 break; 106 107 case Power_Down: 108 (*pp->pw_power_down)(); 109 break; 110 111 case Power_Lost: 112 (*pp->pw_power_lost)(opc.arg1); 113 break; 114 115 default: 116 mutex_exit(&_power_mutex); 117 return (EINVAL); 118 } 119 120 pp = pp->next; 121 } 122 mutex_exit(&_power_mutex); 123 return (0); 124 } 125 126 /* 127 * int 128 * _nsc_init_power (void) 129 * Initialise power ioctl subsystem. 130 * 131 * Calling/Exit State: 132 * Called at driver initialisation time to allocate necessary 133 * data structures. 134 */ 135 int 136 _nsc_init_power(void) 137 { 138 mutex_init(&_power_mutex, NULL, MUTEX_DRIVER, NULL); 139 return (0); 140 } 141 142 /* 143 * int 144 * _nsc_deinit_power (void) 145 * Initialise power ioctl subsystem. 146 * 147 * Calling/Exit State: 148 * Called at driver initialisation time to allocate necessary 149 * data structures. 150 */ 151 int 152 _nsc_deinit_power(void) 153 { 154 _nsc_power_t *pp, *npp; 155 156 mutex_enter(&_power_mutex); 157 pp = _power_clients; 158 while (pp) { 159 npp = pp->next; 160 nsc_kmem_free(pp, sizeof (_nsc_power_t)); 161 pp = npp; 162 } 163 _power_clients = NULL; 164 mutex_exit(&_power_mutex); 165 mutex_destroy(&_power_mutex); 166 return (0); 167 } 168 169 /* 170 * blind_t 171 * nsc_register_power (char *name, nsc_def_t *def) 172 * Register an power ioctl client. 173 * 174 * Calling/Exit State: 175 * Returns a token for use in future calls to nsc_unregister_power. 176 * If a client with the same name is already registered then NULL 177 * is return to indicate failure. 178 * If registration fails NULL is returned. 179 * 180 * Description: 181 * Registers an power ioctl client for notifications during subsequent 182 * ioctl from UPS/PCU management. 183 */ 184 blind_t 185 nsc_register_power(char *name, nsc_def_t *def) 186 { 187 _nsc_power_t *entry, *pp; 188 189 190 entry = nsc_kmem_alloc(sizeof (_nsc_power_t), 0, _nsc_local_mem); 191 192 if (entry == NULL) 193 return (NULL); 194 nsc_decode_param(def, _nsc_power_def, (long *)entry); 195 196 mutex_enter(&_power_mutex); 197 198 for (pp = _power_clients; pp; pp = pp->next) { 199 if (strcmp(pp->name, name) == 0) { 200 mutex_exit(&_power_mutex); 201 nsc_kmem_free(entry, sizeof (_nsc_power_t)); 202 return (NULL); 203 } 204 } 205 entry->name = name; 206 207 entry->next = _power_clients; 208 _power_clients = entry; 209 mutex_exit(&_power_mutex); 210 return ((blind_t)entry); 211 } 212 213 /* 214 * int 215 * nsc_unregister_power (blind_t powerp) 216 * Un-register a power ioctl client. 217 * 218 * Calling/Exit State: 219 * Returns 0 on success, otherwise returns an error code. 220 * 221 * Description: 222 * The specified power ioctl client is un-registered if possible. 223 * Zero is returned on success otherwise an error code. 224 */ 225 int 226 nsc_unregister_power(blind_t powerp) 227 { 228 _nsc_power_t **xpp, *entry; 229 230 entry = (_nsc_power_t *)powerp; 231 if (entry == NULL) 232 return (EINVAL); 233 234 mutex_enter(&_power_mutex); 235 236 for (xpp = &_power_clients; *xpp; xpp = &(*xpp)->next) 237 if (*xpp == entry) 238 break; 239 240 if (*xpp == NULL) { 241 mutex_exit(&_power_mutex); 242 return (EALREADY); 243 } 244 *xpp = entry->next; 245 mutex_exit(&_power_mutex); 246 nsc_kmem_free(entry, sizeof (_nsc_power_t)); 247 248 return (0); 249 } 250