00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <agnix/agnix.h>
00015 #include <agnix/init.h>
00016 #include <agnix/sleep.h>
00017 #include <agnix/bios/bios.h>
00018 #include <asm/bios_parametrs.h>
00019 #include <asm/desc.h>
00020 #include <asm/segment.h>
00021 #include <asm/paging.h>
00022 #include <asm/irq.h>
00023 #include <agnix/tasks.h>
00024 #include <agnix/threads.h>
00025 #include <agnix/unistd.h>
00026 #include <agnix/irq.h>
00027 #include <agnix/syscalls.h>
00028 #include <agnix/console.h>
00029
00030 #define MOD_NAME "APM: "
00031
00032 const char *apm_baterry_status[] = { "high", "low", "critical", "charging" };
00033
00034
00035 static struct indirect_s {
00036 u32 offset;
00037 u16 segment;
00038 } apm_indirect;
00039
00040 struct apm_info_s *apm_bios_info;
00041 struct apm_power_status_s apm_power_status;
00042 int apm_enabled;
00043
00044 u32 eax, ebx, ecx, edx, esi, edi;
00045
00046 u8 apm_function_call_simple(u32 func_nr, u32 ebx_i, u32 ecx_i)
00047 {
00048 u32 eax_o;
00049 u32 flags;
00050
00051 save_flags(flags); __cli();
00052
00053 __asm__ __volatile__ (
00054 "pushl %%ds\n\t"
00055 "pushl %%es\n\t"
00056 "pushl %%fs\n\t"
00057 "pushl %%gs\n\t"
00058
00059 "xorl %%edx, %%edx\n\t"
00060 "movw %%dx, %%ds\n\t"
00061 "movw %%dx, %%es\n\t"
00062 "movw %%dx, %%fs\n\t"
00063 "movw %%dx, %%gs"
00064 :
00065 :
00066 );
00067
00068 __asm__ __volatile__ (
00069 "pushl %%edi\n\t"
00070 "pushl %%ebp\n\t"
00071 "lcall %%cs:apm_indirect\n\t"
00072 "setc %%al\n\t"
00073 "popl %%ebp\n\t"
00074 "popl %%edi\n\t"
00075
00076 "popl %%gs\n\t"
00077 "popl %%fs\n\t"
00078 "popl %%es\n\t"
00079 "popl %%ds"
00080
00081 :"=a"(eax_o)
00082 :"D"(&apm_indirect), "a"(func_nr), "b"(ebx_i), "c"(ecx_i)
00083 );
00084
00085 restore_flags(flags);
00086
00087 return (u8)((eax_o) & 0xFF);
00088 }
00089
00090 u8 apm_function_call_full(u32 func_nr, u32 ebx_i, u32 ecx_i,
00091 u32 *eax_o, u32 *ebx_o, u32 *ecx_o, u32 *edx_o, u32 *esi_o, u32 *edi_o)
00092 {
00093 u32 flags;
00094
00095 save_flags(flags); __cli();
00096
00097 __asm__ __volatile__ (
00098 "pushl %%ds\n\t"
00099 "pushl %%es\n\t"
00100 "pushl %%fs\n\t"
00101 "pushl %%gs\n\t"
00102
00103 "xorl %%edx, %%edx\n\t"
00104 "movw %%dx, %%ds\n\t"
00105 "movw %%dx, %%es\n\t"
00106 "movw %%dx, %%fs\n\t"
00107 "movw %%dx, %%gs"
00108 :
00109 :
00110 );
00111
00112 __asm__ __volatile__ (
00113 "pushl %%edi\n\t"
00114 "pushl %%ebp\n\t"
00115 "lcall %%cs:apm_indirect\n\t"
00116 "setc %%al\n\t"
00117 "popl %%ebp\n\t"
00118 "popl %%edi\n\t"
00119
00120 "popl %%gs\n\t"
00121 "popl %%fs\n\t"
00122 "popl %%es\n\t"
00123 "popl %%ds"
00124
00125 :"=a"(*eax_o), "=b"(*ebx_o), "=c"(*ecx_o), "=d"(*edx_o), "=S"(*esi_o), "=D"(*edi_o)
00126 :"D"(&apm_indirect), "a"(func_nr), "b"(ebx_i), "c"(ecx_i)
00127 );
00128
00129 restore_flags(flags);
00130
00131 return (u8)((*eax_o) & 0xFF);
00132 }
00133
00134 int apm_cpu_idle(void)
00135 {
00136 if (apm_function_call_simple(APM_CPU_IDLE, APM_DEFAULT, APM_DEFAULT))
00137 return -1;
00138
00139 return 0;
00140 }
00141
00142 int apm_cpu_busy(void)
00143 {
00144 if (apm_function_call_simple(APM_CPU_BUSY, APM_DEFAULT, APM_DEFAULT))
00145 return -1;
00146
00147 return 0;
00148 }
00149
00150 int apm_set_power_state(u8 dest, u8 state)
00151 {
00152 if (apm_function_call_simple(APM_SET_POWER_STATE, dest, state))
00153 return -1;
00154
00155 return 0;
00156 }
00157
00158 void apm_show_power_status(struct apm_power_status_s *power_status)
00159 {
00160 if ((power_status->apm_battery_status != 0xFF) && (power_status->apm_battery_status <= 3))
00161 printk(MOD_NAME "battery status = %s\n", apm_baterry_status[power_status->apm_battery_status]);
00162
00163 if ((power_status->apm_battery_life_perc) <= 0x64)
00164 printk(MOD_NAME "battery remaining = %d%%\n", power_status->apm_battery_life_perc);
00165 }
00166
00167 int apm_get_power_status(void)
00168 {
00169 if (apm_function_call_full(APM_GET_POWER_STATUS, APM_ALL_DEVICES, APM_DEFAULT, &eax, &ebx, &ecx, &edx, &esi, &edi))
00170 return -1;
00171
00172 apm_power_status.apm_battery_status = (u8)(ebx & 0xFF);
00173 apm_power_status.apm_battery_flag = (u8)((ecx >> 8) & 0xFF);
00174 apm_power_status.apm_battery_life_perc = (u8)(ecx & 0xFF);
00175 apm_power_status.apm_battery_life_time = (u16)((edx >> 16) & 0xFFFF);
00176
00177 return 0;
00178 }
00179
00180 int apm_enable(void)
00181 {
00182 if (apm_function_call_simple(APM_ENABLE_DEV_APM, APM_ALL_DEVICES, APM_ENABLE)) {
00183 printk(MOD_NAME "Cannot enable APM\n");
00184 apm_enabled = 0;
00185 return -1;
00186 }
00187
00188 if (apm_function_call_simple(APM_ENGAGE_APM, APM_ALL_DEVICES, APM_ENABLE)) {
00189 printk(MOD_NAME "Cannot engage APM\n");
00190 apm_enabled = 0;
00191 return -1;
00192 }
00193
00194 return 0;
00195 }
00196
00197 void apm_signal_handler(int signal)
00198 {
00199 printk("APM_SIGNAL_HANDLER %d\n", signal);
00200 }
00201
00202 void apm_events_handle(void)
00203 {
00204 u32 apm_ret, apm_event, apm_info, apm_dummy;
00205
00206 while(!(apm_function_call_full(APM_GET_PM_EVENT, 0, 0, &apm_ret, &apm_event, &apm_info,
00207 &apm_dummy, &apm_dummy, &apm_dummy)))
00208 {
00209 switch(apm_event) {
00210
00211 case APM_EVENT_STANDBY:
00212 printk(MOD_NAME "APM_EVENT_STANDBY\n");
00213 break;
00214
00215 case APM_EVENT_SUSPEND:
00216 printk(MOD_NAME "APM_EVENT_SUSPEND\n");
00217 break;
00218
00219 case APM_EVENT_NORMAL_RESUME:
00220 printk(MOD_NAME "APM_EVENT_NORMAL_RESUME\n");
00221 break;
00222
00223 case APM_EVENT_CRITICAL_RESUME:
00224 printk(MOD_NAME "APM_EVENT_CRITICAL_RESUME\n");
00225 break;
00226
00227 case APM_EVENT_LOW_BATTERY:
00228 printk(MOD_NAME "APM_EVENT_LOW_BATTERY\n");
00229 break;
00230
00231 case APM_EVENT_POWER_STATUS_CHANGE:
00232 printk(MOD_NAME "APM_EVENT_POWER_STATUS_CHANGE\n");
00233 break;
00234
00235 case APM_EVENT_UPDATE_TIME:
00236 printk(MOD_NAME "APM_EVENT_UPDATE_TIME\n");
00237 break;
00238
00239 case APM_EVENT_CRITICAL_SUSPEND:
00240 printk(MOD_NAME "APM_EVENT_CRITICAL_SUSPEND\n");
00241 break;
00242
00243 case APM_EVENT_USER_STANDBY:
00244 printk(MOD_NAME "APM_EVENT_USER_STANDBY\n");
00245 break;
00246
00247 case APM_EVENT_USER_SUSPEND:
00248 printk(MOD_NAME "APM_EVENT_USER_SUSPEND\n");
00249 break;
00250
00251 case APM_EVENT_STANDBY_RESUME:
00252 printk(MOD_NAME "APM_EVENT_STANDBY_RESUME\n");
00253 break;
00254
00255 case APM_EVENT_CAPABILITY_CHANGE:
00256 printk(MOD_NAME "APM_EVENT_CAPABILITY_CHANGE\n");
00257 break;
00258 }
00259 }
00260 }
00261
00262 void apm_task_start(void *data)
00263 {
00264 __sti();
00265
00266 for(;;) {
00267 apm_events_handle();
00268 sleep_timeout(TIMER_HZ);
00269 }
00270 }
00271
00272 int __init apm_init(void)
00273 {
00274 apm_bios_info = APM_INFO;
00275 apm_enabled = 1;
00276
00277 if (apm_bios_info->apm_version == 0x00) {
00278 printk(MOD_NAME "not found\n");
00279 return -1;
00280 }
00281
00282 printk(MOD_NAME "Found APM ver. %d.%d\n",
00283 (apm_bios_info->apm_version >> 8) & 0xFF, apm_bios_info->apm_version & 0xFF);
00284
00285 if (apm_bios_info->apm_version != 0x100) {
00286 set_code_desc(__APM_CS >> 3, phys_to_virt((u32)(apm_bios_info->apm_cseg << 4)), (apm_bios_info->apm_cseg_len - 1) & 0xffff, 0, 1);
00287 set_code_desc(__APM_CS_16 >> 3, phys_to_virt((u32)(apm_bios_info->apm_cseg_16 << 4)), (apm_bios_info->apm_cseg_16_len - 1) & 0xffff, 0, 0);
00288 set_data_desc(__APM_DS >> 3, phys_to_virt((u32)(apm_bios_info->apm_dseg << 4)), (apm_bios_info->apm_dseg_len - 1) & 0xffff, 0, 1);
00289 } else {
00290 set_code_desc(__APM_CS >> 3, phys_to_virt((u32)(apm_bios_info->apm_cseg << 4)), 64 * 1024 - 1, 0, 1);
00291 set_code_desc(__APM_CS_16 >> 3, phys_to_virt((u32)(apm_bios_info->apm_cseg_16 << 4)), 64 * 1024 - 1, 0, 0);
00292 set_data_desc(__APM_DS >> 3, phys_to_virt((u32)(apm_bios_info->apm_dseg << 4)), 64 * 1024 - 1, 0, 1);
00293 }
00294 set_data_desc(__APM_40 >> 3, phys_to_virt((u32)(0x40 << 4)), 4095 - (0x40 << 4), 0, 1);
00295
00296
00297
00298
00299
00300
00301 apm_indirect.offset = apm_bios_info->apm_offset;
00302 apm_indirect.segment = __APM_CS;
00303
00304 apm_enable();
00305 apm_get_power_status();
00306 apm_show_power_status(&apm_power_status);
00307 create_kernel_thread("APM", apm_task_start, NULL);
00308
00309 return 0;
00310 }
00311