xref: /titanic_52/usr/src/uts/common/io/power.c (revision c2785286330b58810071fc24f6ca69f401682dff)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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 = NANOSEC/MILLISEC*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 };
227 
228 static struct modldrv modldrv = {
229 	&mod_driverops,		/* Type of module.  This one is a driver */
230 	"power button driver",	/* name of module */
231 	&power_ops,		/* driver ops */
232 };
233 
234 static struct modlinkage modlinkage = {
235 	MODREV_1,
236 	(void *)&modldrv,
237 	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  * Given a handle to a device object, locate a _PRW object
950  * if present and fetch the GPE info for this device object
951  */
952 static ACPI_STATUS
953 power_get_prw_gpe(ACPI_HANDLE dev, ACPI_HANDLE *gpe_dev, UINT32 *gpe_num)
954 {
955 	ACPI_BUFFER buf;
956 	ACPI_STATUS status;
957 	ACPI_HANDLE prw;
958 	ACPI_OBJECT *gpe;
959 
960 	/*
961 	 * Evaluate _PRW if present
962 	 */
963 	status = AcpiGetHandle(dev, "_PRW", &prw);
964 	if (status != AE_OK)
965 		return (status);
966 	buf.Length = ACPI_ALLOCATE_BUFFER;
967 	status = AcpiEvaluateObjectTyped(prw, NULL, NULL, &buf,
968 	    ACPI_TYPE_PACKAGE);
969 	if (status != AE_OK)
970 		return (status);
971 
972 	/*
973 	 * Sanity-check the package; need at least two elements
974 	 */
975 	status = AE_ERROR;
976 	if (((ACPI_OBJECT *)buf.Pointer)->Package.Count < 2)
977 		goto done;
978 
979 	gpe = &((ACPI_OBJECT *)buf.Pointer)->Package.Elements[0];
980 	if (gpe->Type == ACPI_TYPE_INTEGER) {
981 		*gpe_dev = NULL;
982 		*gpe_num = gpe->Integer.Value;
983 		status = AE_OK;
984 	} else if (gpe->Type == ACPI_TYPE_PACKAGE) {
985 		if ((gpe->Package.Count != 2) ||
986 		    (gpe->Package.Elements[0].Type != ACPI_TYPE_DEVICE) ||
987 		    (gpe->Package.Elements[1].Type != ACPI_TYPE_INTEGER))
988 			goto done;
989 		*gpe_dev = gpe->Package.Elements[0].Reference.Handle;
990 		*gpe_num = gpe->Package.Elements[1].Integer.Value;
991 		status = AE_OK;
992 	}
993 
994 done:
995 	AcpiOsFree(buf.Pointer);
996 	return (status);
997 }
998 
999 
1000 /*
1001  *
1002  */
1003 /*ARGSUSED*/
1004 static ACPI_STATUS
1005 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv)
1006 {
1007 
1008 	*((ACPI_HANDLE *)context) = obj;
1009 	return (AE_OK);
1010 }
1011 
1012 /*
1013  *
1014  */
1015 static ACPI_HANDLE
1016 probe_acpi_pwrbutton()
1017 {
1018 	ACPI_HANDLE obj = NULL;
1019 
1020 	(void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL);
1021 	return (obj);
1022 }
1023 
1024 static UINT32
1025 power_acpi_fixed_event(void *ctx)
1026 {
1027 
1028 	mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex);
1029 	power_button_pressed++;
1030 	mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex);
1031 
1032 	/* post softint to issue timeout for power button action */
1033 	if (((struct power_soft_state *)ctx)->softintr_id != NULL)
1034 		ddi_trigger_softintr(
1035 		    ((struct power_soft_state *)ctx)->softintr_id);
1036 
1037 	return (AE_OK);
1038 }
1039 
1040 /*ARGSUSED*/
1041 static void
1042 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx)
1043 {
1044 	if (val == 0x80)
1045 		(void) power_acpi_fixed_event(ctx);
1046 }
1047 
1048 /*
1049  *
1050  */
1051 static int
1052 power_probe_method_button(struct power_soft_state *softsp)
1053 {
1054 	ACPI_HANDLE button_obj;
1055 	UINT32 gpe_num;
1056 	ACPI_HANDLE gpe_dev;
1057 
1058 	button_obj = probe_acpi_pwrbutton();
1059 	softsp->button_obj = button_obj;	/* remember obj */
1060 	if ((button_obj != NULL) &&
1061 	    (power_get_prw_gpe(button_obj, &gpe_dev, &gpe_num) == AE_OK) &&
1062 	    (AcpiSetGpeType(gpe_dev, gpe_num, ACPI_GPE_TYPE_WAKE_RUN) ==
1063 	    AE_OK) &&
1064 	    (AcpiEnableGpe(gpe_dev, gpe_num, ACPI_NOT_ISR) == AE_OK) &&
1065 	    (AcpiInstallNotifyHandler(button_obj, ACPI_DEVICE_NOTIFY,
1066 	    power_acpi_notify_event, (void*)softsp) == AE_OK))
1067 		return (1);
1068 	return (0);
1069 }
1070 
1071 /*
1072  *
1073  */
1074 static int
1075 power_probe_fixed_button(struct power_soft_state *softsp)
1076 {
1077 	FADT_DESCRIPTOR *fadt;
1078 
1079 	if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING,
1080 	    (ACPI_TABLE_HEADER **) &fadt) != AE_OK)
1081 		return (0);
1082 
1083 	if (!fadt->PwrButton) {
1084 		if (AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1085 		    power_acpi_fixed_event, (void *)softsp) == AE_OK)
1086 			return (1);
1087 	}
1088 	return (0);
1089 }
1090 
1091 
1092 /*
1093  *
1094  */
1095 static int
1096 power_attach_acpi(struct power_soft_state *softsp)
1097 {
1098 
1099 	/*
1100 	 * If we've attached anything already, return an error
1101 	 */
1102 	if ((softsp->gpe_attached) || (softsp->fixed_attached))
1103 		return (DDI_FAILURE);
1104 
1105 	/*
1106 	 * attempt to attach both a fixed-event handler and a GPE
1107 	 * handler; remember what we got
1108 	 */
1109 	softsp->fixed_attached = (power_probe_fixed_button(softsp) != 0);
1110 	softsp->gpe_attached = (power_probe_method_button(softsp) != 0);
1111 
1112 	/*
1113 	 * If we've attached anything now, return success
1114 	 */
1115 	if ((softsp->gpe_attached) || (softsp->fixed_attached))
1116 		return (DDI_SUCCESS);
1117 
1118 	return (DDI_FAILURE);
1119 }
1120 
1121 /*
1122  *
1123  */
1124 static void
1125 power_detach_acpi(struct power_soft_state *softsp)
1126 {
1127 	if (softsp->gpe_attached) {
1128 		if (AcpiRemoveNotifyHandler(softsp->button_obj,
1129 		    ACPI_DEVICE_NOTIFY, power_acpi_notify_event) != AE_OK)
1130 			cmn_err(CE_WARN, "!power: failed to remove Notify"
1131 			    " handler");
1132 	}
1133 
1134 	if (softsp->fixed_attached) {
1135 		if (AcpiRemoveFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1136 		    power_acpi_fixed_event) != AE_OK)
1137 			cmn_err(CE_WARN, "!power: failed to remove Power"
1138 			    " Button handler");
1139 	}
1140 }
1141 
1142 #else
1143 /*
1144  * Code for platforms that have EPIC processor for processing power
1145  * button interrupts.
1146  */
1147 static int
1148 power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp)
1149 {
1150 	ddi_device_acc_attr_t	attr;
1151 	uint8_t *reg_base;
1152 
1153 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1154 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1155 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1156 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base,
1157 	    EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr,
1158 	    &softsp->power_rhandle) != DDI_SUCCESS) {
1159 		return (DDI_FAILURE);
1160 	}
1161 
1162 	softsp->power_btn_reg = reg_base;
1163 	softsp->power_regs_mapped = B_TRUE;
1164 
1165 	/* Clear power button interrupt first */
1166 	EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1167 	    EPIC_ATOM_INTR_CLEAR);
1168 
1169 	/* Enable EPIC interrupt for power button single press event */
1170 	EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1171 	    EPIC_ATOM_INTR_ENABLE);
1172 
1173 	/*
1174 	 * At this point, EPIC interrupt processing is fully initialised.
1175 	 */
1176 	hasEPIC = B_TRUE;
1177 	return (DDI_SUCCESS);
1178 }
1179 
1180 /*
1181  *
1182  * power button register definitions for acpi register on m1535d
1183  */
1184 #define	M1535D_PWR_BTN_REG_01		0x1
1185 #define	M1535D_PWR_BTN_EVENT_FLAG	0x1
1186 
1187 static int
1188 power_setup_m1535_regs(dev_info_t *dip, struct power_soft_state *softsp)
1189 {
1190 	ddi_device_acc_attr_t	attr;
1191 	uint8_t *reg_base;
1192 
1193 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1194 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1195 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1196 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base, 0, 0, &attr,
1197 	    &softsp->power_rhandle) != DDI_SUCCESS) {
1198 		return (DDI_FAILURE);
1199 	}
1200 	softsp->power_btn_reg = &reg_base[M1535D_PWR_BTN_REG_01];
1201 	softsp->power_btn_bit = M1535D_PWR_BTN_EVENT_FLAG;
1202 	softsp->power_regs_mapped = B_TRUE;
1203 	return (DDI_SUCCESS);
1204 }
1205 
1206 /*
1207  * MBC Fire/SSI Interrupt Status Register definitions
1208  */
1209 #define	FIRE_SSI_ISR			0x0
1210 #define	FIRE_SSI_INTR_ENA		0x8
1211 #define	FIRE_SSI_SHUTDOWN_REQ		0x4
1212 
1213 static int
1214 power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp)
1215 {
1216 	ddi_device_acc_attr_t   attr;
1217 	uint8_t *reg_base;
1218 	ddi_acc_handle_t hdl;
1219 	uint8_t reg;
1220 
1221 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1222 	attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1223 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1224 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&reg_base, 0, 0, &attr,
1225 	    &softsp->power_rhandle) != DDI_SUCCESS) {
1226 		return (DDI_FAILURE);
1227 	}
1228 	softsp->power_btn_reg = &reg_base[FIRE_SSI_ISR];
1229 	softsp->power_btn_bit = FIRE_SSI_SHUTDOWN_REQ;
1230 	hdl = softsp->power_rhandle;
1231 	/*
1232 	 * Clear MBC Fire Power Button interrupt, if set.
1233 	 */
1234 	reg = ddi_get8(hdl, softsp->power_btn_reg);
1235 	if (reg & softsp->power_btn_bit) {
1236 		reg &= softsp->power_btn_bit;
1237 		ddi_put8(hdl, softsp->power_btn_reg, reg);
1238 		(void) ddi_get8(hdl, softsp->power_btn_reg);
1239 	}
1240 	/*
1241 	 * Enable MBC Fire Power Button interrupt.
1242 	 */
1243 	reg = ddi_get8(hdl, &reg_base[FIRE_SSI_INTR_ENA]);
1244 	reg |= FIRE_SSI_SHUTDOWN_REQ;
1245 	ddi_put8(hdl, &reg_base[FIRE_SSI_INTR_ENA], reg);
1246 
1247 	softsp->power_regs_mapped = B_TRUE;
1248 
1249 	return (DDI_SUCCESS);
1250 }
1251 
1252 /*
1253  * Setup register map for the power button
1254  * NOTE:- we only map registers for platforms if
1255  * the OBP power device has any of the following
1256  * properties:
1257  *
1258  * a) Boston:  power-device-type set to "SUNW,mbc"
1259  * b) Seattle: power-device-type set to "SUNW,pic18lf65j10"
1260  * c) Chalupa: compatible set to "ali1535d+-power"
1261  *
1262  * Cases (a) and (b) are defined in FWARC 2005/687.
1263  * If none of the above conditions are true, then we
1264  * do not need to map in any registers, and this
1265  * function can simply return DDI_SUCCESS.
1266  */
1267 static int
1268 power_setup_regs(struct power_soft_state *softsp)
1269 {
1270 	char	*binding_name;
1271 	char	*power_type = NULL;
1272 	int	retval = DDI_SUCCESS;
1273 
1274 	softsp->power_regs_mapped = B_FALSE;
1275 	softsp->power_btn_ioctl = B_FALSE;
1276 	binding_name = ddi_binding_name(softsp->dip);
1277 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, softsp->dip,
1278 	    DDI_PROP_DONTPASS, POWER_DEVICE_TYPE,
1279 	    &power_type) == DDI_PROP_SUCCESS) {
1280 		if (strcmp(power_type, "SUNW,mbc") == 0) {
1281 			retval = power_setup_mbc_regs(softsp->dip, softsp);
1282 		} else if (strcmp(power_type, "SUNW,pic18lf65j10") == 0) {
1283 			retval = power_setup_epic_regs(softsp->dip, softsp);
1284 		} else {
1285 			cmn_err(CE_WARN, "unexpected power-device-type: %s\n",
1286 			    power_type);
1287 			retval = DDI_FAILURE;
1288 		}
1289 		ddi_prop_free(power_type);
1290 	} else if (strcmp(binding_name, "ali1535d+-power") == 0) {
1291 		retval = power_setup_m1535_regs(softsp->dip, softsp);
1292 	}
1293 
1294 	/*
1295 	 * If power-device-type does not exist AND the binding name is not
1296 	 * "ali1535d+-power", that means there is no additional HW and hence
1297 	 * no extra processing is necessary. In that case, retval should still
1298 	 * be set to its initial value of DDI_SUCCESS.
1299 	 */
1300 	return (retval);
1301 }
1302 
1303 static void
1304 power_free_regs(struct power_soft_state *softsp)
1305 {
1306 	if (softsp->power_regs_mapped)
1307 		ddi_regs_map_free(&softsp->power_rhandle);
1308 }
1309 #endif	/* ACPI_POWER_BUTTON */
1310