1 /* $NetBSD: apm.c,v 1.24 2009/09/16 16:34:49 dyoung Exp $ */
4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by John Kohl and Christopher G. Demetriou.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 * from: sys/arch/i386/i386/apm.c,v 1.49 2000/05/08
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: apm.c,v 1.24 2009/09/16 16:34:49 dyoung Exp $");
41 #error APM_NOIDLE option deprecated; use APM_NO_IDLE instead
44 #if defined(DEBUG) && !defined(APMDEBUG)
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/signalvar.h>
51 #include <sys/kernel.h>
53 #include <sys/kthread.h>
54 #include <sys/malloc.h>
55 #include <sys/device.h>
56 #include <sys/fcntl.h>
57 #include <sys/ioctl.h>
58 #include <sys/select.h>
62 #include <dev/apm/apmvar.h>
64 #include <machine/stdarg.h>
67 #define DPRINTF(f, x) do { if (apmdebug & (f)) printf x; } while (0)
71 int apmdebug
= APMDEBUG_VALUE
;
74 #endif /* APMDEBUG_VALUE */
77 #define DPRINTF(f, x) /**/
80 #define SCFLAG_OREAD 0x0000001
81 #define SCFLAG_OWRITE 0x0000002
82 #define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
84 #define APMUNIT(dev) (minor(dev)&0xf0)
85 #define APM(dev) (minor(dev)&0x0f)
90 * A brief note on the locking protocol: it's very simple; we
91 * assert an exclusive lock any time thread context enters the
92 * APM module. This is both the APM thread itself, as well as
95 #define APM_LOCK(apmsc) \
96 (void) mutex_enter(&(apmsc)->sc_lock)
97 #define APM_UNLOCK(apmsc) \
98 (void) mutex_exit(&(apmsc)->sc_lock)
100 static void apm_event_handle(struct apm_softc
*, u_int
, u_int
);
101 static void apm_periodic_check(struct apm_softc
*);
102 static void apm_thread(void *);
103 static void apm_perror(const char *, int, ...)
104 __attribute__((__format__(__printf__
,1,3)));
105 #ifdef APM_POWER_PRINT
106 static void apm_power_print(struct apm_softc
*, struct apm_power_info
*);
108 static int apm_record_event(struct apm_softc
*, u_int
);
109 static void apm_set_ver(struct apm_softc
*);
110 static void apm_standby(struct apm_softc
*);
111 static void apm_suspend(struct apm_softc
*);
112 static void apm_resume(struct apm_softc
*, u_int
, u_int
);
114 extern struct cfdriver apm_cd
;
116 dev_type_open(apmopen
);
117 dev_type_close(apmclose
);
118 dev_type_ioctl(apmioctl
);
119 dev_type_poll(apmpoll
);
120 dev_type_kqfilter(apmkqfilter
);
122 const struct cdevsw apm_cdevsw
= {
123 apmopen
, apmclose
, noread
, nowrite
, apmioctl
,
124 nostop
, notty
, apmpoll
, nommap
, apmkqfilter
, D_OTHER
,
127 /* configurable variables */
128 int apm_bogus_bios
= 0;
139 #ifdef APM_NO_STANDBY
140 int apm_do_standby
= 0;
142 int apm_do_standby
= 1;
145 int apm_v11_enabled
= 0;
147 int apm_v11_enabled
= 1;
150 int apm_v12_enabled
= 0;
152 int apm_v12_enabled
= 1;
154 #ifdef APM_FORCE_64K_SEGMENTS
155 int apm_force_64k_segments
= 1;
157 int apm_force_64k_segments
= 0;
159 #ifdef APM_ALLOW_BOGUS_SEGMENTS
160 int apm_allow_bogus_segments
= 1;
162 int apm_allow_bogus_segments
= 0;
165 /* variables used during operation (XXX cgd) */
166 u_char apm_majver
, apm_minver
;
168 int apm_standbys
, apm_userstandbys
, apm_suspends
, apm_battlow
;
169 int apm_damn_fool_bios
, apm_op_inprog
;
172 static int apm_spl
; /* saved spl while suspended */
175 apm_strerror(int code
)
178 case APM_ERR_PM_DISABLED
:
179 return ("power management disabled");
180 case APM_ERR_REALALREADY
:
181 return ("real mode interface already connected");
182 case APM_ERR_NOTCONN
:
183 return ("interface not connected");
184 case APM_ERR_16ALREADY
:
185 return ("16-bit interface already connected");
186 case APM_ERR_16NOTSUPP
:
187 return ("16-bit interface not supported");
188 case APM_ERR_32ALREADY
:
189 return ("32-bit interface already connected");
190 case APM_ERR_32NOTSUPP
:
191 return ("32-bit interface not supported");
192 case APM_ERR_UNRECOG_DEV
:
193 return ("unrecognized device ID");
195 return ("parameter out of range");
196 case APM_ERR_NOTENGAGED
:
197 return ("interface not engaged");
199 return ("unable to enter requested state");
200 case APM_ERR_NOEVENTS
:
201 return ("no pending events");
202 case APM_ERR_NOT_PRESENT
:
203 return ("no APM present");
205 return ("unknown error code");
210 apm_perror(const char *str
, int errinfo
, ...) /* XXX cgd */
216 va_start(ap
, errinfo
);
217 vprintf(str
, ap
); /* XXX cgd */
220 printf(": %s\n", apm_strerror(errinfo
));
223 #ifdef APM_POWER_PRINT
225 apm_power_print(struct apm_softc
*sc
, struct apm_power_info
*pi
)
228 if (pi
->battery_life
!= APM_BATT_LIFE_UNKNOWN
) {
229 aprint_normal_dev(sc
->sc_dev
,
230 "battery life expectancy: %d%%\n",
233 aprint_normal_dev(sc
->sc_dev
, "A/C state: ");
234 switch (pi
->ac_state
) {
242 printf("backup power\n");
249 aprint_normal_dev(sc
->sc_dev
, "battery charge state:");
251 switch (pi
->battery_state
) {
258 case APM_BATT_CRITICAL
:
259 printf("critical\n");
261 case APM_BATT_CHARGING
:
262 printf("charging\n");
264 case APM_BATT_UNKNOWN
:
268 printf("undecoded state %x\n", pi
->battery_state
);
271 else if (apm_minver
>= 1) {
272 if (pi
->battery_flags
& APM_BATT_FLAG_NO_SYSTEM_BATTERY
)
273 printf(" no battery");
275 if (pi
->battery_flags
& APM_BATT_FLAG_HIGH
)
277 if (pi
->battery_flags
& APM_BATT_FLAG_LOW
)
279 if (pi
->battery_flags
& APM_BATT_FLAG_CRITICAL
)
281 if (pi
->battery_flags
& APM_BATT_FLAG_CHARGING
)
285 if (pi
->minutes_valid
) {
286 aprint_normal_dev(sc
->sc_dev
, "estimated ");
287 if (pi
->minutes_left
/ 60)
288 printf("%dh ", pi
->minutes_left
/ 60);
289 printf("%dm\n", pi
->minutes_left
% 60);
297 apm_suspend(struct apm_softc
*sc
)
301 if (sc
->sc_power_state
== PWR_SUSPEND
) {
303 aprint_debug_dev(sc
->sc_dev
,
304 "apm_suspend: already suspended?\n");
308 sc
->sc_power_state
= PWR_SUSPEND
;
310 if (!(sc
->sc_hwflags
& APM_F_DONT_RUN_HOOKS
)) {
311 pmf_system_suspend(PMF_Q_NONE
);
315 error
= (*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
, APM_DEV_ALLDEVS
,
319 apm_resume(sc
, 0, 0);
323 apm_standby(struct apm_softc
*sc
)
327 if (sc
->sc_power_state
== PWR_STANDBY
) {
329 aprint_debug_dev(sc
->sc_dev
,
330 "apm_standby: already standing by?\n");
334 sc
->sc_power_state
= PWR_STANDBY
;
336 if (!(sc
->sc_hwflags
& APM_F_DONT_RUN_HOOKS
)) {
337 pmf_system_suspend(PMF_Q_NONE
);
340 error
= (*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
, APM_DEV_ALLDEVS
,
343 apm_resume(sc
, 0, 0);
347 apm_resume(struct apm_softc
*sc
, u_int event_type
, u_int event_info
)
350 if (sc
->sc_power_state
== PWR_RESUME
) {
352 aprint_debug_dev(sc
->sc_dev
, "apm_resume: already running?\n");
356 sc
->sc_power_state
= PWR_RESUME
;
360 * Some system requires its clock to be initialized after hybernation.
362 initrtclock(TIMER_FREQ
);
365 inittodr(time_second
);
366 if (!(sc
->sc_hwflags
& APM_F_DONT_RUN_HOOKS
)) {
368 pmf_system_resume(PMF_Q_NONE
);
371 apm_record_event(sc
, event_type
);
375 * return 0 if the user will notice and handle the event,
376 * return 1 if the kernel driver should do so.
379 apm_record_event(struct apm_softc
*sc
, u_int event_type
)
381 struct apm_event_info
*evp
;
383 if ((sc
->sc_flags
& SCFLAG_OPEN
) == 0)
384 return 1; /* no user waiting */
385 if (sc
->sc_event_count
== APM_NEVENTS
)
386 return 1; /* overflow */
387 evp
= &sc
->sc_event_list
[sc
->sc_event_ptr
];
388 sc
->sc_event_count
++;
390 sc
->sc_event_ptr
%= APM_NEVENTS
;
391 evp
->type
= event_type
;
392 evp
->index
= ++apm_evindex
;
393 selnotify(&sc
->sc_rsel
, 0, 0);
394 return (sc
->sc_flags
& SCFLAG_OWRITE
) ? 0 : 1; /* user may handle */
398 apm_event_handle(struct apm_softc
*sc
, u_int event_code
, u_int event_info
)
402 struct apm_power_info pi
;
404 switch (event_code
) {
405 case APM_USER_STANDBY_REQ
:
406 DPRINTF(APMDEBUG_EVENTS
, ("apmev: user standby request\n"));
407 if (apm_do_standby
) {
408 if (apm_op_inprog
== 0 && apm_record_event(sc
, event_code
))
411 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
412 APM_DEV_ALLDEVS
, APM_LASTREQ_INPROG
);
414 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
415 APM_DEV_ALLDEVS
, APM_LASTREQ_REJECTED
);
416 /* in case BIOS hates being spurned */
417 (*sc
->sc_ops
->aa_enable
)(sc
->sc_cookie
, 1);
421 case APM_STANDBY_REQ
:
422 DPRINTF(APMDEBUG_EVENTS
, ("apmev: system standby request\n"));
423 if (apm_standbys
|| apm_suspends
) {
424 DPRINTF(APMDEBUG_EVENTS
| APMDEBUG_ANOM
,
425 ("damn fool BIOS did not wait for answer\n"));
426 /* just give up the fight */
427 apm_damn_fool_bios
= 1;
429 if (apm_do_standby
) {
430 if (apm_op_inprog
== 0 &&
431 apm_record_event(sc
, event_code
))
434 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
435 APM_DEV_ALLDEVS
, APM_LASTREQ_INPROG
);
437 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
438 APM_DEV_ALLDEVS
, APM_LASTREQ_REJECTED
);
439 /* in case BIOS hates being spurned */
440 (*sc
->sc_ops
->aa_enable
)(sc
->sc_cookie
, 1);
444 case APM_USER_SUSPEND_REQ
:
445 DPRINTF(APMDEBUG_EVENTS
, ("apmev: user suspend request\n"));
446 if (apm_op_inprog
== 0 && apm_record_event(sc
, event_code
))
449 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
450 APM_DEV_ALLDEVS
, APM_LASTREQ_INPROG
);
453 case APM_SUSPEND_REQ
:
454 DPRINTF(APMDEBUG_EVENTS
, ("apmev: system suspend request\n"));
455 if (apm_standbys
|| apm_suspends
) {
456 DPRINTF(APMDEBUG_EVENTS
| APMDEBUG_ANOM
,
457 ("damn fool BIOS did not wait for answer\n"));
458 /* just give up the fight */
459 apm_damn_fool_bios
= 1;
461 if (apm_op_inprog
== 0 && apm_record_event(sc
, event_code
))
464 (void)(*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
,
465 APM_DEV_ALLDEVS
, APM_LASTREQ_INPROG
);
468 case APM_POWER_CHANGE
:
469 DPRINTF(APMDEBUG_EVENTS
, ("apmev: power status change\n"));
470 error
= (*sc
->sc_ops
->aa_get_powstat
)(sc
->sc_cookie
, 0, &pi
);
471 #ifdef APM_POWER_PRINT
472 /* only print if nobody is catching events. */
474 (sc
->sc_flags
& (SCFLAG_OREAD
|SCFLAG_OWRITE
)) == 0)
475 apm_power_print(sc
, &pi
);
477 apm_record_event(sc
, event_code
);
480 case APM_NORMAL_RESUME
:
481 DPRINTF(APMDEBUG_EVENTS
, ("apmev: resume system\n"));
482 apm_resume(sc
, event_code
, event_info
);
485 case APM_CRIT_RESUME
:
486 DPRINTF(APMDEBUG_EVENTS
, ("apmev: critical resume system"));
487 apm_resume(sc
, event_code
, event_info
);
490 case APM_SYS_STANDBY_RESUME
:
491 DPRINTF(APMDEBUG_EVENTS
, ("apmev: system standby resume\n"));
492 apm_resume(sc
, event_code
, event_info
);
495 case APM_UPDATE_TIME
:
496 DPRINTF(APMDEBUG_EVENTS
, ("apmev: update time\n"));
497 apm_resume(sc
, event_code
, event_info
);
500 case APM_CRIT_SUSPEND_REQ
:
501 DPRINTF(APMDEBUG_EVENTS
, ("apmev: critical system suspend\n"));
502 apm_record_event(sc
, event_code
);
506 case APM_BATTERY_LOW
:
507 DPRINTF(APMDEBUG_EVENTS
, ("apmev: battery low\n"));
509 apm_record_event(sc
, event_code
);
513 DPRINTF(APMDEBUG_EVENTS
, ("apmev: capability change\n"));
514 if (apm_minver
< 2) {
515 DPRINTF(APMDEBUG_EVENTS
, ("apm: unexpected event\n"));
517 u_int numbatts
, capflags
;
518 (*sc
->sc_ops
->aa_get_capabilities
)(sc
->sc_cookie
,
519 &numbatts
, &capflags
);
520 (*sc
->sc_ops
->aa_get_powstat
)(sc
->sc_cookie
, 0, &pi
);
525 switch (event_code
>> 8) {
527 code
= "reserved system";
530 code
= "reserved device";
533 code
= "OEM defined";
539 printf("APM: %s event code %x\n", code
, event_code
);
544 apm_periodic_check(struct apm_softc
*sc
)
547 u_int event_code
, event_info
;
551 * tell the BIOS we're working on it, if asked to do a
555 (*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
, APM_DEV_ALLDEVS
,
558 while ((error
= (*sc
->sc_ops
->aa_get_event
)(sc
->sc_cookie
, &event_code
,
559 &event_info
)) == 0 && !apm_damn_fool_bios
)
560 apm_event_handle(sc
, event_code
, event_info
);
562 if (error
!= APM_ERR_NOEVENTS
)
563 apm_perror("get event", error
);
567 } else if (apm_standbys
|| apm_userstandbys
) {
571 apm_suspends
= apm_standbys
= apm_battlow
= apm_userstandbys
= 0;
572 apm_damn_fool_bios
= 0;
576 apm_set_ver(struct apm_softc
*sc
)
579 if (apm_v12_enabled
&&
580 APM_MAJOR_VERS(sc
->sc_vers
) == 1 &&
581 APM_MINOR_VERS(sc
->sc_vers
) == 2) {
587 if (apm_v11_enabled
&&
588 APM_MAJOR_VERS(sc
->sc_vers
) == 1 &&
589 APM_MINOR_VERS(sc
->sc_vers
) == 1) {
597 aprint_normal("Power Management spec V%d.%d", apm_majver
, apm_minver
);
599 if (sc
->sc_detail
& APM_IDLE_SLOWS
) {
601 /* not relevant often */
602 aprint_normal(" (slowidle)");
604 /* leave apm_do_idle at its user-configured setting */
608 if (sc
->sc_detail
& APM_BIOS_PM_DISABLED
)
609 aprint_normal(" (BIOS mgmt disabled)");
610 if (sc
->sc_detail
& APM_BIOS_PM_DISENGAGED
)
611 aprint_normal(" (BIOS managing devices)");
623 apm_attach(struct apm_softc
*sc
)
625 u_int numbatts
, capflags
;
629 switch ((APM_MAJOR_VERS(sc
->sc_vers
) << 8) + APM_MINOR_VERS(sc
->sc_vers
)) {
642 apm_set_ver(sc
); /* prints version info */
645 (*sc
->sc_ops
->aa_get_capabilities
)(sc
->sc_cookie
, &numbatts
,
649 * enable power management
651 (*sc
->sc_ops
->aa_enable
)(sc
->sc_cookie
, 1);
653 if (sc
->sc_ops
->aa_cpu_busy
)
654 (*sc
->sc_ops
->aa_cpu_busy
)(sc
->sc_cookie
);
656 mutex_init(&sc
->sc_lock
, MUTEX_DEFAULT
, IPL_NONE
);
658 /* Initial state is `resumed'. */
659 sc
->sc_power_state
= PWR_RESUME
;
660 selinit(&sc
->sc_rsel
);
661 selinit(&sc
->sc_xsel
);
663 /* Do an initial check. */
664 apm_periodic_check(sc
);
667 * Create a kernel thread to periodically check for APM events,
668 * and notify other subsystems when they occur.
670 if (kthread_create(PRI_NONE
, 0, NULL
, apm_thread
, sc
,
671 &sc
->sc_thread
, "%s", device_xname(sc
->sc_dev
)) != 0) {
673 * We were unable to create the APM thread; bail out.
675 if (sc
->sc_ops
->aa_disconnect
)
676 (*sc
->sc_ops
->aa_disconnect
)(sc
->sc_cookie
);
677 aprint_error_dev(sc
->sc_dev
, "unable to create thread, "
678 "kernel APM support disabled\n");
681 if (!pmf_device_register(sc
->sc_dev
, NULL
, NULL
))
682 aprint_error_dev(sc
->sc_dev
, "couldn't establish power handler\n");
686 apm_thread(void *arg
)
688 struct apm_softc
*apmsc
= arg
;
691 * Loop forever, doing a periodic check for APM events.
695 apm_periodic_check(apmsc
);
697 (void) tsleep(apmsc
, PWAIT
, "apmev", (8 * hz
) / 7);
702 apmopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
706 struct apm_softc
*sc
;
708 sc
= device_lookup_private(&apm_cd
, APMUNIT(dev
));
715 DPRINTF(APMDEBUG_DEVICE
,
716 ("apmopen: pid %d flag %x mode %x\n", l
->l_proc
->p_pid
, flag
, mode
));
721 if (!(flag
& FWRITE
)) {
725 if (sc
->sc_flags
& SCFLAG_OWRITE
) {
729 sc
->sc_flags
|= SCFLAG_OWRITE
;
732 if (!(flag
& FREAD
) || (flag
& FWRITE
)) {
736 sc
->sc_flags
|= SCFLAG_OREAD
;
748 apmclose(dev_t dev
, int flag
, int mode
,
751 struct apm_softc
*sc
= device_lookup_private(&apm_cd
, APMUNIT(dev
));
754 DPRINTF(APMDEBUG_DEVICE
,
755 ("apmclose: pid %d flag %x mode %x\n", l
->l_proc
->p_pid
, flag
, mode
));
760 sc
->sc_flags
&= ~SCFLAG_OWRITE
;
763 sc
->sc_flags
&= ~SCFLAG_OREAD
;
766 if ((sc
->sc_flags
& SCFLAG_OPEN
) == 0) {
767 sc
->sc_event_count
= 0;
768 sc
->sc_event_ptr
= 0;
775 apmioctl(dev_t dev
, u_long cmd
, void *data
, int flag
,
778 struct apm_softc
*sc
= device_lookup_private(&apm_cd
, APMUNIT(dev
));
779 struct apm_power_info
*powerp
;
780 struct apm_event_info
*evp
;
782 struct apm_ctl
*actl
;
786 struct apm_ctl
*actl
;
790 case APM_IOC_STANDBY
:
791 if (!apm_do_standby
) {
796 if ((flag
& FWRITE
) == 0) {
803 case APM_IOC_DEV_CTL
:
804 actl
= (struct apm_ctl
*)data
;
805 if ((flag
& FWRITE
) == 0) {
810 apm_get_powstate(actl
->dev
); /* XXX */
812 error
= (*sc
->sc_ops
->aa_set_powstate
)(sc
->sc_cookie
, actl
->dev
,
817 case APM_IOC_SUSPEND
:
818 if ((flag
& FWRITE
) == 0) {
825 case APM_IOC_NEXTEVENT
:
826 if (!sc
->sc_event_count
)
829 evp
= (struct apm_event_info
*)data
;
830 i
= sc
->sc_event_ptr
+ APM_NEVENTS
- sc
->sc_event_count
;
832 *evp
= sc
->sc_event_list
[i
];
833 sc
->sc_event_count
--;
837 case OAPM_IOC_GETPOWER
:
838 case APM_IOC_GETPOWER
:
839 powerp
= (struct apm_power_info
*)data
;
840 if ((error
= (*sc
->sc_ops
->aa_get_powstat
)(sc
->sc_cookie
, 0,
842 apm_perror("ioctl get power status", error
);
846 switch (apm_minver
) {
851 batt_flags
= powerp
->battery_flags
;
852 powerp
->battery_state
= APM_BATT_UNKNOWN
;
853 if (batt_flags
& APM_BATT_FLAG_HIGH
)
854 powerp
->battery_state
= APM_BATT_HIGH
;
855 else if (batt_flags
& APM_BATT_FLAG_LOW
)
856 powerp
->battery_state
= APM_BATT_LOW
;
857 else if (batt_flags
& APM_BATT_FLAG_CRITICAL
)
858 powerp
->battery_state
= APM_BATT_CRITICAL
;
859 else if (batt_flags
& APM_BATT_FLAG_CHARGING
)
860 powerp
->battery_state
= APM_BATT_CHARGING
;
861 else if (batt_flags
& APM_BATT_FLAG_NO_SYSTEM_BATTERY
)
862 powerp
->battery_state
= APM_BATT_ABSENT
;
876 apmpoll(dev_t dev
, int events
, struct lwp
*l
)
878 struct apm_softc
*sc
= device_lookup_private(&apm_cd
, APMUNIT(dev
));
882 if (events
& (POLLIN
| POLLRDNORM
)) {
883 if (sc
->sc_event_count
)
884 revents
|= events
& (POLLIN
| POLLRDNORM
);
886 selrecord(l
, &sc
->sc_rsel
);
894 filt_apmrdetach(struct knote
*kn
)
896 struct apm_softc
*sc
= kn
->kn_hook
;
899 SLIST_REMOVE(&sc
->sc_rsel
.sel_klist
, kn
, knote
, kn_selnext
);
904 filt_apmread(struct knote
*kn
, long hint
)
906 struct apm_softc
*sc
= kn
->kn_hook
;
908 kn
->kn_data
= sc
->sc_event_count
;
909 return (kn
->kn_data
> 0);
912 static const struct filterops apmread_filtops
=
913 { 1, NULL
, filt_apmrdetach
, filt_apmread
};
916 apmkqfilter(dev_t dev
, struct knote
*kn
)
918 struct apm_softc
*sc
= device_lookup_private(&apm_cd
, APMUNIT(dev
));
921 switch (kn
->kn_filter
) {
923 klist
= &sc
->sc_rsel
.sel_klist
;
924 kn
->kn_fop
= &apmread_filtops
;
934 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);