powerMgr/src/powerMgr.c File Reference

PowerMgr. More...

#include <config.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <linux/soundcard.h>
#include <glib.h>
#include <liberdm/erdm.h>
#include <liberipc/eripcpowermgr.h>
#include <liberipc/eripcbusyd.h>
#include <liberipc/eripccontentlister.h>
#include <liberipc/eripctoolbar.h>
#include "powerMgr.h"
#include "toolbar.h"

Go to the source code of this file.

Defines

#define DBG(x)
#define ERROR(x)   printf x
#define ENABLE_CPU_THROTTLE
#define CPU_SPEED_LOW   "100000"
#define CPU_SPEED_HIGH   "400000"
#define IDLE_PERCENTAGE_SPEED_UP   50
#define IDLE_PERCENTAGE_THROTTLE   95
#define SAMPLE_INTERVAL_LONG   1000
#define SAMPLE_INTERVAL_SHORT   100
#define MS_PER_IDLE_TICK   10
#define IDLE_THRESHOLD_SPEED_UP   (SAMPLE_INTERVAL_SHORT * IDLE_PERCENTAGE_SPEED_UP / 100 / MS_PER_IDLE_TICK)
#define IDLE_THRESHOLD_THROTTLE   (SAMPLE_INTERVAL_LONG * IDLE_PERCENTAGE_THROTTLE / 100 / MS_PER_IDLE_TICK)

Enumerations

enum  { e_cpu_low, e_cpu_high }

Functions

static int getDeviceState (board_status_t *ereader, int evt_fd, int pwr_fd)
static int setAC97Amp (int enabled)
static int setMMC (int enabled, int pwr_fd, board_status_t *ereader)
static void set_cpu_speed (const char *kHz)
void powerMgrMsgRxd (erServerChannel_t channel, int source_fd)
int powerMgrInstallIpcServer ()
static guint64 get_cpu_idle_count (void)
static void cpu_throttle (void)
static void check_battery_status (unsigned int charge_status, unsigned int time_left, short current)
static void * eventPoller (void *arg)
int main (int argc, char *argv[])

Variables

static erServerChannel_t theServerChannel
static erClientChannel_t contentListerChannel
static board_status_t g_ereader
static enum { ... }  g_cpu_speed


Detailed Description

PowerMgr.

Copyright (C) 2005-2008 iRex Technologies B.V. All rights reserved.

Definition in file powerMgr.c.


Define Documentation

#define CPU_SPEED_HIGH   "400000"

Definition at line 68 of file powerMgr.c.

#define CPU_SPEED_LOW   "100000"

Definition at line 67 of file powerMgr.c.

#define DBG (  ) 

eReader Powermanagement daemon

Definition at line 55 of file powerMgr.c.

#define ENABLE_CPU_THROTTLE

Definition at line 64 of file powerMgr.c.

#define ERROR (  )     printf x

Definition at line 57 of file powerMgr.c.

#define IDLE_PERCENTAGE_SPEED_UP   50

Definition at line 70 of file powerMgr.c.

#define IDLE_PERCENTAGE_THROTTLE   95

Definition at line 71 of file powerMgr.c.

#define IDLE_THRESHOLD_SPEED_UP   (SAMPLE_INTERVAL_SHORT * IDLE_PERCENTAGE_SPEED_UP / 100 / MS_PER_IDLE_TICK)

Definition at line 77 of file powerMgr.c.

#define IDLE_THRESHOLD_THROTTLE   (SAMPLE_INTERVAL_LONG * IDLE_PERCENTAGE_THROTTLE / 100 / MS_PER_IDLE_TICK)

Definition at line 78 of file powerMgr.c.

#define MS_PER_IDLE_TICK   10

Definition at line 76 of file powerMgr.c.

#define SAMPLE_INTERVAL_LONG   1000

Definition at line 73 of file powerMgr.c.

#define SAMPLE_INTERVAL_SHORT   100

Definition at line 74 of file powerMgr.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
e_cpu_low 
e_cpu_high 

Definition at line 80 of file powerMgr.c.


Function Documentation

static void check_battery_status ( unsigned int  charge_status,
unsigned int  time_left,
short  current 
) [static]

Definition at line 317 of file powerMgr.c.

00318 {
00319     static int iconState_previous = 0;  // for battery iconState = 0 is grey
00320            int iconState;
00321 
00322     DBG(("check_battery_status(): charge [%u] time left [%u] current [%hd]\n", charge_status, time_left, current));
00323 
00324     // update toolbar icon: 0 - 20 - 40 - 60 - 80 - 100%
00325     // round  0 .. 14 downward
00326     // round 15 .. 19 upward
00327     if (charge_status >= 0  &&  charge_status <= 100)
00328     {
00329         iconState = 1 + ((charge_status + 4) / 20);
00330     }
00331     else
00332     {
00333         // invalid battery charge: icon grey
00334         iconState = 0;
00335     }
00336 
00337     // show toolbar icon
00338     if (iconState != iconState_previous)
00339     {
00340         iconState_previous = iconState;
00341         toolbar_setIconState(iconID_battery, iconState);
00342         usleep(200*1000);  // wait for toolbar to update the icon
00343         dmDisplay(dmCmdPriorLow, dmQTyping);
00344     }
00345 
00346     // tell contentlister when battery almost empty
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             // this should not happen, seems like contentlister did not respond to our shutdown message
00354             // do a forced shutdown now to avoid the battery gets completely discharged
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             // contentlister must shutdown the device immediately
00361             clBatteryLow(contentListerChannel, ccClBattery_shutdown, charge_status, time_left);
00362         }
00363         else
00364         {
00365             // contentlister must warn the user about the battery status
00366             clBatteryLow(contentListerChannel, ccClBattery_warning, charge_status, time_left);
00367         }
00368     }
00369 }

Here is the call graph for this function:

static void cpu_throttle ( void   )  [static]

Definition at line 284 of file powerMgr.c.

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                 ; // ignore
00309         }
00310     }
00311 }

Here is the call graph for this function:

static void* eventPoller ( void *  arg  )  [static]

Definition at line 371 of file powerMgr.c.

00372 {
00373     static int   battery_poll_ticks = 20;  // delay first update till contentLister started
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     // init event and power mgmt interfaces
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     // Get initial device state
00403     oldstatus = getDeviceState(ereader, evt_fd, pwr_fd);
00404 
00405     // Initialise cpu speed
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             // low cpu frequency: short interval so we can speed up when cpu load changes
00414             usleep(SAMPLE_INTERVAL_SHORT * 1000L);
00415             cpu_throttle();
00416             if (--next_second_ticks > 0)
00417             {
00418                 continue;  //next while iteration
00419             }
00420         }
00421         else
00422         {
00423             // high cpu frequency: long interval so we do not disturb other processing
00424             usleep(SAMPLE_INTERVAL_LONG * 1000L);
00425             cpu_throttle();
00426         }
00427         next_second_ticks = (1000 / SAMPLE_INTERVAL_SHORT);
00428 
00429         /* Check the battery status */
00430         if (--battery_poll_ticks <= 0)
00431         {
00432             battery_poll_ticks = 60;  // seconds
00433 
00434             // battery measurement works reliably only at full cpu speed
00435             if (g_cpu_speed == e_cpu_low)
00436             {
00437                 set_cpu_speed(CPU_SPEED_HIGH);
00438             }
00439 
00440             // read battery status
00441             if (ioctl(pwr_fd, BATTERY_IOCTL_READ_CHARGE, &battery_charge_status) == -1)  // percentage 0 ... 100
00442             {
00443                 perror("ioctl read charge failed");
00444             }
00445             if (ioctl(pwr_fd, BATTERY_IOCTL_READ_TIME, &battery_time_left) == -1)   // in minutes, 65535 = charging
00446             {
00447                 perror("ioctl read time failed");
00448             }
00449             if (ioctl(pwr_fd, BATTERY_IOCTL_READ_CURRENT, &battery_current) == -1)  // in milliamps, positive or negative
00450             {
00451                 perror("ioctl read current failed");
00452             }
00453             current = battery_current & 0xFFFF; // convert from unsigned int to short
00454             
00455             // back to low cpu speed when needed
00456             if (g_cpu_speed == e_cpu_low)
00457             {
00458                 set_cpu_speed(CPU_SPEED_LOW);
00459             }
00460 
00461             // check battery status and set toolbar icon
00462             check_battery_status(battery_charge_status, battery_time_left, current);
00463         }
00464         
00465         /* Check the buttons */
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             //DBG(("decode status: [P = %x] [CF = %x] [MMC = %x]\n", GETPENDETECT(status), GETCFDETECT(status), GETMMCDETECT(status)));
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                     /* a card was inserted, mount it and tell contentLister */
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                     /* a card was removed, unmount it and tell contentLister */
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     } // while
00507 
00508     /* cleanup */
00509     close(evt_fd);
00510     close(pwr_fd);
00511 
00512     pthread_exit(NULL);
00513 }

Here is the call graph for this function:

static guint64 get_cpu_idle_count ( void   )  [static]

Definition at line 242 of file powerMgr.c.

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 }

static int getDeviceState ( board_status_t ereader,
int  evt_fd,
int  pwr_fd 
) [static]

Query device state at boot time

Definition at line 518 of file powerMgr.c.

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         /* MMC present at boot time, mount it! */
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 }

int main ( int  argc,
char *  argv[] 
)

Definition at line 549 of file powerMgr.c.

00550 {
00551     pthread_t pollThread;
00552     //pthread_t timerThread;
00553     pthread_attr_t my_attr;
00554 
00555     toolbar_init();
00556     
00557     erIpcStartClient(erIpcGetChannel(ER_CONTENT_LISTER_UA_ID), &contentListerChannel);
00558 
00559     /* start polling thread */
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     /* setup ipc */
00574     powerMgrInstallIpcServer();
00575 
00576     return 0;                   /* we never get here */
00577 }

Here is the call graph for this function:

int powerMgrInstallIpcServer (  ) 

Definition at line 211 of file powerMgr.c.

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 }

Here is the call graph for this function:

void powerMgrMsgRxd ( erServerChannel_t  channel,
int  source_fd 
)

This callback is invoked when there is data to read on file descriptor source_fd. The channel info is passed via parameter 'data'

Definition at line 165 of file powerMgr.c.

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 }

Here is the call graph for this function:

static void set_cpu_speed ( const char *  kHz  )  [static]

Definition at line 138 of file powerMgr.c.

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         // Never set CPU speed
00156         return;
00157 #endif
00158 }

static int setAC97Amp ( int  enabled  )  [static]

Definition at line 86 of file powerMgr.c.

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 //    if (ioctl(audio_device, SOUND_MIXER_PRIVATE1, &i))
00114 //    {
00115 //      perror("Ioctl on audio device");
00116 //      return -1;
00117 //    }
00118     close(mixer_device);
00119     return 0;
00120 }

static int setMMC ( int  enabled,
int  pwr_fd,
board_status_t ereader 
) [static]

Definition at line 122 of file powerMgr.c.

00123 {
00124     DBG(("Setting MMC controller to %s\n", (enabled == POWERED) ? "enabled" : "disabled"));
00125     if (enabled == POWERED)
00126     {
00127         //    if ( 0 == ioctl (pwr_fd, BATTERY_IOCTL_ENABLE_MMC, &status))
00128         ereader->mmc_ctrl = POWERED;
00129     }
00130     else
00131     {
00132         //    if ( 0 == ioctl (pwr_fd, BATTERY_IOCTL_DISABLE_MMC, &status))
00133         ereader->mmc_ctrl = UNPOWERED;
00134     }
00135     return 0;
00136 }


Variable Documentation

Definition at line 60 of file powerMgr.c.

enum { ... } g_cpu_speed [static]

Definition at line 61 of file powerMgr.c.

Definition at line 59 of file powerMgr.c.


Generated on Sun Dec 14 17:14:20 2008 by  doxygen 1.5.6