Print this page
PANKOVs restructure
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/ppm/acpippm.c
+++ new/usr/src/uts/i86pc/io/ppm/acpippm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
26 26 */
27 27
↓ open down ↓ |
27 lines elided |
↑ open up ↑ |
28 28 #include <sys/types.h>
29 29 #include <sys/conf.h>
30 30 #include <sys/open.h>
31 31 #include <sys/modctl.h>
32 32 #include <sys/promif.h>
33 33 #include <sys/stat.h>
34 34 #include <sys/ddi_impldefs.h>
35 35 #include <sys/ddi.h>
36 36 #include <sys/sunddi.h>
37 37 #include <sys/epm.h>
38 -#include <sys/acpi/acpi.h>
38 +#include <acpica/include/acpi.h>
39 39 #include <sys/acpica.h>
40 40 #include <sys/psm_types.h>
41 41
42 42 /*
43 43 * ACPI Power Management Driver
44 44 *
45 45 * acpippm deals with those bits of ppm functionality that
46 46 * must be mediated by ACPI
47 47 *
48 48 * The routines in this driver is referenced by Platform
49 49 * Power Management driver of X86 workstation systems.
50 50 * acpippm driver is loaded because it is listed as a platform driver
51 51 * It is initially configured as a pseudo driver.
52 52 */
53 53 extern void pc_tod_set_rtc_offsets(ACPI_TABLE_FADT *);
54 54 extern int acpica_use_safe_delay;
55 55
56 56 /*
57 57 * Configuration Function prototypes and data structures
58 58 */
59 59 static int appm_attach(dev_info_t *, ddi_attach_cmd_t);
60 60 static int appm_detach(dev_info_t *, ddi_detach_cmd_t);
61 61 static int appm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
62 62 static int appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
63 63 static int appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
64 64 static int appm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
65 65
66 66 /*
67 67 * Configuration data structures
68 68 */
69 69 static struct cb_ops appm_cbops = {
70 70 appm_open, /* open */
71 71 appm_close, /* close */
72 72 nodev, /* strategy */
73 73 nodev, /* print */
74 74 nodev, /* dump */
75 75 nodev, /* read */
76 76 nodev, /* write */
77 77 appm_ioctl, /* ioctl */
78 78 nodev, /* devmap */
79 79 nodev, /* mmap */
80 80 nodev, /* segmap */
81 81 nochpoll, /* chpoll */
82 82 ddi_prop_op, /* prop_op */
83 83 NULL, /* stream */
84 84 D_MP | D_NEW, /* flag */
85 85 CB_REV, /* rev */
86 86 nodev, /* aread */
87 87 nodev, /* awrite */
88 88 };
89 89
90 90 static struct dev_ops appm_ops = {
91 91 DEVO_REV, /* devo_rev */
92 92 0, /* refcnt */
93 93 appm_getinfo, /* getinfo */
94 94 nulldev, /* identify */
95 95 nulldev, /* probe */
96 96 appm_attach, /* attach */
97 97 appm_detach, /* detach */
98 98 nodev, /* reset */
99 99 &appm_cbops, /* cb_ops */
100 100 NULL, /* bus_ops */
101 101 NULL, /* power */
102 102 ddi_quiesce_not_needed, /* quiesce */
103 103 };
104 104
105 105 extern struct mod_ops mod_driverops;
106 106
107 107 static struct modldrv modldrv = {
108 108 &mod_driverops,
109 109 "ACPI ppm driver",
110 110 &appm_ops,
111 111 };
112 112
113 113 static struct modlinkage modlinkage = {
114 114 MODREV_1,
115 115 &modldrv,
116 116 NULL
117 117 };
118 118
119 119 /*
120 120 * Driver state structure
121 121 */
122 122 typedef struct {
123 123 dev_info_t *dip;
124 124 ddi_acc_handle_t devid_hndl;
125 125 ddi_acc_handle_t estar_hndl;
126 126 int lyropen; /* ref count */
127 127 } appm_unit;
128 128
129 129 /*
130 130 * Driver global variables
131 131 *
132 132 * appm_lock synchronize the access of lyr handle to each appm
133 133 * minor device, therefore write to tomatillo device is
134 134 * sequentialized. Lyr protocol requires pairing up lyr open
135 135 * and close, so only a single reference is allowed per minor node.
136 136 */
137 137 static void *appm_statep;
138 138 static kmutex_t appm_lock;
139 139
140 140 /*
141 141 * S3 stuff:
142 142 */
143 143 extern int acpi_enter_sleepstate(s3a_t *);
144 144 extern int acpi_exit_sleepstate(s3a_t *);
145 145
146 146
147 147 int
148 148 _init(void)
149 149 {
150 150 int error;
151 151
152 152 if ((error = ddi_soft_state_init(&appm_statep,
153 153 sizeof (appm_unit), 0)) != DDI_SUCCESS) {
154 154 return (error);
155 155 }
156 156
157 157 mutex_init(&appm_lock, NULL, MUTEX_DRIVER, NULL);
158 158
159 159 if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) {
160 160 mutex_destroy(&appm_lock);
161 161 ddi_soft_state_fini(&appm_statep);
162 162 return (error);
163 163 }
164 164
165 165 return (error);
166 166 }
167 167
168 168 int
169 169 _fini(void)
170 170 {
171 171 int error;
172 172
173 173 if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) {
174 174 mutex_destroy(&appm_lock);
175 175 ddi_soft_state_fini(&appm_statep);
176 176 }
177 177
178 178 return (error);
179 179
180 180 }
181 181
182 182 int
183 183 _info(struct modinfo *modinfop)
184 184 {
185 185 return (mod_info(&modlinkage, modinfop));
186 186 }
187 187
188 188
189 189
190 190 /*
191 191 * Driver attach(9e) entry point
192 192 */
193 193 static int
194 194 appm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
195 195 {
196 196 char *str = "appm_attach";
197 197 int instance;
198 198 appm_unit *unitp;
199 199 ACPI_TABLE_FADT *fadt = NULL;
200 200 int rv = DDI_SUCCESS;
201 201
202 202 switch (cmd) {
203 203 case DDI_ATTACH:
204 204 break;
205 205 case DDI_RESUME:
206 206 return (DDI_SUCCESS);
207 207 default:
208 208 cmn_err(CE_WARN, "%s: cmd %d unsupported.\n", str, cmd);
209 209 return (DDI_FAILURE);
210 210 }
211 211
212 212 instance = ddi_get_instance(dip);
213 213 rv = ddi_soft_state_zalloc(appm_statep, instance);
214 214 if (rv != DDI_SUCCESS) {
215 215 cmn_err(CE_WARN, "%s: failed alloc for dev(%s@%s)",
216 216 str, ddi_binding_name(dip),
217 217 ddi_get_name_addr(dip) ? ddi_get_name_addr(dip) : " ");
218 218 return (rv);
219 219 }
220 220
221 221 if ((unitp = ddi_get_soft_state(appm_statep, instance)) == NULL) {
222 222 rv = DDI_FAILURE;
223 223 goto doerrs;
224 224 }
225 225
226 226 /*
227 227 * Export "ddi-kernel-ioctl" property - prepared to support
228 228 * kernel ioctls (driver layering).
229 229 * XXX is this still needed?
230 230 * XXXX (RSF) Not that I am aware of.
231 231 */
232 232 rv = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
233 233 DDI_KERNEL_IOCTL, NULL, 0);
234 234 if (rv != DDI_PROP_SUCCESS)
235 235 goto doerrs;
236 236
237 237 ddi_report_dev(dip);
238 238 unitp->dip = dip;
239 239
240 240 /*
241 241 * XXX here we would do whatever we need to to determine if the
242 242 * XXX platform supports ACPI, and fail the attach if not.
243 243 * XXX If it does, we do whatever setup is needed to get access to
244 244 * XXX ACPI register space.
245 245 */
246 246
247 247 unitp->lyropen = 0;
248 248
249 249 /*
250 250 * create minor node for kernel_ioctl calls
251 251 */
252 252 rv = ddi_create_minor_node(dip, "acpi-ppm", S_IFCHR, instance, 0, 0);
253 253 if (rv != DDI_SUCCESS)
254 254 goto doerrs;
255 255
256 256 /* Get the FADT */
257 257 if (AcpiGetTable(ACPI_SIG_FADT, 1,
258 258 (ACPI_TABLE_HEADER **)&fadt) != AE_OK)
259 259 return (rv);
260 260
261 261 /* Init the RTC offsets */
262 262 if (fadt != NULL)
263 263 pc_tod_set_rtc_offsets(fadt);
264 264
265 265 return (rv);
266 266
267 267 doerrs:
268 268
269 269 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
270 270 DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL))
271 271 ddi_prop_remove_all(dip);
272 272
273 273 ddi_soft_state_free(appm_statep, instance);
274 274
275 275 return (rv);
276 276 }
277 277
278 278
279 279 /*
280 280 * Driver getinfo(9e) entry routine
281 281 */
282 282 /* ARGSUSED */
283 283 static int
284 284 appm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
285 285 {
286 286 appm_unit *unitp;
287 287 int instance;
288 288
289 289 switch (cmd) {
290 290 case DDI_INFO_DEVT2DEVINFO:
291 291 instance = getminor((dev_t)arg);
292 292 unitp = ddi_get_soft_state(appm_statep, instance);
293 293 if (unitp == NULL) {
294 294 return (DDI_FAILURE);
295 295 }
296 296 *result = (void *) unitp->dip;
297 297 return (DDI_SUCCESS);
298 298
299 299 case DDI_INFO_DEVT2INSTANCE:
300 300 instance = getminor((dev_t)arg);
301 301 *result = (void *)(uintptr_t)instance;
302 302 return (DDI_SUCCESS);
303 303
304 304 default:
305 305 return (DDI_FAILURE);
306 306 }
307 307 }
308 308
309 309
310 310 /*
311 311 * detach(9e)
312 312 */
313 313 /* ARGSUSED */
314 314 static int
315 315 appm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
316 316 {
317 317 char *str = "appm_detach";
318 318
319 319 switch (cmd) {
320 320 case DDI_DETACH:
321 321 return (DDI_FAILURE);
322 322 case DDI_SUSPEND:
323 323 return (DDI_SUCCESS);
324 324 default:
325 325 cmn_err(CE_WARN, "%s: cmd %d unsupported", str, cmd);
326 326 return (DDI_FAILURE);
327 327 }
328 328 }
329 329
330 330
331 331 /* ARGSUSED */
332 332 static int
333 333 appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
334 334 {
335 335 appm_unit *unitp;
336 336
337 337 /* not intended to allow sysadmin level root process to open it */
338 338 if (drv_priv(cred_p) != DDI_SUCCESS)
339 339 return (EPERM);
340 340
341 341 if ((unitp = ddi_get_soft_state(
342 342 appm_statep, getminor(*dev_p))) == NULL) {
343 343 cmn_err(CE_WARN, "appm_open: failed to get soft state!");
344 344 return (DDI_FAILURE);
345 345 }
346 346
347 347 mutex_enter(&appm_lock);
348 348 if (unitp->lyropen != 0) {
349 349 mutex_exit(&appm_lock);
350 350 return (EBUSY);
351 351 }
352 352 unitp->lyropen++;
353 353 mutex_exit(&appm_lock);
354 354
355 355 return (DDI_SUCCESS);
356 356 }
357 357
358 358
359 359 /* ARGSUSED */
360 360 static int
361 361 appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
362 362 {
363 363 appm_unit *unitp;
364 364
365 365 if ((unitp =
366 366 ddi_get_soft_state(appm_statep, getminor(dev))) == NULL)
367 367 return (DDI_FAILURE);
368 368
369 369 mutex_enter(&appm_lock);
370 370 unitp->lyropen = 0;
371 371 mutex_exit(&appm_lock);
372 372
373 373 return (DDI_SUCCESS);
374 374 }
375 375
376 376
377 377 /*
378 378 * must match ppm.conf
379 379 */
380 380 #define APPMIOC ('A' << 8)
381 381 #define APPMIOC_ENTER_S3 (APPMIOC | 1) /* arg *s3a_t */
382 382 #define APPMIOC_EXIT_S3 (APPMIOC | 2) /* arg *s3a_t */
383 383
384 384 /* ARGSUSED3 */
385 385 static int
386 386 appm_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
387 387 cred_t *cred_p, int *rval_p)
388 388 {
389 389 static boolean_t acpi_initted = B_FALSE;
390 390 char *str = "appm_ioctl";
391 391 int ret;
392 392 s3a_t *s3ap = (s3a_t *)arg;
393 393
394 394 PMD(PMD_SX, ("%s: called with %x\n", str, cmd))
395 395
396 396 if (drv_priv(cred_p) != 0) {
397 397 PMD(PMD_SX, ("%s: EPERM\n", str))
398 398 return (EPERM);
399 399 }
400 400
401 401 if (ddi_get_soft_state(appm_statep, getminor(dev)) == NULL) {
402 402 PMD(PMD_SX, ("%s: no soft state: EIO\n", str))
403 403 return (EIO);
404 404 }
405 405
406 406 if (!acpi_initted) {
407 407 PMD(PMD_SX, ("%s: !acpi_initted\n", str))
408 408 if (acpica_init() == 0) {
409 409 acpi_initted = B_TRUE;
410 410 } else {
411 411 if (rval_p != NULL) {
412 412 *rval_p = EINVAL;
413 413 }
414 414 PMD(PMD_SX, ("%s: EINVAL\n", str))
415 415 return (EINVAL);
416 416 }
417 417 }
418 418
419 419 PMD(PMD_SX, ("%s: looking for cmd %x\n", str, cmd))
420 420 switch (cmd) {
421 421 case APPMIOC_ENTER_S3:
422 422 /*
423 423 * suspend to RAM (ie S3)
424 424 */
425 425 PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
426 426 acpica_use_safe_delay = 1;
427 427 ret = acpi_enter_sleepstate(s3ap);
428 428 break;
429 429
430 430 case APPMIOC_EXIT_S3:
431 431 /*
432 432 * return from S3
433 433 */
434 434 PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
435 435 ret = acpi_exit_sleepstate(s3ap);
436 436 acpica_use_safe_delay = 0;
437 437 break;
438 438
439 439 default:
440 440 PMD(PMD_SX, ("%s: cmd %x unrecognized: ENOTTY\n", str, cmd))
441 441 return (ENOTTY);
442 442 }
443 443
444 444 /*
445 445 * upon failure return EINVAL
446 446 */
447 447 if (ret != 0) {
448 448 if (rval_p != NULL) {
449 449 *rval_p = EINVAL;
450 450 }
451 451 return (EINVAL);
452 452 }
453 453
454 454 return (0);
455 455 }
↓ open down ↓ |
407 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX