Main Page | Directories | File List | Globals

apm.c

Go to the documentation of this file.
00001 /*
00002  * kernel_arch/i386/kernel/bios/apm.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/01
00008  * Author:      Lukasz Dembinski
00009  * Info:        apm.c core file
00010  * Contact:     mailto: <dembol@nasa.com.pl>
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>     /* do_sys_sigaction */
00028 #include <agnix/console.h>
00029 
00030 #define MOD_NAME        "APM: "
00031 
00032 const char *apm_baterry_status[] = { "high", "low", "critical", "charging" };
00033 
00034 /* this is redefined in kernel_arch/i386/kernel/task.c */
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       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);
00297       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);
00298       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);
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 
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix