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