|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright 1994 NeXT Computer, Inc.
27: * All rights reserved.
28: */
29:
30: /*
31: * Power Management (PM) kernel interface.
32: * This implementation uses the Microsoft/Intel APM 1.1 interface.
33: */
34:
35: #import <bsd/sys/time.h>
36:
37: #import <kern/power.h>
38:
39: #import <mach/mach_types.h>
40:
41: #import <machdep/i386/pmap.h>
42: #import <machdep/i386/seg.h>
43: #import <machdep/i386/table_inline.h>
44: #import <machdep/i386/desc_inline.h>
45: #import <machdep/i386/kernBootStruct.h>
46: #import <machdep/i386/bios.h>
47: #import <machdep/i386/APM_BIOS.h>
48:
49: static boolean_t APM_BIOS_connected;
50: static struct {
51: unsigned major;
52: unsigned minor;
53: } APM_BIOS_version;
54:
55: #define VERSION_EQ(maj,min) ((APM_BIOS_version.major == (maj)) && \
56: (APM_BIOS_version.minor == (min)))
57: #define VERSION_GE(maj,min) ((APM_BIOS_version.major > (maj)) || \
58: ((APM_BIOS_version.major == (maj)) && \
59: (APM_BIOS_version.minor >= (min))))
60: /*
61: * Note: we assume that the power management version is 1.0,
62: * because some machine report a bogus version.
63: * If we do the standard 1.0 "APM Connect" BIOS call in the booter,
64: * then the BIOS should give us APM 1.0 behavior.
65: */
66:
67: static void
68: setUpGdtEntries()
69: {
70: KERNBOOTSTRUCT *kbp = KERNSTRUCT_ADDR;
71:
72: map_code((data_desc_t *) sel_to_gdt_entry(APMCODE32_SEL),
73: (vm_offset_t) KERNEL_LINEAR_BASE + kbp->apm_config.cs32_base,
74: (vm_size_t) kbp->apm_config.cs_length,
75: KERN_PRIV,
76: FALSE
77: );
78:
79: map_code_16((data_desc_t *) sel_to_gdt_entry(APMCODE16_SEL),
80: (vm_offset_t) KERNEL_LINEAR_BASE + kbp->apm_config.cs16_base,
81: (vm_size_t) kbp->apm_config.cs_length,
82: KERN_PRIV,
83: FALSE
84: );
85:
86: map_data((data_desc_t *) sel_to_gdt_entry(APMDATA_SEL),
87: (vm_offset_t) KERNEL_LINEAR_BASE + kbp->apm_config.ds_base,
88: (vm_size_t) kbp->apm_config.ds_length,
89: KERN_PRIV,
90: FALSE
91: );
92:
93: APM_BIOS_addr = kbp->apm_config.entry_offset;
94: }
95:
96: /*
97: * Initialize PM support. Returns TRUE if PM is available.
98: */
99: PMReturn PMConnect(void)
100: {
101: KERNBOOTSTRUCT *kbp = KERNSTRUCT_ADDR;
102:
103: APM_BIOS_version.major = kbp->apm_config.major_vers;
104: APM_BIOS_version.minor = kbp->apm_config.minor_vers;
105:
106: if (kbp->apm_config.connected) {
107: APM_BIOS_connected = TRUE;
108: setUpGdtEntries();
109: printf("Power management is enabled.\n");
110: return PM_R_SUCCESS;
111: }
112: return PM_R_NO_PM;
113: }
114:
115: /*
116: * Return PM control to previous user (probably the BIOS).
117: */
118: PMReturn PMDisconnect(void)
119: {
120: return PM_R_SUCCESS;
121: }
122:
123: /*
124: * Inform PM of the CPU state. If the CPU is idle, PM may
125: * put the CPU in a power-saving state until the next system event
126: * (typically an interrupt). Marking the CPU busy will ensure
127: * that the CPU is running at full speed.
128: */
129: PMReturn PMSetCpuState(
130: PMCpuState state
131: )
132: {
133: boolean_t ret;
134:
135: if (APM_BIOS_connected) {
136: switch (state) {
137: case PM_CPU_IDLE:
138: ret = APMBIOS_Idle();
139: break;
140: case PM_CPU_BUSY:
141: ret = APMBIOS_Busy();
142: break;
143: default:
144: ret = FALSE;
145: }
146: if (ret == FALSE)
147: return PM_R_BAD_STATE;
148: } else {
149: if (state == PM_CPU_IDLE) {
150: asm volatile("hlt");
151: }
152: }
153: return PM_R_SUCCESS;
154: }
155:
156: /*
157: * Set the power state of a device or the entire computer.
158: */
159: PMReturn PMSetPowerState(
160: PMDeviceID device,
161: PMPowerState state
162: )
163: {
164: union {
165: struct {
166: unsigned int deviceNumber :8;
167: unsigned int deviceType :8;
168: } device;
169: unsigned short data;
170: } du;
171: union {
172: PMPowerState state;
173: unsigned short data;
174: } su;
175: PMReturn ret;
176:
177: /* Eventually this should differentiate between devices. */
178: if (device.deviceType == PM_SYSTEM && device.deviceNumber == 1) {
179: _io_setDriverPowerState(state);
180: }
181:
182: if (APM_BIOS_connected) {
183: if (device.deviceType == PM_SYSTEM && device.deviceNumber == 1) {
184: /*
185: * In PM 1.1 and 1.0,
186: * you can't set the system state to "ready".
187: */
188: if (state == PM_READY)
189: return PM_R_BAD_STATE;
190: /*
191: * In PM 1.0, you can't set the system state to "off".
192: */
193: if (state == PM_OFF)
194: return PM_R_BAD_STATE;
195: }
196: du.device.deviceNumber = device.deviceNumber;
197: du.device.deviceType = device.deviceType;
198: su.state = state;
199: return APMBIOS_SetPowerState(du.data, su.data);
200: }
201: return PM_R_NOT_CONNECTED;
202: }
203:
204: /*
205: * Get a power event from PM, if one has occurred.
206: */
207: PMReturn PMGetPowerEvent(
208: PMPowerEvent *event
209: )
210: {
211: unsigned short event_code;
212: PMReturn ret;
213:
214: if (APM_BIOS_connected) {
215: if ((ret = APMBIOS_GetPowerEvent(&event_code)) == PM_R_SUCCESS) {
216: *event = (PMPowerEvent)event_code;
217: return PM_R_SUCCESS;
218: }
219: return ret;
220: }
221: return PM_R_NOT_CONNECTED;
222: }
223:
224: /*
225: * Get the power state of the computer.
226: */
227: PMReturn PMGetPowerStatus(
228: PMPowerStatus *status
229: )
230: {
231: unsigned char line_status, batt_status, batt_life;
232: PMReturn ret;
233:
234: if (APM_BIOS_connected) {
235: if ((ret = APMBIOS_GetPowerStatus(&line_status, &batt_status,
236: &batt_life)) == PM_R_SUCCESS) {
237: status->lineStatus = (PMLineStatus)line_status;
238: status->batteryStatus = (PMBatteryStatus)batt_status;
239: status->batteryLife = (batt_life == 0xFF) ? -1 : (int)batt_life;
240: return PM_R_SUCCESS;
241: } else {
242: return ret;
243: }
244: }
245: return PM_R_NOT_CONNECTED;
246: }
247:
248: /*
249: * Enable or disable power management by the computer.
250: * If enable == PM_ENABLED, the computer can take power saving steps
251: * when the CPU state is idle. If enable == PM_DISABLED, no automatic
252: * power saving steps will be taken and power management functions
253: * will be disabled.
254: */
255: PMReturn PMSetPowerManagement(
256: PMDeviceID device,
257: PMPowerManagementState state
258: )
259: {
260: if (APM_BIOS_connected) {
261: if (device.deviceType == PM_SYSTEM && device.deviceNumber == 1)
262: return APMBIOS_SetSystemPowerManagement(state);
263: else
264: return PM_R_BAD_ID;
265: }
266:
267: return PM_R_NOT_CONNECTED;
268: }
269:
270: /*
271: * Restores the default settings for all power management settings.
272: */
273: PMReturn PMRestoreDefaults(void)
274: {
275: if (APM_BIOS_connected)
276: return APMBIOS_RestoreDefaults();
277: else
278: return PM_R_NOT_CONNECTED;
279: }
280:
281: /*
282: * Update current kernel clock from real-time clock.
283: */
284: void PMUpdateClock(void)
285: {
286: /* THIS IS WRONG!!
287: extern struct timeval time;
288: readtodc(&time.tv_sec);
289: */
290: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.