Annotation of sys/arch/macppc/dev/apm.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: apm.c,v 1.12 2006/01/18 23:21:17 miod Exp $ */
2:
3: /*-
4: * Copyright (c) 2001 Alexander Guy. All rights reserved.
5: * Copyright (c) 1998-2001 Michael Shalayeff. All rights reserved.
6: * Copyright (c) 1995 John T. Kohl. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: */
37:
38: #include "apm.h"
39:
40: #if NAPM > 1
41: #error only one APM emulation device may be configured
42: #endif
43:
44: #include <sys/param.h>
45: #include <sys/systm.h>
46: #include <sys/kernel.h>
47: #include <sys/proc.h>
48: #include <sys/device.h>
49: #include <sys/fcntl.h>
50: #include <sys/ioctl.h>
51: #include <sys/event.h>
52:
53: #include <machine/conf.h>
54: #include <machine/cpu.h>
55: #include <machine/apmvar.h>
56:
57: #include <dev/adb/adb.h>
58: #include <macppc/dev/adbvar.h>
59: #include <macppc/dev/pm_direct.h>
60:
61: #if defined(APMDEBUG)
62: #define DPRINTF(x) printf x
63: #else
64: #define DPRINTF(x) /**/
65: #endif
66:
67: struct apm_softc {
68: struct device sc_dev;
69: struct klist sc_note;
70: int sc_flags;
71: };
72:
73: int apmmatch(struct device *, void *, void *);
74: void apmattach(struct device *, struct device *, void *);
75:
76: struct cfattach apm_ca = {
77: sizeof(struct apm_softc), apmmatch, apmattach
78: };
79:
80: struct cfdriver apm_cd = {
81: NULL, "apm", DV_DULL
82: };
83:
84: #define APMUNIT(dev) (minor(dev)&0xf0)
85: #define APMDEV(dev) (minor(dev)&0x0f)
86: #define APMDEV_NORMAL 0
87: #define APMDEV_CTL 8
88:
89: void filt_apmrdetach(struct knote *kn);
90: int filt_apmread(struct knote *kn, long hint);
91: int apmkqfilter(dev_t dev, struct knote *kn);
92:
93: struct filterops apmread_filtops =
94: { 1, NULL, filt_apmrdetach, filt_apmread};
95:
96: /*
97: * Flags to control kernel display
98: * SCFLAG_NOPRINT: do not output APM power messages due to
99: * a power change event.
100: *
101: * SCFLAG_PCTPRINT: do not output APM power messages due to
102: * to a power change event unless the battery
103: * percentage changes.
104: */
105:
106: #define SCFLAG_NOPRINT 0x0008000
107: #define SCFLAG_PCTPRINT 0x0004000
108: #define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
109:
110: #define SCFLAG_OREAD (1 << 0)
111: #define SCFLAG_OWRITE (1 << 1)
112: #define SCFLAG_OPEN (SCFLAG_OREAD|SCFLAG_OWRITE)
113:
114:
115: int
116: apmmatch(struct device *parent, void *match, void *aux)
117: {
118: struct adb_attach_args *aa = (void *)aux;
119: if (aa->origaddr != ADBADDR_APM ||
120: aa->handler_id != ADBADDR_APM ||
121: aa->adbaddr != ADBADDR_APM)
122: return 0;
123:
124: if (adbHardware != ADB_HW_PMU)
125: return 0;
126:
127: return 1;
128: }
129:
130: void
131: apmattach(struct device *parent, struct device *self, void *aux)
132: {
133: struct pmu_battery_info info;
134:
135: pm_battery_info(0, &info);
136:
137: printf(": battery flags 0x%X, ", info.flags);
138: printf("%d%% charged\n", ((info.cur_charge * 100) / info.max_charge));
139: }
140:
141: int
142: apmopen(dev_t dev, int flag, int mode, struct proc *p)
143: {
144: struct apm_softc *sc;
145: int error = 0;
146:
147: /* apm0 only */
148: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
149: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
150: return ENXIO;
151:
152: DPRINTF(("apmopen: dev %d pid %d flag %x mode %x\n",
153: APMDEV(dev), p->p_pid, flag, mode));
154:
155: switch (APMDEV(dev)) {
156: case APMDEV_CTL:
157: if (!(flag & FWRITE)) {
158: error = EINVAL;
159: break;
160: }
161: if (sc->sc_flags & SCFLAG_OWRITE) {
162: error = EBUSY;
163: break;
164: }
165: sc->sc_flags |= SCFLAG_OWRITE;
166: break;
167: case APMDEV_NORMAL:
168: if (!(flag & FREAD) || (flag & FWRITE)) {
169: error = EINVAL;
170: break;
171: }
172: sc->sc_flags |= SCFLAG_OREAD;
173: break;
174: default:
175: error = ENXIO;
176: break;
177: }
178: return error;
179: }
180:
181: int
182: apmclose(dev_t dev, int flag, int mode, struct proc *p)
183: {
184: struct apm_softc *sc;
185:
186: /* apm0 only */
187: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
188: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
189: return ENXIO;
190:
191: DPRINTF(("apmclose: pid %d flag %x mode %x\n", p->p_pid, flag, mode));
192:
193: switch (APMDEV(dev)) {
194: case APMDEV_CTL:
195: sc->sc_flags &= ~SCFLAG_OWRITE;
196: break;
197: case APMDEV_NORMAL:
198: sc->sc_flags &= ~SCFLAG_OREAD;
199: break;
200: }
201: return 0;
202: }
203:
204: int
205: apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
206: {
207: struct apm_softc *sc;
208: struct pmu_battery_info batt;
209: struct apm_power_info *power;
210: int error = 0;
211:
212: /* apm0 only */
213: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
214: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
215: return ENXIO;
216:
217: switch (cmd) {
218: /* some ioctl names from linux */
219: case APM_IOC_STANDBY:
220: if ((flag & FWRITE) == 0)
221: error = EBADF;
222: break;
223: case APM_IOC_SUSPEND:
224: if ((flag & FWRITE) == 0)
225: error = EBADF;
226: break;
227: case APM_IOC_PRN_CTL:
228: if ((flag & FWRITE) == 0)
229: error = EBADF;
230: else {
231: int flag = *(int *)data;
232: DPRINTF(( "APM_IOC_PRN_CTL: %d\n", flag ));
233: switch (flag) {
234: case APM_PRINT_ON: /* enable printing */
235: sc->sc_flags &= ~SCFLAG_PRINT;
236: break;
237: case APM_PRINT_OFF: /* disable printing */
238: sc->sc_flags &= ~SCFLAG_PRINT;
239: sc->sc_flags |= SCFLAG_NOPRINT;
240: break;
241: case APM_PRINT_PCT: /* disable some printing */
242: sc->sc_flags &= ~SCFLAG_PRINT;
243: sc->sc_flags |= SCFLAG_PCTPRINT;
244: break;
245: default:
246: error = EINVAL;
247: break;
248: }
249: }
250: break;
251: case APM_IOC_DEV_CTL:
252: if ((flag & FWRITE) == 0)
253: error = EBADF;
254: break;
255: case APM_IOC_GETPOWER:
256: power = (struct apm_power_info *)data;
257:
258: pm_battery_info(0, &batt);
259:
260: power->ac_state = ((batt.flags & PMU_PWR_AC_PRESENT) ?
261: APM_AC_ON : APM_AC_OFF);
262: power->battery_life =
263: ((batt.cur_charge * 100) / batt.max_charge);
264:
265: /*
266: * If the battery is charging, return the minutes left until
267: * charging is complete. apmd knows this.
268: */
269:
270: if (!(batt.flags & PMU_PWR_BATT_PRESENT)) {
271: power->battery_state = APM_BATT_UNKNOWN;
272: power->minutes_left = 0;
273: power->battery_life = 0;
274: } else if ((power->ac_state == APM_AC_ON) &&
275: (batt.draw > 0)) {
276: power->minutes_left =
277: (((batt.max_charge - batt.cur_charge) * 3600) /
278: batt.draw) / 60;
279: power->battery_state = APM_BATT_CHARGING;
280: } else {
281: power->minutes_left =
282: ((batt.cur_charge * 3600) / (-batt.draw)) / 60;
283:
284: /* XXX - Arbitrary */
285: if (power->battery_life > 60)
286: power->battery_state = APM_BATT_HIGH;
287: else if (power->battery_life < 10)
288: power->battery_state = APM_BATT_CRITICAL;
289: else
290: power->battery_state = APM_BATT_LOW;
291: }
292: break;
293:
294: default:
295: error = ENOTTY;
296: }
297:
298: return error;
299: }
300:
301: void
302: filt_apmrdetach(struct knote *kn)
303: {
304: struct apm_softc *sc = (struct apm_softc *)kn->kn_hook;
305:
306: SLIST_REMOVE(&sc->sc_note, kn, knote, kn_selnext);
307: }
308:
309: int
310: filt_apmread(struct knote *kn, long hint)
311: {
312: /* XXX weird kqueue_scan() semantics */
313: if (hint && !kn->kn_data)
314: kn->kn_data = (int)hint;
315:
316: return (1);
317: }
318:
319: int
320: apmkqfilter(dev_t dev, struct knote *kn)
321: {
322: struct apm_softc *sc;
323:
324: /* apm0 only */
325: if (!apm_cd.cd_ndevs || APMUNIT(dev) != 0 ||
326: !(sc = apm_cd.cd_devs[APMUNIT(dev)]))
327: return ENXIO;
328:
329: switch (kn->kn_filter) {
330: case EVFILT_READ:
331: kn->kn_fop = &apmread_filtops;
332: break;
333: default:
334: return (1);
335: }
336:
337: kn->kn_hook = (caddr_t)sc;
338: SLIST_INSERT_HEAD(&sc->sc_note, kn, kn_selnext);
339:
340: return (0);
341: }
CVSweb