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
null_power(void)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
_nsc_power(blind_t argp,int * rvp)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
_nsc_init_power(void)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
_nsc_deinit_power(void)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
nsc_register_power(char * name,nsc_def_t * def)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
nsc_unregister_power(blind_t powerp)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