00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00034 #include <config.h>
00035 #include <pthread.h>
00036 #include <fcntl.h>
00037 #include <sys/ioctl.h>
00038 #include <sys/select.h>
00039 #include <linux/soundcard.h>
00040
00041 #include <glib.h>
00042
00043 #include <liberdm/erdm.h>
00044 #include <liberipc/eripcpowermgr.h>
00045 #include <liberipc/eripcbusyd.h>
00046 #include <liberipc/eripccontentlister.h>
00047 #include <liberipc/eripctoolbar.h>
00048 #include "powerMgr.h"
00049 #include "toolbar.h"
00050
00051 #undef DEBUG
00052 #ifdef DEBUG
00053 #define DBG(x) printf x
00054 #else
00055 #define DBG(x)
00056 #endif
00057 #define ERROR(x) printf x
00058
00059 static erServerChannel_t theServerChannel;
00060 static erClientChannel_t contentListerChannel;
00061 static board_status_t g_ereader;
00062
00063
00064 #define ENABLE_CPU_THROTTLE
00065
00066
00067 #define CPU_SPEED_LOW "100000" // cpu frequency in kHz
00068 #define CPU_SPEED_HIGH "400000" // cpu frequency in kHz
00069
00070 #define IDLE_PERCENTAGE_SPEED_UP 50 // speed up CPU when idle percentage falls below this threshold
00071 #define IDLE_PERCENTAGE_THROTTLE 95 // throttle down CPU when idle percentage comes above this threshold
00072
00073 #define SAMPLE_INTERVAL_LONG 1000 // in milliseconds
00074 #define SAMPLE_INTERVAL_SHORT 100 // in milliseconds
00075
00076 #define MS_PER_IDLE_TICK 10 // number of milliseconds represented by one tick of the idle counter
00077 #define IDLE_THRESHOLD_SPEED_UP (SAMPLE_INTERVAL_SHORT * IDLE_PERCENTAGE_SPEED_UP / 100 / MS_PER_IDLE_TICK)
00078 #define IDLE_THRESHOLD_THROTTLE (SAMPLE_INTERVAL_LONG * IDLE_PERCENTAGE_THROTTLE / 100 / MS_PER_IDLE_TICK)
00079
00080 static enum { e_cpu_low, e_cpu_high } g_cpu_speed = e_cpu_high;
00081
00082
00083 static int getDeviceState(board_status_t * ereader, int evt_fd, int pwr_fd);
00084
00085
00086 static int setAC97Amp(int enabled)
00087 {
00088 int mixer_device = 0;
00089
00090 DBG(("Setting AC97 to %s\n", (enabled) ? "enabled" : "disabled"));
00091 mixer_device = open("/dev/dsp", O_RDWR);
00092 if (mixer_device == -1)
00093 {
00094 perror("opening mixer device.\n");
00095 return -1;
00096 }
00097
00098 if(!enabled)
00099 {
00100 if (ioctl(mixer_device, SNDCTL_POWER_OFF))
00101 {
00102 perror("Ioctl on mixer device");
00103 }
00104 }
00105 else
00106 {
00107 if (ioctl(mixer_device, SNDCTL_POWER_ON))
00108 {
00109 perror("Ioctl on mixer device");
00110 }
00111 }
00112
00113
00114
00115
00116
00117
00118 close(mixer_device);
00119 return 0;
00120 }
00121
00122 static int setMMC(int enabled, int pwr_fd, board_status_t * ereader)
00123 {
00124 DBG(("Setting MMC controller to %s\n", (enabled == POWERED) ? "enabled" : "disabled"));
00125 if (enabled == POWERED)
00126 {
00127
00128 ereader->mmc_ctrl = POWERED;
00129 }
00130 else
00131 {
00132
00133 ereader->mmc_ctrl = UNPOWERED;
00134 }
00135 return 0;
00136 }
00137
00138 static void set_cpu_speed(const char *kHz)
00139 {
00140 #ifdef ENABLE_CPU_THROTTLE
00141 FILE *fp;
00142
00143 if (kHz == NULL)
00144 {
00145 return;
00146 }
00147
00148 fp = fopen("/proc/sys/cpu/0/speed", "w");
00149 if (fp)
00150 {
00151 fputs(kHz, fp);
00152 fclose(fp);
00153 }
00154 #else
00155
00156 return;
00157 #endif
00158 }
00159
00160
00165 void powerMgrMsgRxd(erServerChannel_t channel, int source_fd)
00166 {
00167 char szBuffer[SERVER_BUFFER_SIZE];
00168 int nBuf = SERVER_BUFFER_SIZE;
00169 erIpcCmd_t command;
00170 int enabled;
00171 int MHz;
00172
00173 erIpcGetMessage(channel, szBuffer, &nBuf);
00174
00175 if (pwrParseCommand(szBuffer, &command) >= 0)
00176 {
00177 switch (command.cc)
00178 {
00179 case ccPwrAC97:
00180 enabled = atoi(command.arg[0]);
00181 setAC97Amp(enabled);
00182 break;
00183
00184 case ccPwrIdleMode:
00185 MHz = atoi(command.arg[0]);
00186 if (MHz * 1000 == atoi(CPU_SPEED_LOW))
00187 {
00188 set_cpu_speed(CPU_SPEED_LOW);
00189 g_cpu_speed = e_cpu_low;
00190 }
00191 else if (MHz * 1000 == atoi(CPU_SPEED_HIGH))
00192 {
00193 set_cpu_speed(CPU_SPEED_HIGH);
00194 g_cpu_speed = e_cpu_high;
00195 }
00196 else
00197 {
00198 printf("Invalid cpu speed requested [%s]\n", command.arg[0]);
00199 set_cpu_speed(CPU_SPEED_HIGH);
00200 g_cpu_speed = e_cpu_high;
00201 }
00202 break;
00203
00204 default:
00205 printf("UNKNOWN COMMAND %d\n", command.cc);
00206 break;
00207 }
00208 }
00209 }
00210
00211 int powerMgrInstallIpcServer()
00212 {
00213 int returnValue;
00214 int fd = -1;
00215 fd_set readfds;
00216
00217 returnValue =
00218 erIpcOpenServerChannel(ER_POWERMGR_CHANNEL, &theServerChannel);
00219
00220 if (returnValue != (-1))
00221 {
00222 fd = erIpcGetServerFd(theServerChannel);
00223
00224 FD_ZERO(&readfds);
00225 FD_SET(fd, &readfds);
00226
00227 while (1)
00228 {
00229 select(fd + 1, &readfds, NULL, NULL, NULL);
00230 powerMgrMsgRxd(theServerChannel, fd);
00231 }
00232 }
00233 else
00234 {
00235 fprintf(stderr, "Could not open server channel\n");
00236 return -1;
00237 }
00238 return 0;
00239 }
00240
00241
00242 static guint64 get_cpu_idle_count(void)
00243 {
00244 static guint64 idle_previous = 0;
00245
00246 guint64 idle_current;
00247 guint64 idle_diff = 0;
00248 FILE *fp;
00249 char buf[200];
00250 char *cp;
00251
00252 fp = fopen("/proc/stat", "r");
00253 if (fp)
00254 {
00255 cp = fgets(buf, sizeof(buf), fp);
00256 if (cp == buf)
00257 {
00258 cp = strtok(buf, " ");
00259 if (strcmp(cp, "cpu") == 0)
00260 {
00261 cp = strtok(NULL, " ");
00262 cp = strtok(NULL, " ");
00263 cp = strtok(NULL, " ");
00264 cp = strtok(NULL, " ");
00265 idle_current = g_ascii_strtoull(cp, NULL, 10);
00266
00267 idle_diff = idle_current - idle_previous;
00268 if (idle_diff < 0)
00269 {
00270 printf("--> Illegal cpu idle count [%s] [%llu], previous [%llu]\n",
00271 cp, idle_current, idle_previous);
00272 idle_diff = 0;
00273 }
00274
00275 idle_previous = idle_current;
00276 }
00277 }
00278 fclose(fp);
00279 }
00280
00281 return idle_diff;
00282 }
00283
00284 static void cpu_throttle(void)
00285 {
00286 guint64 idle_diff;
00287
00288 idle_diff = get_cpu_idle_count();
00289 if (idle_diff >= 0)
00290 {
00291 switch (g_cpu_speed)
00292 {
00293 case e_cpu_low:
00294 if (idle_diff <= IDLE_THRESHOLD_SPEED_UP)
00295 {
00296 set_cpu_speed(CPU_SPEED_HIGH);
00297 g_cpu_speed = e_cpu_high;
00298 }
00299 break;
00300 case e_cpu_high:
00301 if (idle_diff >= IDLE_THRESHOLD_THROTTLE)
00302 {
00303 set_cpu_speed(CPU_SPEED_LOW);
00304 g_cpu_speed = e_cpu_low;
00305 }
00306 break;
00307 default:
00308 ;
00309 }
00310 }
00311 }
00312
00313
00314
00315
00316
00317 static void check_battery_status(unsigned int charge_status, unsigned int time_left, short current)
00318 {
00319 static int iconState_previous = 0;
00320 int iconState;
00321
00322 DBG(("check_battery_status(): charge [%u] time left [%u] current [%hd]\n", charge_status, time_left, current));
00323
00324
00325
00326
00327 if (charge_status >= 0 && charge_status <= 100)
00328 {
00329 iconState = 1 + ((charge_status + 4) / 20);
00330 }
00331 else
00332 {
00333
00334 iconState = 0;
00335 }
00336
00337
00338 if (iconState != iconState_previous)
00339 {
00340 iconState_previous = iconState;
00341 toolbar_setIconState(iconID_battery, iconState);
00342 usleep(200*1000);
00343 dmDisplay(dmCmdPriorLow, dmQTyping);
00344 }
00345
00346
00347 if ((charge_status <= BATTERY_LOW_WARNING) && (current < BATTERY_CHARGING))
00348 {
00349 ERROR(("Battery charge is %u, threshold is %u (time left is %u, current is %hd)\n", charge_status, BATTERY_LOW_WARNING, time_left, current));
00350
00351 if (charge_status <= BATTERY_LOW_EMERGENCY)
00352 {
00353
00354
00355 ERROR(("\n\n --- EMERGENCY SHUTDOWN: battery charge is %d%% ---\n\n", charge_status));
00356 system("halt");
00357 }
00358 else if (charge_status <= BATTERY_LOW_SHUTDOWN)
00359 {
00360
00361 clBatteryLow(contentListerChannel, ccClBattery_shutdown, charge_status, time_left);
00362 }
00363 else
00364 {
00365
00366 clBatteryLow(contentListerChannel, ccClBattery_warning, charge_status, time_left);
00367 }
00368 }
00369 }
00370
00371 static void* eventPoller(void *arg)
00372 {
00373 static int battery_poll_ticks = 20;
00374 static int next_second_ticks = 0;
00375 unsigned int battery_charge_status;
00376 unsigned int battery_time_left;
00377 unsigned int battery_current;
00378 short current;
00379
00380 board_status_t* ereader = (board_status_t *) arg;
00381 int evt_fd;
00382 int pwr_fd;
00383 int status;
00384 int oldstatus;
00385 int ret;
00386
00387
00388 evt_fd = open(DEVEVTIFACE, O_RDWR | O_NONBLOCK);
00389 if (evt_fd < 0)
00390 {
00391 perror("Error opening /dev/buttons");
00392 pthread_exit(NULL);
00393 }
00394
00395 pwr_fd = open(POWERMGMTIFACE, O_RDWR);
00396 if (pwr_fd < 0)
00397 {
00398 perror("Error opening /dev/battery");
00399 pthread_exit(NULL);
00400 }
00401
00402
00403 oldstatus = getDeviceState(ereader, evt_fd, pwr_fd);
00404
00405
00406 set_cpu_speed(CPU_SPEED_HIGH);
00407 g_cpu_speed = e_cpu_high;
00408
00409 while (1)
00410 {
00411 if (g_cpu_speed == e_cpu_low)
00412 {
00413
00414 usleep(SAMPLE_INTERVAL_SHORT * 1000L);
00415 cpu_throttle();
00416 if (--next_second_ticks > 0)
00417 {
00418 continue;
00419 }
00420 }
00421 else
00422 {
00423
00424 usleep(SAMPLE_INTERVAL_LONG * 1000L);
00425 cpu_throttle();
00426 }
00427 next_second_ticks = (1000 / SAMPLE_INTERVAL_SHORT);
00428
00429
00430 if (--battery_poll_ticks <= 0)
00431 {
00432 battery_poll_ticks = 60;
00433
00434
00435 if (g_cpu_speed == e_cpu_low)
00436 {
00437 set_cpu_speed(CPU_SPEED_HIGH);
00438 }
00439
00440
00441 if (ioctl(pwr_fd, BATTERY_IOCTL_READ_CHARGE, &battery_charge_status) == -1)
00442 {
00443 perror("ioctl read charge failed");
00444 }
00445 if (ioctl(pwr_fd, BATTERY_IOCTL_READ_TIME, &battery_time_left) == -1)
00446 {
00447 perror("ioctl read time failed");
00448 }
00449 if (ioctl(pwr_fd, BATTERY_IOCTL_READ_CURRENT, &battery_current) == -1)
00450 {
00451 perror("ioctl read current failed");
00452 }
00453 current = battery_current & 0xFFFF;
00454
00455
00456 if (g_cpu_speed == e_cpu_low)
00457 {
00458 set_cpu_speed(CPU_SPEED_LOW);
00459 }
00460
00461
00462 check_battery_status(battery_charge_status, battery_time_left, current);
00463 }
00464
00465
00466 ret = ioctl(evt_fd, BUTTON_IOCTL_GET_STATUS, &status);
00467 if (ret < 0)
00468 {
00469 perror("ioctl invalid status");
00470 }
00471 else
00472 {
00473
00474
00475 if (GETMMCDETECT(status) ^ GETMMCDETECT(oldstatus))
00476 {
00477 if (GETMMCDETECT(status))
00478 {
00479 ERROR(("MMC card inserted\n"));
00480 ereader->mmc_card = INSERTED;
00481
00482
00483 if (ereader->mmc_ctrl == UNPOWERED)
00484 {
00485 setMMC(POWERED, pwr_fd, ereader);
00486 }
00487 system("/usr/bin/mountmmc.sh");
00488 clStoragePresent(contentListerChannel, SD_ID, 1);
00489 }
00490 else
00491 {
00492 ERROR(("MMC card gone\n"));
00493 ereader->mmc_card = GONE;
00494
00495
00496 system("/usr/bin/umountmmc.sh");
00497 clStoragePresent(contentListerChannel, SD_ID, 0);
00498 if (ereader->mmc_ctrl == POWERED)
00499 {
00500 setMMC(UNPOWERED, pwr_fd, ereader);
00501 }
00502 }
00503 }
00504 }
00505 oldstatus = status;
00506 }
00507
00508
00509 close(evt_fd);
00510 close(pwr_fd);
00511
00512 pthread_exit(NULL);
00513 }
00514
00518 static int getDeviceState(board_status_t * ereader, int evt_fd, int pwr_fd)
00519 {
00520 int ret, status;
00521
00522 ret = ioctl(evt_fd, BUTTON_IOCTL_GET_STATUS, &status);
00523 if (ret < 0)
00524 perror("ioctl on event interface");
00525
00526 DBG(("Got initial state 0x%x\n", status));
00527
00528 ereader->ac97_amp = POWERED;
00529 DBG(("- AC97 powered on\n"));
00530
00531 if (GETMMCDETECT(status))
00532 {
00533 ereader->mmc_card = INSERTED;
00534 ereader->mmc_ctrl = POWERED;
00535 DBG(("- MMC card present, MMC controller powered\n"));
00536
00537 system("/usr/bin/mountmmc.sh");
00538 }
00539 else
00540 {
00541 ereader->mmc_card = GONE;
00542 ereader->mmc_ctrl = POWERED;
00543 DBG(("- MMC card gone, MMC controller powered\n"));
00544 }
00545 return status;
00546 }
00547
00548
00549 int main(int argc, char *argv[])
00550 {
00551 pthread_t pollThread;
00552
00553 pthread_attr_t my_attr;
00554
00555 toolbar_init();
00556
00557 erIpcStartClient(erIpcGetChannel(ER_CONTENT_LISTER_UA_ID), &contentListerChannel);
00558
00559
00560 if (0 != pthread_attr_init(&my_attr))
00561 {
00562 perror("pthread_attr_init");
00563 }
00564 if (0 != pthread_attr_setdetachstate(&my_attr, PTHREAD_CREATE_DETACHED))
00565 {
00566 perror("thread set detach state");
00567 }
00568 if (0 != pthread_create(&pollThread, &my_attr, eventPoller, (void *) &g_ereader))
00569 {
00570 perror("pthread_create");
00571 }
00572
00573
00574 powerMgrInstallIpcServer();
00575
00576 return 0;
00577 }
00578