Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/power.c
+++ new/usr/src/uts/common/io/power.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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2011 Joyent, Inc. All rights reserved.
25 25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 26 */
27 27
28 28 /*
29 29 * Power Button Driver
30 30 *
31 31 * This driver handles interrupt generated by the power button on
32 32 * platforms with "power" device node which has "button" property.
33 33 * Currently, these platforms are:
34 34 *
35 35 * ACPI-enabled x86/x64 platforms
36 36 * Ultra-5_10, Ultra-80, Sun-Blade-100, Sun-Blade-150,
37 37 * Sun-Blade-1500, Sun-Blade-2500,
38 38 * Sun-Fire-V210, Sun-Fire-V240, Netra-240
39 39 *
40 40 * Only one instance is allowed to attach. In order to know when
41 41 * an application that has opened the device is going away, a new
42 42 * minor clone is created for each open(9E) request. There are
43 43 * allocations for creating minor clones between 1 and 255. The ioctl
44 44 * interface is defined by pbio(7I) and approved as part of
45 45 * PSARC/1999/393 case.
46 46 */
47 47
48 48 #include <sys/types.h>
49 49 #include <sys/conf.h>
50 50 #include <sys/ddi.h>
51 51 #include <sys/sunddi.h>
52 52 #include <sys/ddi_impldefs.h>
53 53 #include <sys/cmn_err.h>
54 54 #include <sys/errno.h>
55 55 #include <sys/modctl.h>
56 56 #include <sys/open.h>
57 57 #include <sys/stat.h>
58 58 #include <sys/poll.h>
59 59 #include <sys/pbio.h>
60 60 #include <sys/sysevent/eventdefs.h>
61 61 #include <sys/sysevent/pwrctl.h>
62 62
63 63 #if defined(__sparc)
64 64 #include <sys/machsystm.h>
65 65 #endif
66 66
67 67 #ifdef ACPI_POWER_BUTTON
68 68
69 69 #include <sys/acpi/acpi.h>
70 70 #include <sys/acpica.h>
71 71
72 72 #else
73 73
74 74 #include <sys/epic.h>
75 75 /*
76 76 * Some #defs that must be here as they differ for power.c
77 77 * and epic.c
78 78 */
79 79 #define EPIC_REGS_OFFSET 0x00
80 80 #define EPIC_REGS_LEN 0x82
81 81
82 82
83 83 /*
84 84 * This flag, which is set for platforms, that have EPIC processor
85 85 * to process power button interrupt, helps in executing platform
86 86 * specific code.
87 87 */
88 88 static char hasEPIC = B_FALSE;
89 89 #endif /* ACPI_POWER_BUTTON */
90 90
91 91 /*
92 92 * Maximum number of clone minors that is allowed. This value
93 93 * is defined relatively low to save memory.
94 94 */
95 95 #define POWER_MAX_CLONE 256
96 96
97 97 /*
98 98 * Minor number is instance << 8 + clone minor from range 1-255; clone 0
99 99 * is reserved for "original" minor.
100 100 */
101 101 #define POWER_MINOR_TO_CLONE(minor) ((minor) & (POWER_MAX_CLONE - 1))
102 102
103 103 /*
104 104 * Power Button Abort Delay
105 105 */
106 106 #define ABORT_INCREMENT_DELAY 10
107 107
108 108 /*
109 109 * FWARC 2005/687: power device compatible property
110 110 */
111 111 #define POWER_DEVICE_TYPE "power-device-type"
112 112
113 113 /*
114 114 * Driver global variables
115 115 */
116 116 static void *power_state;
117 117 static int power_inst = -1;
118 118
119 119 static hrtime_t power_button_debounce = MSEC2NSEC(10);
120 120 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC;
121 121 static int power_button_abort_presses = 3;
122 122 static int power_button_abort_enable = 1;
123 123 static int power_button_enable = 1;
124 124
125 125 static int power_button_pressed = 0;
126 126 static int power_button_cancel = 0;
127 127 static int power_button_timeouts = 0;
128 128 static int timeout_cancel = 0;
129 129 static int additional_presses = 0;
130 130
131 131 /*
132 132 * Function prototypes
133 133 */
134 134 static int power_attach(dev_info_t *, ddi_attach_cmd_t);
135 135 static int power_detach(dev_info_t *, ddi_detach_cmd_t);
136 136 static int power_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
137 137 static int power_open(dev_t *, int, int, cred_t *);
138 138 static int power_close(dev_t, int, int, cred_t *);
139 139 static int power_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
140 140 static int power_chpoll(dev_t, short, int, short *, struct pollhead **);
141 141 #ifndef ACPI_POWER_BUTTON
142 142 static uint_t power_high_intr(caddr_t);
143 143 #endif
144 144 static uint_t power_soft_intr(caddr_t);
145 145 static uint_t power_issue_shutdown(caddr_t);
146 146 static void power_timeout(caddr_t);
147 147 static void power_log_message(void);
148 148
149 149 /*
150 150 * Structure used in the driver
151 151 */
152 152 struct power_soft_state {
153 153 dev_info_t *dip; /* device info pointer */
154 154 kmutex_t power_mutex; /* mutex lock */
155 155 kmutex_t power_intr_mutex; /* interrupt mutex lock */
156 156 ddi_iblock_cookie_t soft_iblock_cookie; /* holds interrupt cookie */
157 157 ddi_iblock_cookie_t high_iblock_cookie; /* holds interrupt cookie */
158 158 ddi_softintr_t softintr_id; /* soft interrupt id */
159 159 uchar_t clones[POWER_MAX_CLONE]; /* array of minor clones */
160 160 int monitor_on; /* clone monitoring the button event */
161 161 /* clone 0 indicates no one is */
162 162 /* monitoring the button event */
163 163 pollhead_t pollhd; /* poll head struct */
164 164 int events; /* bit map of occured events */
165 165 int shutdown_pending; /* system shutdown in progress */
166 166 #ifdef ACPI_POWER_BUTTON
167 167 boolean_t fixed_attached; /* true means fixed is attached */
168 168 boolean_t gpe_attached; /* true means GPE is attached */
169 169 ACPI_HANDLE button_obj; /* handle to device power button */
170 170 #else
171 171 ddi_acc_handle_t power_rhandle; /* power button register handle */
172 172 uint8_t *power_btn_reg; /* power button register address */
173 173 uint8_t power_btn_bit; /* power button register bit */
174 174 boolean_t power_regs_mapped; /* flag to tell if regs mapped */
175 175 boolean_t power_btn_ioctl; /* flag to specify ioctl request */
176 176 #endif
177 177 };
178 178
179 179 static void power_gen_sysevent(struct power_soft_state *);
180 180
181 181 #ifdef ACPI_POWER_BUTTON
182 182 static int power_attach_acpi(struct power_soft_state *softsp);
183 183 static void power_detach_acpi(struct power_soft_state *softsp);
184 184 static UINT32 power_acpi_fixed_event(void *ctx);
185 185 #else
186 186 static int power_setup_regs(struct power_soft_state *softsp);
187 187 static void power_free_regs(struct power_soft_state *softsp);
188 188 #endif /* ACPI_POWER_BUTTON */
189 189
190 190 /*
191 191 * Configuration data structures
192 192 */
193 193 static struct cb_ops power_cb_ops = {
194 194 power_open, /* open */
195 195 power_close, /* close */
196 196 nodev, /* strategy */
197 197 nodev, /* print */
198 198 nodev, /* dump */
199 199 nodev, /* read */
200 200 nodev, /* write */
201 201 power_ioctl, /* ioctl */
202 202 nodev, /* devmap */
203 203 nodev, /* mmap */
204 204 nodev, /* segmap */
205 205 power_chpoll, /* poll */
206 206 ddi_prop_op, /* cb_prop_op */
207 207 NULL, /* streamtab */
208 208 D_MP | D_NEW, /* Driver compatibility flag */
209 209 CB_REV, /* rev */
210 210 nodev, /* cb_aread */
211 211 nodev /* cb_awrite */
212 212 };
213 213
214 214 static struct dev_ops power_ops = {
215 215 DEVO_REV, /* devo_rev, */
216 216 0, /* refcnt */
217 217 power_getinfo, /* getinfo */
218 218 nulldev, /* identify */
219 219 nulldev, /* probe */
220 220 power_attach, /* attach */
221 221 power_detach, /* detach */
222 222 nodev, /* reset */
223 223 &power_cb_ops, /* cb_ops */
224 224 (struct bus_ops *)NULL, /* bus_ops */
225 225 NULL, /* power */
226 226 ddi_quiesce_not_supported, /* devo_quiesce */
↓ open down ↓ |
226 lines elided |
↑ open up ↑ |
227 227 };
228 228
229 229 static struct modldrv modldrv = {
230 230 &mod_driverops, /* Type of module. This one is a driver */
231 231 "power button driver", /* name of module */
232 232 &power_ops, /* driver ops */
233 233 };
234 234
235 235 static struct modlinkage modlinkage = {
236 236 MODREV_1,
237 - (void *)&modldrv,
238 - NULL
237 + { (void *)&modldrv, NULL }
239 238 };
240 239
241 240 /*
242 241 * These are the module initialization routines.
243 242 */
244 243
245 244 int
246 245 _init(void)
247 246 {
248 247 int error;
249 248
250 249 if ((error = ddi_soft_state_init(&power_state,
251 250 sizeof (struct power_soft_state), 0)) != 0)
252 251 return (error);
253 252
254 253 if ((error = mod_install(&modlinkage)) != 0)
255 254 ddi_soft_state_fini(&power_state);
256 255
257 256 return (error);
258 257 }
259 258
260 259 int
261 260 _fini(void)
262 261 {
263 262 int error;
264 263
265 264 if ((error = mod_remove(&modlinkage)) == 0)
266 265 ddi_soft_state_fini(&power_state);
267 266
268 267 return (error);
269 268 }
270 269
271 270 int
272 271 _info(struct modinfo *modinfop)
273 272 {
274 273 return (mod_info(&modlinkage, modinfop));
275 274 }
276 275
277 276 /*ARGSUSED*/
278 277 static int
279 278 power_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
280 279 void **result)
281 280 {
282 281 struct power_soft_state *softsp;
283 282
284 283 if (power_inst == -1)
285 284 return (DDI_FAILURE);
286 285
287 286 switch (infocmd) {
288 287 case DDI_INFO_DEVT2DEVINFO:
289 288 if ((softsp = ddi_get_soft_state(power_state, power_inst))
290 289 == NULL)
291 290 return (DDI_FAILURE);
292 291 *result = (void *)softsp->dip;
293 292 return (DDI_SUCCESS);
294 293
295 294 case DDI_INFO_DEVT2INSTANCE:
296 295 *result = (void *)(uintptr_t)power_inst;
297 296 return (DDI_SUCCESS);
298 297
299 298 default:
300 299 return (DDI_FAILURE);
301 300 }
302 301 }
303 302
304 303 static int
305 304 power_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
306 305 {
307 306 struct power_soft_state *softsp;
308 307
309 308 switch (cmd) {
310 309 case DDI_ATTACH:
311 310 break;
312 311 case DDI_RESUME:
313 312 return (DDI_SUCCESS);
314 313 default:
315 314 return (DDI_FAILURE);
316 315 }
317 316
318 317 /*
319 318 * If the power node doesn't have "button" property, quietly
320 319 * fail to attach.
321 320 */
322 321 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
323 322 "button") == 0)
324 323 return (DDI_FAILURE);
325 324
326 325 if (power_inst != -1)
327 326 return (DDI_FAILURE);
328 327
329 328 power_inst = ddi_get_instance(dip);
330 329
331 330 if (ddi_soft_state_zalloc(power_state, power_inst) != DDI_SUCCESS)
332 331 return (DDI_FAILURE);
333 332
334 333 if (ddi_create_minor_node(dip, "power_button", S_IFCHR,
335 334 (power_inst << 8) + 0, "ddi_power_button", 0) != DDI_SUCCESS)
336 335 return (DDI_FAILURE);
337 336
338 337 softsp = ddi_get_soft_state(power_state, power_inst);
339 338 softsp->dip = dip;
340 339
341 340 #ifdef ACPI_POWER_BUTTON
342 341 (void) power_attach_acpi(softsp);
343 342 #else
344 343 if (power_setup_regs(softsp) != DDI_SUCCESS) {
345 344 cmn_err(CE_WARN, "power_attach: failed to setup registers");
346 345 goto error;
347 346 }
348 347
349 348 if (ddi_get_iblock_cookie(dip, 0,
350 349 &softsp->high_iblock_cookie) != DDI_SUCCESS) {
351 350 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
352 351 "failed.");
353 352 goto error;
354 353 }
355 354 mutex_init(&softsp->power_intr_mutex, NULL, MUTEX_DRIVER,
356 355 softsp->high_iblock_cookie);
357 356
358 357 if (ddi_add_intr(dip, 0, &softsp->high_iblock_cookie, NULL,
359 358 power_high_intr, (caddr_t)softsp) != DDI_SUCCESS) {
360 359 cmn_err(CE_WARN, "power_attach: failed to add high-level "
361 360 " interrupt handler.");
362 361 mutex_destroy(&softsp->power_intr_mutex);
363 362 goto error;
364 363 }
365 364 #endif /* ACPI_POWER_BUTTON */
366 365
367 366 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
368 367 &softsp->soft_iblock_cookie) != DDI_SUCCESS) {
369 368 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
370 369 "failed.");
371 370 mutex_destroy(&softsp->power_intr_mutex);
372 371 ddi_remove_intr(dip, 0, NULL);
373 372 goto error;
374 373 }
375 374
376 375 mutex_init(&softsp->power_mutex, NULL, MUTEX_DRIVER,
377 376 (void *)softsp->soft_iblock_cookie);
378 377
379 378 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softsp->softintr_id,
380 379 NULL, NULL, power_soft_intr, (caddr_t)softsp) != DDI_SUCCESS) {
381 380 cmn_err(CE_WARN, "power_attach: failed to add soft "
382 381 "interrupt handler.");
383 382 mutex_destroy(&softsp->power_mutex);
384 383 mutex_destroy(&softsp->power_intr_mutex);
385 384 ddi_remove_intr(dip, 0, NULL);
386 385 goto error;
387 386 }
388 387
389 388 ddi_report_dev(dip);
390 389
391 390 return (DDI_SUCCESS);
392 391
393 392 error:
394 393 #ifdef ACPI_POWER_BUTTON
395 394 /*
396 395 * detach ACPI power button
397 396 */
398 397 power_detach_acpi(softsp);
399 398 #else
400 399 power_free_regs(softsp);
401 400 #endif /* ACPI_POWER_BUTTON */
402 401 ddi_remove_minor_node(dip, "power_button");
403 402 ddi_soft_state_free(power_state, power_inst);
404 403 return (DDI_FAILURE);
405 404 }
406 405
407 406 /*ARGSUSED*/
408 407 /*
409 408 * This driver doesn't detach.
410 409 */
411 410 static int
412 411 power_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
413 412 {
414 413 /*
415 414 * Since the "power" node has "reg" property, as part of
416 415 * the suspend operation, detach(9E) entry point is called.
417 416 * There is no state to save, since this register is used
418 417 * by OBP to power off the system and the state of the
419 418 * power off is preserved by hardware.
420 419 */
421 420 return ((cmd == DDI_SUSPEND) ? DDI_SUCCESS :
422 421 DDI_FAILURE);
423 422 }
424 423
425 424
426 425 #ifndef ACPI_POWER_BUTTON
427 426 /*
428 427 * Handler for the high-level interrupt.
429 428 */
430 429 static uint_t
431 430 power_high_intr(caddr_t arg)
432 431 {
433 432 struct power_soft_state *softsp = (struct power_soft_state *)arg;
434 433 ddi_acc_handle_t hdl = softsp->power_rhandle;
435 434 uint8_t reg;
436 435
437 436 hrtime_t tstamp;
438 437 static hrtime_t o_tstamp = 0;
439 438 static hrtime_t power_button_tstamp = 0;
440 439 static int power_button_cnt;
441 440
442 441 if (softsp->power_regs_mapped) {
443 442 mutex_enter(&softsp->power_intr_mutex);
444 443
445 444 /* Check if power button interrupt is delivered by EPIC HW */
446 445 if (hasEPIC) {
447 446 /* read isr - first issue command */
448 447 EPIC_WR(hdl, softsp->power_btn_reg,
449 448 EPIC_ATOM_INTR_READ);
450 449 /* next, read the reg */
451 450 EPIC_RD(hdl, softsp->power_btn_reg, reg);
452 451
453 452 if (reg & EPIC_FIRE_INTERRUPT) { /* PB pressed */
454 453 /* clear the interrupt */
455 454 EPIC_WR(hdl, softsp->power_btn_reg,
456 455 EPIC_ATOM_INTR_CLEAR);
457 456 } else {
458 457 if (!softsp->power_btn_ioctl) {
459 458 mutex_exit(&softsp->power_intr_mutex);
460 459 return (DDI_INTR_CLAIMED);
461 460 }
462 461 softsp->power_btn_ioctl = B_FALSE;
463 462 }
464 463 } else {
465 464 reg = ddi_get8(hdl, softsp->power_btn_reg);
466 465 if (reg & softsp->power_btn_bit) {
467 466 reg &= softsp->power_btn_bit;
468 467 ddi_put8(hdl, softsp->power_btn_reg, reg);
469 468 (void) ddi_get8(hdl, softsp->power_btn_reg);
470 469 } else {
471 470 if (!softsp->power_btn_ioctl) {
472 471 mutex_exit(&softsp->power_intr_mutex);
473 472 return (DDI_INTR_CLAIMED);
474 473 }
475 474 softsp->power_btn_ioctl = B_FALSE;
476 475 }
477 476 }
478 477 mutex_exit(&softsp->power_intr_mutex);
479 478 }
480 479
481 480 tstamp = gethrtime();
482 481
483 482 /* need to deal with power button debounce */
484 483 if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) {
485 484 o_tstamp = tstamp;
486 485 return (DDI_INTR_CLAIMED);
487 486 }
488 487 o_tstamp = tstamp;
489 488
490 489 power_button_cnt++;
491 490
492 491 mutex_enter(&softsp->power_intr_mutex);
493 492 power_button_pressed++;
494 493 mutex_exit(&softsp->power_intr_mutex);
495 494
496 495 /*
497 496 * If power button abort is enabled and power button was pressed
498 497 * power_button_abort_presses times within power_button_abort_interval
499 498 * then call abort_sequence_enter();
500 499 */
501 500 if (power_button_abort_enable) {
502 501 if (power_button_abort_presses == 1 ||
503 502 tstamp < (power_button_tstamp +
504 503 power_button_abort_interval)) {
505 504 if (power_button_cnt == power_button_abort_presses) {
506 505 mutex_enter(&softsp->power_intr_mutex);
507 506 power_button_cancel += power_button_timeouts;
508 507 power_button_pressed = 0;
509 508 mutex_exit(&softsp->power_intr_mutex);
510 509 power_button_cnt = 0;
511 510 abort_sequence_enter("Power Button Abort");
512 511 return (DDI_INTR_CLAIMED);
513 512 }
514 513 } else {
515 514 power_button_cnt = 1;
516 515 power_button_tstamp = tstamp;
517 516 }
518 517 }
519 518
520 519 if (!power_button_enable)
521 520 return (DDI_INTR_CLAIMED);
522 521
523 522 /* post softint to issue timeout for power button action */
524 523 if (softsp->softintr_id != NULL)
525 524 ddi_trigger_softintr(softsp->softintr_id);
526 525
527 526 return (DDI_INTR_CLAIMED);
528 527 }
529 528 #endif /* ifndef ACPI_POWER_BUTTON */
530 529
531 530 /*
532 531 * Handle the softints....
533 532 *
534 533 * If only one softint is posted for several button presses, record
535 534 * the number of additional presses just incase this was actually not quite
536 535 * an Abort sequence so that we can log this event later.
537 536 *
538 537 * Issue a timeout with a duration being a fraction larger than
539 538 * the specified Abort interval inorder to perform a power down if required.
540 539 */
541 540 static uint_t
542 541 power_soft_intr(caddr_t arg)
543 542 {
544 543 struct power_soft_state *softsp = (struct power_soft_state *)arg;
545 544
546 545 if (!power_button_abort_enable)
547 546 return (power_issue_shutdown(arg));
548 547
549 548 mutex_enter(&softsp->power_intr_mutex);
550 549 if (!power_button_pressed) {
551 550 mutex_exit(&softsp->power_intr_mutex);
552 551 return (DDI_INTR_CLAIMED);
553 552 }
554 553
555 554 /*
556 555 * Schedule a timeout to do the necessary
557 556 * work for shutdown, only one timeout for
558 557 * n presses if power button was pressed
559 558 * more than once before softint fired
560 559 */
561 560 if (power_button_pressed > 1)
562 561 additional_presses += power_button_pressed - 1;
563 562
564 563 timeout_cancel = 0;
565 564 power_button_pressed = 0;
566 565 power_button_timeouts++;
567 566 mutex_exit(&softsp->power_intr_mutex);
568 567 (void) timeout((void(*)(void *))power_timeout,
569 568 softsp, NSEC_TO_TICK(power_button_abort_interval) +
570 569 ABORT_INCREMENT_DELAY);
571 570
572 571 return (DDI_INTR_CLAIMED);
573 572 }
574 573
575 574 /*
576 575 * Upon receiving a timeout the following is determined:
577 576 *
578 577 * If an Abort sequence was issued, then we cancel all outstanding timeouts
579 578 * and additional presses prior to the Abort sequence.
580 579 *
581 580 * If we had multiple timeouts issued and the abort sequence was not met,
582 581 * then we had more than one button press to power down the machine. We
583 582 * were probably trying to issue an abort. So log a message indicating this
584 583 * and cancel all outstanding timeouts.
585 584 *
586 585 * If we had just one timeout and the abort sequence was not met then
587 586 * we really did want to power down the machine, so call power_issue_shutdown()
588 587 * to do the work and schedule a power down
589 588 */
590 589 static void
591 590 power_timeout(caddr_t arg)
592 591 {
593 592 struct power_soft_state *softsp = (struct power_soft_state *)arg;
594 593 static int first = 0;
595 594
596 595 /*
597 596 * Abort was generated cancel all outstanding power
598 597 * button timeouts
599 598 */
600 599 mutex_enter(&softsp->power_intr_mutex);
601 600 if (power_button_cancel) {
602 601 power_button_cancel--;
603 602 power_button_timeouts--;
604 603 if (!first) {
605 604 first++;
606 605 additional_presses = 0;
607 606 }
608 607 mutex_exit(&softsp->power_intr_mutex);
609 608 return;
610 609 }
611 610 first = 0;
612 611
613 612 /*
614 613 * We get here if the timeout(s) have fired and they were
615 614 * not issued prior to an abort.
616 615 *
617 616 * If we had more than one press in the interval we were
618 617 * probably trying to issue an abort, but didnt press the
619 618 * required number within the interval. Hence cancel all
620 619 * timeouts and do not continue towards shutdown.
621 620 */
622 621 if (!timeout_cancel) {
623 622 timeout_cancel = power_button_timeouts +
624 623 additional_presses;
625 624
626 625 power_button_timeouts--;
627 626 if (!power_button_timeouts)
628 627 additional_presses = 0;
629 628
630 629 if (timeout_cancel > 1) {
631 630 mutex_exit(&softsp->power_intr_mutex);
632 631 cmn_err(CE_NOTE, "Power Button pressed "
633 632 "%d times, cancelling all requests",
634 633 timeout_cancel);
635 634 return;
636 635 }
637 636 mutex_exit(&softsp->power_intr_mutex);
638 637
639 638 /* Go and do the work to request shutdown */
640 639 (void) power_issue_shutdown((caddr_t)softsp);
641 640 return;
642 641 }
643 642
644 643 power_button_timeouts--;
645 644 if (!power_button_timeouts)
646 645 additional_presses = 0;
647 646 mutex_exit(&softsp->power_intr_mutex);
648 647 }
649 648
650 649 #ifdef ACPI_POWER_BUTTON
651 650 static void
652 651 do_shutdown(void)
653 652 {
654 653 proc_t *initpp;
655 654
656 655 /*
657 656 * If we're still booting and init(1) isn't set up yet, simply halt.
658 657 */
659 658 mutex_enter(&pidlock);
660 659 initpp = prfind(P_INITPID);
661 660 mutex_exit(&pidlock);
662 661 if (initpp == NULL) {
663 662 extern void halt(char *);
664 663 halt("Power off the System"); /* just in case */
665 664 }
666 665
667 666 /*
668 667 * else, graceful shutdown with inittab and all getting involved
669 668 */
670 669 psignal(initpp, SIGPWR);
671 670 }
672 671 #endif
673 672
674 673 static uint_t
675 674 power_issue_shutdown(caddr_t arg)
676 675 {
677 676 struct power_soft_state *softsp = (struct power_soft_state *)arg;
678 677
679 678 mutex_enter(&softsp->power_mutex);
680 679 softsp->events |= PB_BUTTON_PRESS;
681 680 if (softsp->monitor_on != 0) {
682 681 mutex_exit(&softsp->power_mutex);
683 682 pollwakeup(&softsp->pollhd, POLLRDNORM);
684 683 pollwakeup(&softsp->pollhd, POLLIN);
685 684 power_gen_sysevent(softsp);
686 685 return (DDI_INTR_CLAIMED);
687 686 }
688 687
689 688 if (!softsp->shutdown_pending) {
690 689 cmn_err(CE_WARN, "Power off requested from power button or "
691 690 "SC, powering down the system!");
692 691 softsp->shutdown_pending = 1;
693 692 do_shutdown();
694 693
695 694 /*
696 695 * Wait a while for "do_shutdown()" to shut down the system
697 696 * before logging an error message.
698 697 */
699 698 (void) timeout((void(*)(void *))power_log_message, NULL,
700 699 100 * hz);
701 700 }
702 701 mutex_exit(&softsp->power_mutex);
703 702
704 703 return (DDI_INTR_CLAIMED);
705 704 }
706 705
707 706 static void
708 707 power_gen_sysevent(struct power_soft_state *softsp)
709 708 {
710 709 nvlist_t *attr_list = NULL;
711 710 int err;
712 711 char pathname[MAXPATHLEN];
713 712 char hid[9] = "\0";
714 713
715 714 /* Allocate and build sysevent attribute list */
716 715 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
717 716 if (err != 0) {
718 717 cmn_err(CE_WARN,
719 718 "cannot allocate memory for sysevent attributes\n");
720 719 return;
721 720 }
722 721
723 722 #ifdef ACPI_POWER_BUTTON
724 723 /* Only control method power button has HID */
725 724 if (softsp->gpe_attached) {
726 725 (void) strlcpy(hid, "PNP0C0C", sizeof (hid));
727 726 }
728 727 #endif
729 728
730 729 err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, hid);
731 730 if (err != 0) {
732 731 cmn_err(CE_WARN,
733 732 "Failed to add attr [%s] for %s/%s event",
734 733 PWRCTL_DEV_HID, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON);
735 734 nvlist_free(attr_list);
736 735 return;
737 736 }
738 737
739 738 (void) ddi_pathname(softsp->dip, pathname);
740 739 err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname);
741 740 if (err != 0) {
742 741 cmn_err(CE_WARN,
743 742 "Failed to add attr [%s] for %s/%s event",
744 743 PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON);
745 744 nvlist_free(attr_list);
746 745 return;
747 746 }
748 747
749 748 /* Generate/log sysevent */
750 749 err = ddi_log_sysevent(softsp->dip, DDI_VENDOR_SUNW, EC_PWRCTL,
751 750 ESC_PWRCTL_POWER_BUTTON, attr_list, NULL, DDI_NOSLEEP);
752 751 if (err != DDI_SUCCESS) {
753 752 cmn_err(CE_WARN,
754 753 "cannot log sysevent, err code %x\n", err);
755 754 }
756 755
757 756 nvlist_free(attr_list);
758 757 }
759 758
760 759 /*
761 760 * Open the device.
762 761 */
763 762 /*ARGSUSED*/
764 763 static int
765 764 power_open(dev_t *devp, int openflags, int otyp, cred_t *credp)
766 765 {
767 766 struct power_soft_state *softsp;
768 767 int clone;
769 768
770 769 if (otyp != OTYP_CHR)
771 770 return (EINVAL);
772 771
773 772 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
774 773 NULL)
775 774 return (ENXIO);
776 775
777 776 mutex_enter(&softsp->power_mutex);
778 777 for (clone = 1; clone < POWER_MAX_CLONE; clone++)
779 778 if (!softsp->clones[clone])
780 779 break;
781 780
782 781 if (clone == POWER_MAX_CLONE) {
783 782 cmn_err(CE_WARN, "power_open: No more allocation left "
784 783 "to create a clone minor.");
785 784 mutex_exit(&softsp->power_mutex);
786 785 return (ENXIO);
787 786 }
788 787
789 788 *devp = makedevice(getmajor(*devp), (power_inst << 8) + clone);
790 789 softsp->clones[clone] = 1;
791 790 mutex_exit(&softsp->power_mutex);
792 791
793 792 return (0);
794 793 }
795 794
796 795 /*
797 796 * Close the device.
798 797 */
799 798 /*ARGSUSED*/
800 799 static int
801 800 power_close(dev_t dev, int openflags, int otyp, cred_t *credp)
802 801 {
803 802 struct power_soft_state *softsp;
804 803 int clone;
805 804
806 805 if (otyp != OTYP_CHR)
807 806 return (EINVAL);
808 807
809 808 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
810 809 NULL)
811 810 return (ENXIO);
812 811
813 812 clone = POWER_MINOR_TO_CLONE(getminor(dev));
814 813 mutex_enter(&softsp->power_mutex);
815 814 if (softsp->monitor_on == clone)
816 815 softsp->monitor_on = 0;
817 816 softsp->clones[clone] = 0;
818 817 mutex_exit(&softsp->power_mutex);
819 818
820 819 return (0);
821 820 }
822 821
823 822 /*ARGSUSED*/
824 823 static int
825 824 power_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
826 825 int *rval_p)
827 826 {
828 827 struct power_soft_state *softsp;
829 828 int clone;
830 829
831 830 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
832 831 NULL)
833 832 return (ENXIO);
834 833
835 834 clone = POWER_MINOR_TO_CLONE(getminor(dev));
836 835 switch (cmd) {
837 836 case PB_BEGIN_MONITOR:
838 837 mutex_enter(&softsp->power_mutex);
839 838 if (softsp->monitor_on) {
840 839 mutex_exit(&softsp->power_mutex);
841 840 return (EBUSY);
842 841 }
843 842 softsp->monitor_on = clone;
844 843 mutex_exit(&softsp->power_mutex);
845 844 return (0);
846 845
847 846 case PB_END_MONITOR:
848 847 mutex_enter(&softsp->power_mutex);
849 848
850 849 /*
851 850 * If PB_END_MONITOR is called without first
852 851 * calling PB_BEGIN_MONITOR, an error will be
853 852 * returned.
854 853 */
855 854 if (!softsp->monitor_on) {
856 855 mutex_exit(&softsp->power_mutex);
857 856 return (ENXIO);
858 857 }
859 858
860 859 /*
861 860 * This clone is not monitoring the button.
862 861 */
863 862 if (softsp->monitor_on != clone) {
864 863 mutex_exit(&softsp->power_mutex);
865 864 return (EINVAL);
866 865 }
867 866 softsp->monitor_on = 0;
868 867 mutex_exit(&softsp->power_mutex);
869 868 return (0);
870 869
871 870 case PB_GET_EVENTS:
872 871 mutex_enter(&softsp->power_mutex);
873 872 if (ddi_copyout((void *)&softsp->events, (void *)arg,
874 873 sizeof (int), mode) != 0) {
875 874 mutex_exit(&softsp->power_mutex);
876 875 return (EFAULT);
877 876 }
878 877
879 878 /*
880 879 * This ioctl returned the events detected since last
881 880 * call. Note that any application can get the events
882 881 * and clear the event register.
883 882 */
884 883 softsp->events = 0;
885 884 mutex_exit(&softsp->power_mutex);
886 885 return (0);
887 886
888 887 /*
889 888 * This ioctl is used by the test suite.
890 889 */
891 890 case PB_CREATE_BUTTON_EVENT:
892 891 #ifdef ACPI_POWER_BUTTON
893 892 (UINT32)power_acpi_fixed_event((void *)softsp);
894 893 #else
895 894 if (softsp->power_regs_mapped) {
896 895 mutex_enter(&softsp->power_intr_mutex);
897 896 softsp->power_btn_ioctl = B_TRUE;
898 897 mutex_exit(&softsp->power_intr_mutex);
899 898 }
900 899 (void) power_high_intr((caddr_t)softsp);
901 900 #endif /* ACPI_POWER_BUTTON */
902 901 return (0);
903 902
904 903 default:
905 904 return (ENOTTY);
906 905 }
907 906 }
908 907
909 908 /*ARGSUSED*/
910 909 static int
911 910 power_chpoll(dev_t dev, short events, int anyyet,
912 911 short *reventsp, struct pollhead **phpp)
913 912 {
914 913 struct power_soft_state *softsp;
915 914
916 915 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL)
917 916 return (ENXIO);
918 917
919 918 mutex_enter(&softsp->power_mutex);
920 919 *reventsp = 0;
921 920 if (softsp->events)
922 921 *reventsp = POLLRDNORM|POLLIN;
923 922 else {
924 923 if (!anyyet)
925 924 *phpp = &softsp->pollhd;
926 925 }
927 926 mutex_exit(&softsp->power_mutex);
928 927
929 928 return (0);
930 929 }
931 930
932 931 static void
933 932 power_log_message(void)
934 933 {
935 934 struct power_soft_state *softsp;
936 935
937 936 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) {
938 937 cmn_err(CE_WARN, "Failed to get internal state!");
939 938 return;
940 939 }
941 940
942 941 mutex_enter(&softsp->power_mutex);
943 942 softsp->shutdown_pending = 0;
944 943 cmn_err(CE_WARN, "Failed to shut down the system!");
945 944 mutex_exit(&softsp->power_mutex);
946 945 }
947 946
948 947 #ifdef ACPI_POWER_BUTTON
949 948 /*
950 949 *
951 950 */
952 951 /*ARGSUSED*/
953 952 static ACPI_STATUS
954 953 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv)
955 954 {
956 955
957 956 *((ACPI_HANDLE *)context) = obj;
958 957 return (AE_OK);
959 958 }
960 959
961 960 /*
962 961 *
963 962 */
964 963 static ACPI_HANDLE
965 964 probe_acpi_pwrbutton()
966 965 {
967 966 ACPI_HANDLE obj = NULL;
968 967
969 968 (void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL);
970 969 return (obj);
971 970 }
972 971
973 972 static UINT32
974 973 power_acpi_fixed_event(void *ctx)
975 974 {
976 975
977 976 mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex);
978 977 power_button_pressed++;
979 978 mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex);
980 979
981 980 /* post softint to issue timeout for power button action */
982 981 if (((struct power_soft_state *)ctx)->softintr_id != NULL)
983 982 ddi_trigger_softintr(
984 983 ((struct power_soft_state *)ctx)->softintr_id);
985 984
986 985 return (AE_OK);
987 986 }
988 987
989 988 /*ARGSUSED*/
990 989 static void
991 990 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx)
992 991 {
993 992 if (val == 0x80)
994 993 (void) power_acpi_fixed_event(ctx);
995 994 }
996 995
997 996 /*
998 997 *
999 998 */
1000 999 static int
1001 1000 power_probe_method_button(struct power_soft_state *softsp)
1002 1001 {
1003 1002 ACPI_HANDLE button_obj;
1004 1003
1005 1004 button_obj = probe_acpi_pwrbutton();
1006 1005 softsp->button_obj = button_obj; /* remember obj */
1007 1006 if ((button_obj != NULL) &&
1008 1007 (AcpiInstallNotifyHandler(button_obj, ACPI_DEVICE_NOTIFY,
1009 1008 power_acpi_notify_event, (void*)softsp) == AE_OK))
1010 1009 return (1);
1011 1010 return (0);
1012 1011 }
1013 1012
1014 1013 /*
1015 1014 *
1016 1015 */
1017 1016 static int
1018 1017 power_probe_fixed_button(struct power_soft_state *softsp)
1019 1018 {
1020 1019 ACPI_TABLE_FADT *fadt;
1021 1020
1022 1021 if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **) &fadt) !=
1023 1022 AE_OK)
1024 1023 return (0);
1025 1024
1026 1025 if ((fadt->Flags & ACPI_FADT_POWER_BUTTON) == 0) {
1027 1026 if (AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1028 1027 power_acpi_fixed_event, (void *)softsp) == AE_OK)
1029 1028 return (1);
1030 1029 }
1031 1030 return (0);
1032 1031 }
1033 1032
1034 1033
1035 1034 /*
1036 1035 *
1037 1036 */
1038 1037 static int
1039 1038 power_attach_acpi(struct power_soft_state *softsp)
1040 1039 {
1041 1040
1042 1041 /*
1043 1042 * If we've attached anything already, return an error
1044 1043 */
1045 1044 if ((softsp->gpe_attached) || (softsp->fixed_attached))
1046 1045 return (DDI_FAILURE);
1047 1046
1048 1047 /*
1049 1048 * attempt to attach both a fixed-event handler and a GPE
1050 1049 * handler; remember what we got
1051 1050 */
1052 1051 softsp->fixed_attached = (power_probe_fixed_button(softsp) != 0);
1053 1052 softsp->gpe_attached = (power_probe_method_button(softsp) != 0);
1054 1053
1055 1054 /*
1056 1055 * If we've attached anything now, return success
1057 1056 */
1058 1057 if ((softsp->gpe_attached) || (softsp->fixed_attached))
1059 1058 return (DDI_SUCCESS);
1060 1059
1061 1060 return (DDI_FAILURE);
1062 1061 }
1063 1062
1064 1063 /*
1065 1064 *
1066 1065 */
1067 1066 static void
1068 1067 power_detach_acpi(struct power_soft_state *softsp)
1069 1068 {
1070 1069 if (softsp->gpe_attached) {
1071 1070 if (AcpiRemoveNotifyHandler(softsp->button_obj,
1072 1071 ACPI_DEVICE_NOTIFY, power_acpi_notify_event) != AE_OK)
1073 1072 cmn_err(CE_WARN, "!power: failed to remove Notify"
1074 1073 " handler");
1075 1074 }
1076 1075
1077 1076 if (softsp->fixed_attached) {
1078 1077 if (AcpiRemoveFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1079 1078 power_acpi_fixed_event) != AE_OK)
1080 1079 cmn_err(CE_WARN, "!power: failed to remove Power"
1081 1080 " Button handler");
1082 1081 }
1083 1082 }
1084 1083
1085 1084 #else
1086 1085 /*
1087 1086 * Code for platforms that have EPIC processor for processing power
1088 1087 * button interrupts.
1089 1088 */
1090 1089 static int
1091 1090 power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp)
1092 1091 {
1093 1092 ddi_device_acc_attr_t attr;
1094 1093 uint8_t *reg_base;
1095 1094
1096 1095 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1097 1096 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1098 1097 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1099 1098 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base,
1100 1099 EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr,
1101 1100 &softsp->power_rhandle) != DDI_SUCCESS) {
1102 1101 return (DDI_FAILURE);
1103 1102 }
1104 1103
1105 1104 softsp->power_btn_reg = reg_base;
1106 1105 softsp->power_regs_mapped = B_TRUE;
1107 1106
1108 1107 /* Clear power button interrupt first */
1109 1108 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1110 1109 EPIC_ATOM_INTR_CLEAR);
1111 1110
1112 1111 /* Enable EPIC interrupt for power button single press event */
1113 1112 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1114 1113 EPIC_ATOM_INTR_ENABLE);
1115 1114
1116 1115 /*
1117 1116 * At this point, EPIC interrupt processing is fully initialised.
1118 1117 */
1119 1118 hasEPIC = B_TRUE;
1120 1119 return (DDI_SUCCESS);
1121 1120 }
1122 1121
1123 1122 /*
1124 1123 *
1125 1124 * power button register definitions for acpi register on m1535d
1126 1125 */
1127 1126 #define M1535D_PWR_BTN_REG_01 0x1
1128 1127 #define M1535D_PWR_BTN_EVENT_FLAG 0x1
1129 1128
1130 1129 static int
1131 1130 power_setup_m1535_regs(dev_info_t *dip, struct power_soft_state *softsp)
1132 1131 {
1133 1132 ddi_device_acc_attr_t attr;
1134 1133 uint8_t *reg_base;
1135 1134
1136 1135 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1137 1136 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1138 1137 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1139 1138 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr,
1140 1139 &softsp->power_rhandle) != DDI_SUCCESS) {
1141 1140 return (DDI_FAILURE);
1142 1141 }
1143 1142 softsp->power_btn_reg = ®_base[M1535D_PWR_BTN_REG_01];
1144 1143 softsp->power_btn_bit = M1535D_PWR_BTN_EVENT_FLAG;
1145 1144 softsp->power_regs_mapped = B_TRUE;
1146 1145 return (DDI_SUCCESS);
1147 1146 }
1148 1147
1149 1148 /*
1150 1149 * MBC Fire/SSI Interrupt Status Register definitions
1151 1150 */
1152 1151 #define FIRE_SSI_ISR 0x0
1153 1152 #define FIRE_SSI_INTR_ENA 0x8
1154 1153 #define FIRE_SSI_SHUTDOWN_REQ 0x4
1155 1154
1156 1155 static int
1157 1156 power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp)
1158 1157 {
1159 1158 ddi_device_acc_attr_t attr;
1160 1159 uint8_t *reg_base;
1161 1160 ddi_acc_handle_t hdl;
1162 1161 uint8_t reg;
1163 1162
1164 1163 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1165 1164 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1166 1165 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1167 1166 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr,
1168 1167 &softsp->power_rhandle) != DDI_SUCCESS) {
1169 1168 return (DDI_FAILURE);
1170 1169 }
1171 1170 softsp->power_btn_reg = ®_base[FIRE_SSI_ISR];
1172 1171 softsp->power_btn_bit = FIRE_SSI_SHUTDOWN_REQ;
1173 1172 hdl = softsp->power_rhandle;
1174 1173 /*
1175 1174 * Clear MBC Fire Power Button interrupt, if set.
1176 1175 */
1177 1176 reg = ddi_get8(hdl, softsp->power_btn_reg);
1178 1177 if (reg & softsp->power_btn_bit) {
1179 1178 reg &= softsp->power_btn_bit;
1180 1179 ddi_put8(hdl, softsp->power_btn_reg, reg);
1181 1180 (void) ddi_get8(hdl, softsp->power_btn_reg);
1182 1181 }
1183 1182 /*
1184 1183 * Enable MBC Fire Power Button interrupt.
1185 1184 */
1186 1185 reg = ddi_get8(hdl, ®_base[FIRE_SSI_INTR_ENA]);
1187 1186 reg |= FIRE_SSI_SHUTDOWN_REQ;
1188 1187 ddi_put8(hdl, ®_base[FIRE_SSI_INTR_ENA], reg);
1189 1188
1190 1189 softsp->power_regs_mapped = B_TRUE;
1191 1190
1192 1191 return (DDI_SUCCESS);
1193 1192 }
1194 1193
1195 1194 /*
1196 1195 * Setup register map for the power button
1197 1196 * NOTE:- we only map registers for platforms if
1198 1197 * the OBP power device has any of the following
1199 1198 * properties:
1200 1199 *
1201 1200 * a) Boston: power-device-type set to "SUNW,mbc"
1202 1201 * b) Seattle: power-device-type set to "SUNW,pic18lf65j10"
1203 1202 * c) Chalupa: compatible set to "ali1535d+-power"
1204 1203 *
1205 1204 * Cases (a) and (b) are defined in FWARC 2005/687.
1206 1205 * If none of the above conditions are true, then we
1207 1206 * do not need to map in any registers, and this
1208 1207 * function can simply return DDI_SUCCESS.
1209 1208 */
1210 1209 static int
1211 1210 power_setup_regs(struct power_soft_state *softsp)
1212 1211 {
1213 1212 char *binding_name;
1214 1213 char *power_type = NULL;
1215 1214 int retval = DDI_SUCCESS;
1216 1215
1217 1216 softsp->power_regs_mapped = B_FALSE;
1218 1217 softsp->power_btn_ioctl = B_FALSE;
1219 1218 binding_name = ddi_binding_name(softsp->dip);
1220 1219 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, softsp->dip,
1221 1220 DDI_PROP_DONTPASS, POWER_DEVICE_TYPE,
1222 1221 &power_type) == DDI_PROP_SUCCESS) {
1223 1222 if (strcmp(power_type, "SUNW,mbc") == 0) {
1224 1223 retval = power_setup_mbc_regs(softsp->dip, softsp);
1225 1224 } else if (strcmp(power_type, "SUNW,pic18lf65j10") == 0) {
1226 1225 retval = power_setup_epic_regs(softsp->dip, softsp);
1227 1226 } else {
1228 1227 cmn_err(CE_WARN, "unexpected power-device-type: %s\n",
1229 1228 power_type);
1230 1229 retval = DDI_FAILURE;
1231 1230 }
1232 1231 ddi_prop_free(power_type);
1233 1232 } else if (strcmp(binding_name, "ali1535d+-power") == 0) {
1234 1233 retval = power_setup_m1535_regs(softsp->dip, softsp);
1235 1234 }
1236 1235
1237 1236 /*
1238 1237 * If power-device-type does not exist AND the binding name is not
1239 1238 * "ali1535d+-power", that means there is no additional HW and hence
1240 1239 * no extra processing is necessary. In that case, retval should still
1241 1240 * be set to its initial value of DDI_SUCCESS.
1242 1241 */
1243 1242 return (retval);
1244 1243 }
1245 1244
1246 1245 static void
1247 1246 power_free_regs(struct power_soft_state *softsp)
1248 1247 {
1249 1248 if (softsp->power_regs_mapped)
1250 1249 ddi_regs_map_free(&softsp->power_rhandle);
1251 1250 }
1252 1251 #endif /* ACPI_POWER_BUTTON */
↓ open down ↓ |
1004 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX