system.c

Go to the documentation of this file.
00001 /*
00002  * File Name: system.c
00003  */
00004 
00005 /*
00006  * This file is part of sysd.
00007  *
00008  * sysd is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * sysd is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 //----------------------------------------------------------------------------
00028 // Include Files
00029 //----------------------------------------------------------------------------
00030 
00031 #include "config.h" 
00032 
00033 // system include files, between < >
00034 #include <glib.h>
00035 #include <hal/libhal.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h> 
00039 #include <unistd.h>
00040 #include <dirent.h>
00041 #include <fcntl.h>
00042 #include <sys/statvfs.h>
00043 
00044 // ereader include files, between < >
00045 #include <liberipc/eripc.h>
00046 #include <liberutils/display_utils.h>
00047 
00048 // local include files, between " "
00049 #include "log.h"
00050 #include "connections.h"
00051 #include "busy.h"
00052 #include "conf.h"
00053 #include "display.h"
00054 #include "hal.h"
00055 #include "ipc.h"
00056 #include "wacom.h"
00057 #include "xwindow.h"
00058 #include "tasks.h"
00059 
00060 
00061 //----------------------------------------------------------------------------
00062 // Type Declarations
00063 //----------------------------------------------------------------------------
00064 
00065 enum state_usb
00066 {
00067     STATE_USB_UNKNOWN = 0,
00068     STATE_USB_DISCONNECT_PENDING,
00069     STATE_USB_DISCONNECTED,
00070     STATE_USB_UNMOUNTED,
00071     STATE_USB_MOUNT_CONFIRM,
00072     STATE_USB_MOUNT_PENDING,
00073     STATE_USB_MOUNTED
00074 };
00075 
00076 
00077 //----------------------------------------------------------------------------
00078 // Global Constants
00079 //----------------------------------------------------------------------------
00080 
00081 #define AUTOINSTALL_FILE            "autoinstall"
00082 #define UPDATE_PATH                 MOUNTPOINT_CARD "/System/Update/"
00083 #define UPDATE_FILE                 UPDATE_PATH "update.dat"
00084 #define UPDATE_AUTO_FILE            UPDATE_PATH AUTOINSTALL_FILE
00085 #define DRZ_PATH                    MOUNTPOINT_CARD "/System/drz/"
00086 #define DRZ_AUTO_FILE               DRZ_PATH AUTOINSTALL_FILE
00087 
00088 #define DEMO_FILE                   "slideshow.pdf"
00089 #define DEMO_FLIP_INTERVAL          8
00090 
00091 #define DRZINSTALL_TOOL             "/usr/bin/drzinstall"
00092 #define MDB_INDEXER                 "/usr/bin/mdbindex"
00093 #define ADOBE_SYNC                  "/usr/bin/adobe-sync.sh"
00094 
00095 #define USB_DEVICE_POLL_INTERVAL    1
00096 #define USB_DEVICE_POLL_TIMEOUT     8 * USB_DEVICE_POLL_INTERVAL
00097 #define USB_DEVICE_ONLINE_DELAY     5
00098 
00099 #define BATTERY_LOW_THRESHOLD       5
00100 #define BATTERY_SHUTDOWN_THRESHOLD  2
00101 #define BATTERY_FULL_THRESHOLD      100
00102  
00103 #define IDLE_TIMEOUT_SEC            5
00104 #define PREPARE_STANDBY_TIMEOUT_MS  2500
00105 #define CHECK_STANDBY_TIMEOUT_MS    500
00106 #define HOLDOFF_STANDBY_TIMEOUT     10
00107 
00108 // Hardware Change bits
00109 #define ST_HW_COVER    (1 << 4)
00110 #define ST_HW_CARD     (1 << 6)
00111 #define ST_HW_USB      (1 << 7)
00112 
00113 // Wakeup reasons - taken from ionkdb-private.h
00114 #define WAKEUP_NO_REASON       0  // unknown
00115 #define WAKEUP_KEY             1  // sensor pressed
00116 #define WAKEUP_PEN             2  // wacom pen detected
00117 #define WAKEUP_TIMER           3  // standby timer
00118 #define WAKEUP_BATTERY         4  // battery level update
00119 #define WAKEUP_COVER           5  // cover state change
00120 #define WAKEUP_CARD            6  // mmc card state change
00121 #define WAKEUP_USB             7  // usb state change
00122 #define WAKEUP_CHARGE_DETECTED 8  // charge state change
00123 
00124 const char *sys_devices         = "/sys/devices";
00125 const char *micro_device_name   = "serio";
00126 const char *lun_device_name     = "gadget-lun";
00127 const char *sysset_device_name  = "sysset0";
00128 const char *power_device_name   = "ionpower";
00129 const char *usb_device_name     = "fsl-usb2-udc";
00130 
00131 static const gint SD_FREE_MB_WARN_LEVEL   = 10;
00132 
00133 #define read_ionkbd(file, ...)      read_sysfs(g_serio,   file, __VA_ARGS__)
00134 #define read_sysset(file, ...)      read_sysfs(g_sysset,  file, __VA_ARGS__)
00135 #define read_power(file, ...)       read_sysfs(g_power,   file, __VA_ARGS__)
00136 #define read_usb(file, ...)         read_sysfs(g_usb,     file, __VA_ARGS__)
00137 #define read_lun(file, ...)         read_sysfs(g_lun,     file, __VA_ARGS__)
00138 #define write_ionkbd(file, ...)     write_sysfs(g_serio,  file, __VA_ARGS__)
00139 #define write_power(file, ...)      write_sysfs(g_power,  file, __VA_ARGS__)
00140 
00141 
00142 //----------------------------------------------------------------------------
00143 // Static Variables
00144 //----------------------------------------------------------------------------
00145 
00146 static enum state_device     device_state    = STATE_DEVICE_STARTING;
00147 static enum state_charge     charge_state    = STATE_CHARGE_UNKNOWN;
00148 static enum state_usb        usb_state       = STATE_USB_UNKNOWN;
00149 static enum state_card       card_state      = STATE_CARD_UNKNOWN;
00150 static enum state_power      power_state     = STATE_POWER_RUN;
00151 
00152 static gint                  g_battery_level = 0;
00153 static gchar                 *g_serio        = NULL;
00154 static gchar                 *g_sysset       = NULL;
00155 static gchar                 *g_power        = NULL;
00156 static gchar                 *g_usb          = NULL;
00157 static gchar                 *g_card_device  = NULL;
00158 static gchar                 *g_lun          = NULL;
00159 
00160 static enum rotate_direction    g_rotate_direction   = ROTATE_UNKOWN;
00161 static enum display_orientation g_orientation        = ORIENTATION_PORTRAIT;
00162 
00163 static gfloat                g_version_micro         = 0.0;
00164 static gint                  g_sensor_disable_config = 0x07; 
00165 static gboolean              g_sensor_locked         = FALSE;
00166 static gboolean              g_sound_enabled         = FALSE;
00167 static gboolean              g_popup_enabled         = TRUE;
00168 static gboolean              g_idle_enabled          = TRUE;
00169 static gboolean              g_standby_if_plugged    = TRUE;
00170 static guint                 g_usb_device_source     = 0;
00171 static guint                 g_volume_unmount_source = 0;
00172 static guint                 g_idle_time_source      = 0;
00173 static guint                 g_standby_timeout_sec   = 30*60;
00174 static guint                 g_holdoff_standby       = 0;
00175 static gboolean              g_index_splash_enabled  = TRUE;
00176 static gboolean              g_index_with_metadata   = TRUE;
00177 static gboolean              g_pageturn_inverted     = FALSE;
00178 static gboolean              g_wallcharger_found     = FALSE;
00179 static gboolean              g_demo_mode             = FALSE;
00180 static gboolean              g_demo_invert_flipbar   = FALSE;
00181 
00182 
00183 //============================================================================
00184 // Local Function Definition
00185 //============================================================================
00186 
00187 static gint          read_sysfs                 (const char *device, const char *filename, const char *format, ...);
00188 static gboolean      write_sysfs                (const char *device, const char *filename,  const char *buffer);
00189 static gchar         *find_dir                  (const char *dir, const char *file, gboolean recurse);
00190 
00191 static gboolean      usb_driver_load            (void);
00192 static gboolean      usb_driver_unload          (void);
00193 static void          usb_connection_finish      (void);
00194 static void          usb_set_state              (enum state_usb new_state);
00195 static void          on_usb_connected           (gpointer data);
00196 static gboolean      on_usb_disconnected        (gpointer data);
00197 static gboolean      on_usb_read_device_state   (gpointer data);
00198 static gboolean      on_usb_read_online         (gpointer data);
00199 
00200 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00201 static void          prepare_standby            (void);
00202 static gboolean      on_standby                 (gpointer data);
00203 #endif
00204 static void          do_poweroff                (void);
00205 static void          do_idle                    (void);
00206 static void          set_idle_time              (gint time);
00207 static gboolean      on_idle_timeout            (gpointer data);
00208 static gint          get_wakeup_reason          (void);
00209 
00210 static enum state_charge get_battery_state      (gint level, gint charging);
00211 static void          update_battery_info        (gint cur_level, enum state_charge cur_state, gboolean force_send);
00212 static gboolean      write_ionkbd_orientation   (gint orientation);
00213 static gboolean      write_ionkbd_battery_alerts(gint l1, gint l2, gint l3, gint l4, gint l5);
00214 
00215 static void          on_eject_continue          (gpointer data);
00216 static void          on_poweroff_continue       (gpointer data);
00217 static void          on_restart_continue        (gpointer data);
00218 static void          on_install_drz_ready       (GPid pid, gint status, gpointer data);
00219 static void          report_unmounting_volumes  (void);
00220 static void          check_hardware             (void);
00221 static gboolean      check_and_install_drz      (void);
00222 static void          do_unmount                 (gboolean show_busy, const char *splash, 
00223                                                  gpointer callback_function, gpointer user_data);
00224 
00225 
00226 //============================================================================
00227 // Functions Implementation
00228 //============================================================================
00229 
00230 void sys_set_services(void)
00231 {
00232     LOGPRINTF("entry");
00233     
00234     // find sysset partition
00235     //
00236     g_sysset = find_dir(sys_devices, sysset_device_name, TRUE);
00237     if (!g_sysset) 
00238     {
00239         ERRORPRINTF("%s not found or not unique", sysset_device_name);
00240     }
00241     else
00242     {
00243         LOGPRINTF("Sysset found at %s", g_sysset);
00244     }
00245 
00246     // find power
00247     //
00248     g_power = find_dir(sys_devices, power_device_name, TRUE);
00249     if (!g_power) 
00250     {
00251         ERRORPRINTF("%s not found or not unique", power_device_name);
00252     }
00253     else
00254     {
00255         LOGPRINTF("Ionpower found at %s", g_power);
00256     }
00257     
00258     // find micro driver
00259     //
00260     g_serio = find_dir(sys_devices, micro_device_name, FALSE);
00261     if (!g_serio) 
00262     {
00263         ERRORPRINTF("%s not found or not unique", micro_device_name);
00264     }
00265     else 
00266     {
00267         LOGPRINTF("Device micro found as %s", g_serio);
00268         
00269         read_ionkbd("micro_ver", "%f", &g_version_micro);
00270         LOGPRINTF("Micro version %.2f", g_version_micro);
00271         
00272         // set battery alert levels
00273         write_ionkbd_battery_alerts(BATTERY_LOW_THRESHOLD, 13, 38, 63, 88);
00274 
00275         // check battery state at startup
00276         sys_get_battery(&g_battery_level, &charge_state, NULL);
00277         
00278         // update led for battery state
00279         sys_update_rgb_led();
00280     }
00281 
00282     // set idle
00283 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00284     if (g_version_micro < 0.34f)
00285     {
00286         g_idle_enabled = FALSE;
00287     }
00288 #endif    
00289     if (sys_is_emulator())
00290     {
00291         g_idle_enabled = FALSE;
00292     }
00293     
00294     if (g_idle_enabled) 
00295     {
00296         g_idle_time_source = g_timeout_add_seconds(IDLE_TIMEOUT_SEC, on_idle_timeout, NULL);
00297     }
00298 }
00299 
00300 
00301 void sys_starting_finished()
00302 {
00303     if ((card_state != STATE_CARD_MOUNTED) &&
00304         (card_state != STATE_CARD_INACCESSIBLE) &&
00305         (card_state != STATE_CARD_INDEXING))
00306     {
00307         ipc_show_splash("nosd");
00308     }
00309     
00310     conf_set_first_boot(FALSE);
00311     
00312     // now that everything is up and running, check for USB connection
00313     check_hardware();
00314 }
00315 
00316 
00317 void sys_set_idle_mode(gboolean idle_enabled)
00318 {
00319 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW    
00320     if (g_version_micro < 0.34f)
00321     {
00322         g_idle_enabled = FALSE;
00323     }
00324     else
00325 #endif    
00326     if (sys_is_emulator())
00327     {
00328         g_idle_enabled = FALSE;
00329     }
00330     else
00331     {
00332         g_idle_enabled = idle_enabled;
00333     }
00334     
00335     if (g_idle_enabled)
00336     {
00337         // start idle timer
00338         sys_reset_idle_time();
00339     }
00340     else
00341     {
00342         if (g_idle_time_source)
00343         {
00344             g_source_remove(g_idle_time_source);
00345             g_idle_time_source = 0;
00346         }
00347     }
00348 }
00349 
00350 
00351 void sys_set_standby_time(guint time_sec)
00352 {
00353     g_standby_timeout_sec = time_sec;
00354 }
00355 
00356 
00357 void sys_set_standby_mode(gboolean standby_if_plugged)
00358 {
00359     g_standby_if_plugged = standby_if_plugged;
00360 }
00361 
00362 
00363 void sys_reset_idle_time()
00364 {
00365     set_idle_time(0);
00366 }
00367 
00368 
00369 gboolean sys_set_beeper_config(gboolean use_sound)
00370 {
00371     LOGPRINTF("entry");
00372     
00373     g_sound_enabled = use_sound;
00374     return TRUE;
00375 }
00376 
00377 
00378 gboolean sys_set_beeper(gint duration_ms, const char *tone)
00379 {
00380     LOGPRINTF("entry");
00381     
00382     gboolean retval = FALSE;
00383     char *buffer    = NULL;
00384     gint beep_pitch = -1;
00385     
00386     if (!g_sound_enabled)
00387     {
00388         return FALSE;
00389     }
00390     
00391     if (g_ascii_strcasecmp(tone, "high") == 0)
00392     {
00393         beep_pitch = 1;
00394     }
00395     else if (g_ascii_strcasecmp(tone, "low") == 0)
00396     {
00397         beep_pitch = 0;
00398     }
00399     else
00400     {
00401         WARNPRINTF("Unknown tone: %s", tone);
00402     }
00403 
00404     if (beep_pitch != -1)
00405     {
00406         // Bits 0..6 are length of time to play tone (in units of 10ms)
00407         // Bit 7 sets high/low tone
00408         buffer = g_strdup_printf("%d", ((duration_ms / 10) & 0xEF) | ((beep_pitch & 0x01) << 7));
00409         retval = write_ionkbd("beeper", buffer);
00410         g_free(buffer);
00411     }
00412    
00413     return retval;
00414 }
00415 
00416 
00417 gboolean sys_set_rgb_led(enum led_color color, gint flash_ms)
00418 {
00419     LOGPRINTF("entry");
00420     
00421     gboolean retval  = FALSE;
00422     gchar    *buffer = NULL;
00423     
00424     // LED Color values:
00425     // 0: off  4: red
00426     // 1: blue 5: magenta
00427     // 2: green   6: yellow
00428     // 3: cyan 7: white
00429     
00430     // Value 1: LED Color [0..7]
00431     // Value 2: LED Flash rate (in units of 500ms)
00432 
00433     buffer = g_strdup_printf("%d %d", (color & 0xFF), (flash_ms / 500) & 0xFF);
00434     retval = write_ionkbd("rgbled", buffer);
00435     g_free(buffer);
00436     
00437     return retval;
00438 }
00439 
00440 
00441 gboolean sys_set_index_with_metadata(gboolean with_metadata)
00442 {
00443     LOGPRINTF("entry");
00444 
00445     g_index_with_metadata = with_metadata;
00446     
00447     return TRUE;
00448 }
00449 
00450 gboolean sys_set_pageturn_inverted(gboolean is_inverted)
00451 {
00452     LOGPRINTF("entry");
00453 
00454     g_pageturn_inverted = is_inverted;
00455     
00456     ipc_send_changed_pageturn_inverted(g_pageturn_inverted);
00457 
00458     return TRUE;
00459 }
00460 
00461 
00462 gboolean sys_set_rotate_direction(const char *direction)
00463 {
00464     LOGPRINTF("entry");
00465     
00466     g_return_val_if_fail(direction!=NULL, FALSE);
00467     
00468     if (strcmp(direction, "clockwise") == 0)
00469     {
00470         g_rotate_direction = ROTATE_CLOCKWISE;    
00471     }
00472     else
00473     {
00474         g_rotate_direction = ROTATE_ANTICLOCKWISE;    
00475     }        
00476     
00477     return TRUE;
00478 }
00479 
00480 
00481 static gboolean on_rotated(gpointer data)
00482 {
00483     LOGPRINTF("entry");
00484 
00485     display_update_return_control(DM_HINT_FULL);
00486     
00487     // inform ionkbd
00488     write_ionkbd_orientation(g_orientation);
00489     
00490     // inform applications
00491     ipc_send_changed_orientation(g_orientation);
00492     
00493     return FALSE; // stop timer
00494 }
00495 
00496 
00497 gboolean sys_set_orientation(const char *orientation)
00498 {
00499     LOGPRINTF("entry");
00500     
00501     g_return_val_if_fail(orientation!=NULL, FALSE);
00502 
00503     static gboolean is_portrait = TRUE;
00504     gboolean retval = FALSE;
00505     gboolean is_changed = FALSE;
00506   
00507     if (g_ascii_strcasecmp(orientation, "portrait") == 0)
00508     {
00509         if (!is_portrait)
00510         {
00511             is_portrait = TRUE;
00512             is_changed = TRUE;
00513         }
00514     }
00515     else if (g_ascii_strcasecmp(orientation, "landscape") == 0)
00516     {
00517         if (is_portrait)
00518         {
00519             is_portrait = FALSE;
00520             is_changed = TRUE;
00521         }
00522     }
00523     else if (g_ascii_strcasecmp(orientation, "toggle") == 0)
00524     {
00525         is_portrait = !is_portrait;
00526         is_changed = TRUE;
00527     }
00528     else 
00529     {
00530         WARNPRINTF("Unknown orientation: %s", orientation);
00531     }
00532     
00533     if (is_changed)
00534     {
00535         display_gain_control();
00536 
00537         if (is_portrait)
00538         {
00539             // rotate screen (xrandr)
00540             sys_spawn_sync("xrandr -display 0:0 --screen 0 --orientation normal");
00541             g_orientation = ORIENTATION_PORTRAIT;
00542         }
00543         else  
00544         {
00545             /*
00546              *  GConf Setting:
00547              *  +----------+--------------+--------------+
00548              *  | Portrait | LH Landscape | RH Landscape |
00549              *  +----------+--------------+--------------+
00550              *  | normal   | clockwise    | anticlockwise|
00551              *  +----------+--------------+--------------+
00552              *  
00553              *  Sensor Layouts:
00554              *  +----------+--------------+--------------+
00555              *  | Portrait | LH Landscape | RH Landscape |
00556              *  +----------+--------------+--------------+
00557              *  | 1     5  |      5A1     |     5B1      |
00558              *  | A     B  |    1         |         5    |
00559              *  | 5     1  |    C         |         C    |
00560              *  |   1C5    |    5         |         1    |
00561              *  |          |      1B5     |     1A5      |
00562              *  +----------+--------------+--------------+
00563              * 
00564              *  Xrandr Orientation:
00565              *  +----------+--------------+--------------+
00566              *  | Portrait | LH Landscape | RH Landscape |
00567              *  +----------+--------------+--------------+
00568              *  | normal   | left         | right        |
00569              *  +----------+--------------+--------------+
00570              */ 
00571 
00572             if (g_rotate_direction == ROTATE_CLOCKWISE)
00573             {
00574                 // rotate screen (xrandr)
00575                 sys_spawn_sync("xrandr -display 0:0 --screen 0 --orientation left");
00576                 g_orientation = ORIENTATION_LANDSCAPE_CLOCKWISE;
00577             }
00578             else
00579             {
00580                 // rotate screen (xrandr)
00581                 sys_spawn_sync("xrandr -display 0:0 --screen 0 --orientation right");
00582                 g_orientation = ORIENTATION_LANDSCAPE_ANTICLOCKWISE;
00583             }
00584         }
00585         
00586         // wait time to allow rotation
00587         g_timeout_add(800, (GSourceFunc)on_rotated, NULL);
00588     }
00589 
00590     return retval;
00591 }
00592 
00593 
00594 gboolean sys_set_sensor_feedback(gboolean use_light, gboolean use_sound)
00595 {
00596     LOGPRINTF("entry");
00597     
00598     gboolean retval = FALSE;
00599     char *buffer    = NULL;
00600     
00601     // Value 1: bit 0 - buzzer enable, bit 1 - LED enable
00602 
00603     buffer = g_strdup_printf("%d", use_sound | (use_light << 1));
00604     retval = write_ionkbd("sensor_feedback", buffer);
00605     
00606     g_free(buffer);
00607     return retval;
00608 }
00609 
00610 
00611 gboolean sys_set_sensor_lock_config(gboolean lock_left, gboolean lock_right, gboolean lock_middle)
00612 {
00613     LOGPRINTF("entry");
00614     
00615     // NOTE: the micro has a sensor_enable setting so we invert the 
00616     //       lock to enable logic here
00617     // NOTE: left appears to be Sensor B, right is Sensor A
00618     g_sensor_disable_config = !lock_right | (!lock_left << 1) | (!lock_middle << 2);
00619 
00620     // if lock is currently active, make new config effective
00621     sys_set_sensor_lock("update");
00622     
00623     return TRUE;
00624 }
00625 
00626 
00627 gboolean sys_set_sensor_lock(const char *lock_mode)
00628 {
00629     LOGPRINTF("entry");
00630     
00631     g_return_val_if_fail(lock_mode!=NULL, FALSE);
00632     
00633     gboolean retval = FALSE;
00634     gboolean is_changed = FALSE;
00635     
00636     if (g_ascii_strcasecmp(lock_mode, "lock") == 0)
00637     {
00638         if (!g_sensor_locked)
00639         {
00640             g_sensor_locked  = TRUE;
00641             is_changed = TRUE;
00642         }
00643     }
00644     else if (g_ascii_strcasecmp(lock_mode, "unlock") == 0)
00645     {
00646         if (g_sensor_locked)
00647         {
00648             g_sensor_locked  = FALSE;
00649             is_changed = TRUE;
00650         }
00651     }
00652     else if (g_ascii_strcasecmp(lock_mode, "toggle") == 0)
00653     {
00654         g_sensor_locked  = !g_sensor_locked;
00655         is_changed = TRUE;
00656     }
00657     else if (g_ascii_strcasecmp(lock_mode, "update") == 0)
00658     {
00659         if (g_sensor_locked)
00660         {
00661             is_changed = TRUE;
00662         }
00663         
00664         if (g_sensor_disable_config == 7)
00665         {
00666             g_sensor_locked = FALSE;
00667         }
00668     }
00669     else
00670     {
00671         WARNPRINTF("Unknown lock mode: %s", lock_mode);
00672     }
00673   
00674     if (is_changed)
00675     {
00676         if (g_sensor_locked)
00677         {
00678             // inform ionkbd
00679             char *lock_config = g_strdup_printf("%d", g_sensor_disable_config);
00680             write_ionkbd("sensor_enable", lock_config);
00681             g_free(lock_config);
00682             
00683             // update menu and statusbar item
00684             ipc_menu_set_item_state("lock", "general", "selected");
00685             ipc_menu_set_statusitem_state("statusbar_lock", "locked");
00686         }
00687         else
00688         {
00689             // inform ionkbd
00690             write_ionkbd("sensor_enable", "7"); // enable all three sensors
00691 
00692             // update menu and statusbar item
00693             ipc_menu_set_item_state("lock", "general", "normal");
00694             ipc_menu_set_statusitem_state("statusbar_lock", "normal");
00695         }
00696     }
00697 
00698     return retval;
00699 }
00700 
00701 
00702 void sys_eject_card(gboolean silent)
00703 {
00704     LOGPRINTF("entry");
00705     do_unmount(!silent, NULL, on_eject_continue, (gpointer) silent);
00706 }
00707 
00708 
00709 void sys_standby(void)
00710 {
00711     LOGPRINTF("entry");
00712 
00713     // shutdown completely when standby switch is toggled during first boot of the device
00714     if ((device_state == STATE_DEVICE_STARTING) && conf_get_first_boot())
00715     {
00716         busy_add_background(0);                    
00717         sys_spawn_sync("shutdown -h now");
00718         return;
00719     }
00720 
00721     if ( usb_state == STATE_USB_MOUNT_PENDING ||
00722          usb_state == STATE_USB_MOUNTED || 
00723          card_state == STATE_CARD_INDEXING )
00724     {
00725         LOGPRINTF("System is connected to PC or indexing, don't enter standby");
00726         return;
00727     }
00728     
00729     if (g_holdoff_standby)
00730     {
00731         LOGPRINTF("Just back from standby, ignore key press");
00732         return;
00733     }
00734     
00735 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00736     prepare_standby();
00737 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00738     do_poweroff();
00739 #else
00740 #error Unhandled machine type
00741 #endif
00742 }
00743 
00744 
00745 void sys_restart(void)
00746 {
00747     LOGPRINTF("entry");
00748     
00749     device_state = STATE_DEVICE_STOPPING;
00750     busy_add_foreground(0, BUSY_DIALOG_NONE, NULL);
00751     do_unmount(TRUE, "restart", on_restart_continue, NULL);
00752 }
00753 
00754 
00755 static gboolean sys_check_and_install_firmware(void)
00756 {
00757     LOGPRINTF("entry");
00758 
00759     if (card_state == STATE_CARD_MOUNTED)
00760     {
00761         if (g_file_test(UPDATE_FILE, G_FILE_TEST_IS_REGULAR))
00762         {
00763             LOGPRINTF("Update file found");
00764 
00765             if (g_file_test(UPDATE_AUTO_FILE, G_FILE_TEST_IS_REGULAR))
00766             {
00767                 // don't prompt, install automatically
00768                 LOGPRINTF("Autoinstall file found, restart device");
00769                 sys_restart();
00770             }
00771             else
00772             {
00773                 // prompt to restart & install
00774                 ipc_confirm_install_update(TRUE);
00775             }
00776             return TRUE;
00777         }
00778     }
00779     return FALSE;
00780 }
00781 
00782 
00783 gboolean sys_usb_connect()
00784 {
00785     gboolean retval = FALSE;
00786 
00787     LOGPRINTF("entry");
00788 
00789     if ((card_state == STATE_CARD_MOUNTED) &&
00790         (usb_state == STATE_USB_MOUNT_CONFIRM))
00791     {
00792         usb_set_state(STATE_USB_MOUNT_PENDING);
00793         do_unmount(TRUE, "usbconnect", on_usb_connected, NULL);
00794         retval = TRUE;
00795     }
00796     else
00797     {
00798         LOGPRINTF("no volume mounted or not confirmed");
00799     }
00800 
00801     return retval;
00802 }
00803 
00804 
00805 gboolean sys_spawn_async(const char *command)
00806 {
00807     LOGPRINTF("entry");
00808     return sys_spawn_async_with_callback(command, NULL, NULL);
00809 }
00810 
00811 
00812 gboolean sys_spawn_async_with_callback(const char *command, GChildWatchFunc callback, gpointer data)
00813 {
00814     LOGPRINTF("entry");
00815 
00816     g_return_val_if_fail(command!=NULL, FALSE);
00817 
00818     char *argv[4];
00819     gboolean retval = FALSE;
00820     GError *error = NULL;
00821     GPid child_pid;
00822 
00823     argv[0] = "/bin/sh";
00824     argv[1] = "-c";
00825     argv[2] = (char*) command;
00826     argv[3] = NULL;
00827 
00828     LOGPRINTF("Spawning: %s", argv[2]);
00829     
00830     if (callback)
00831     {
00832         retval = g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &error);
00833     }
00834     else
00835     {
00836         retval = g_spawn_async(NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
00837     }        
00838     
00839     if (error)
00840     {
00841         WARNPRINTF("Execution of '%s' failed with error: %s", command, error->message);
00842         g_error_free(error);
00843         return FALSE;
00844     }
00845 
00846     if (retval && callback)
00847     {
00848         LOGPRINTF("Add callback handler for pid [%d]", (gint) child_pid);
00849         g_child_watch_add(child_pid, (GChildWatchFunc) callback, data);
00850     }
00851     
00852     return retval;
00853 }
00854 
00855 
00856 gboolean sys_spawn_sync(const char *command)
00857 {
00858     LOGPRINTF("entry");
00859     
00860     g_return_val_if_fail(command!=NULL, FALSE);
00861 
00862     char *argv[4];
00863     gboolean retval = FALSE;
00864     GError *error = NULL;
00865     
00866     argv[0] = "/bin/sh";
00867     argv[1] = "-c";
00868     argv[2] = (char*) command;
00869     argv[3] = NULL;
00870 
00871     LOGPRINTF("Spawning: %s", argv[2]);
00872 
00873     retval = g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, NULL, &error);
00874     
00875     if (error)
00876     {
00877         WARNPRINTF("Execution of '%s' failed with error: %s", command, error->message);
00878         g_error_free(error);
00879         return FALSE;
00880     }
00881 
00882     return retval;
00883 }
00884 
00885 
00886 gint sys_battery_level()
00887 {
00888     int level;
00889     enum state_charge state;
00890 
00891     sys_get_battery(&level, &state, NULL);
00892 
00893     return level;
00894 }
00895 
00896 
00897 gboolean sys_get_battery(int *level, enum state_charge *state, int *timeleft)
00898 {
00899     LOGPRINTF("entry");
00900 
00901     gboolean result = FALSE;
00902     gint cur_level = 0;
00903     gint charging  = 0;
00904     gint rc        = 0;
00905     
00906     if (sys_is_emulator())
00907     {
00908         *level = 100;
00909         *state = STATE_CHARGE_DISCHARGING;
00910         return TRUE;
00911     }
00912 
00913     rc = read_ionkbd("battery", "%d %d", &cur_level, &charging);
00914     
00915     if ((rc > 0) && (cur_level != 0xFF))
00916     {
00917         *level    = cur_level;
00918         *state    = get_battery_state(cur_level, charging);
00919         
00920         LOGPRINTF("battery level %d, charging %d", cur_level, charging);
00921         result = TRUE;
00922     }
00923     else
00924     {
00925         WARNPRINTF("Failed to read battery information");
00926     }
00927 
00928     return result;
00929 }
00930 
00931 
00932 void sys_update_battery(const char *battery)
00933 {
00934     gint                  charging  = 0;
00935     gint                  cur_level = 0;
00936     enum state_charge     cur_state = STATE_CHARGE_UNKNOWN;
00937     
00938     LOGPRINTF("entry");
00939     
00940     sscanf(battery, "%d %d", &cur_level, &charging);
00941     cur_state = get_battery_state(cur_level, charging);
00942     update_battery_info(cur_level, cur_state, FALSE);
00943 }
00944 
00945 
00946 gfloat sys_get_display_vcom()
00947 {
00948     LOGPRINTF("entry");
00949     gfloat vcom;
00950 
00951     read_sysset("display/vcom", "%f", &vcom);
00952 
00953     return vcom;
00954 }
00955 
00956 
00957 static void set_keypress_generation(int delay)
00958 {
00959     int fd = open("/sys/devices/serio0/demo_mode", O_WRONLY);
00960     if (fd == -1) {
00961         perror("open");
00962         return;
00963     } else {
00964         char buffer[10];
00965         sprintf(buffer, "%d", delay);
00966         write(fd, buffer, strlen(buffer));
00967         close(fd);
00968     }
00969 
00970 }
00971 
00972 
00973 static gboolean start_demo(gpointer data)
00974 {
00975     set_keypress_generation(DEMO_FLIP_INTERVAL);
00976     return FALSE;
00977 }
00978 
00979 
00980 static void start_demo_mode()
00981 {
00982     WARNPRINTF("found "DEMO_FILE", starting demo mode");
00983     if (g_demo_mode)
00984     {
00985         ERRORPRINTF("already in demo mode");
00986         return;
00987     }
00988     g_demo_invert_flipbar = g_pageturn_inverted;
00989     if (g_pageturn_inverted) {
00990         sys_set_pageturn_inverted(FALSE);
00991     }
00992     // disable wacom and lock all sensors
00993     wacom_disable();
00994     write_ionkbd("sensor_enable", "0");
00995 
00996     // open demo document
00997     ipc_send_demo_mode(TRUE);
00998     task_start("/usr/bin/uds "MOUNTPOINT_CARD"/"DEMO_FILE, MOUNTPOINT_CARD, "Slideshow", NULL, NULL, NULL);
00999 
01000     // start auto-keypress 5 seconds later (+ delay of pressing keys)
01001     g_timeout_add(5000, start_demo, NULL);
01002     g_demo_mode = TRUE;
01003 }
01004 
01005 
01006 static void stop_demo_mode()
01007 {
01008     if (!g_demo_mode) return;
01009 
01010     WARNPRINTF("stopping demo mode");
01011     set_keypress_generation(0);
01012     if (g_demo_invert_flipbar) {
01013         sys_set_pageturn_inverted(TRUE);
01014     }
01015     ipc_send_demo_mode(FALSE);
01016     wacom_enable();
01017     if (g_sensor_locked) {
01018         char buf[20];
01019         sprintf(buf, "%d", g_sensor_disable_config);
01020         write_ionkbd("sensor_enable", buf);
01021     } else {
01022         write_ionkbd("sensor_enable", "7");
01023 
01024     }
01025 
01026     g_demo_mode = FALSE;
01027 }
01028 
01029 
01030 static void update_usb_state(gboolean connected)
01031 {
01032     static gboolean last_connected = FALSE;
01033 
01034 
01035     if (usb_state != STATE_CHARGE_UNKNOWN
01036         && connected == last_connected) return;
01037 
01038     last_connected = connected;
01039 
01040     if (connected)
01041     {
01042         // usb cable connected
01043         usb_set_state(STATE_USB_UNMOUNTED);
01044 
01045         if (card_state == STATE_CARD_MOUNTED)
01046         {
01047             LOGPRINTF("SD/MMC available, load USB drivers check for host");
01048             if (usb_driver_load())
01049             {
01050                 busy_add_background(0);
01051                 g_usb_device_source = g_timeout_add_seconds(USB_DEVICE_POLL_INTERVAL, on_usb_read_device_state, NULL);
01052             }
01053         }
01054         else
01055         {
01056             LOGPRINTF("Card not mounted; don't connect to USB, card_state [%d]", card_state);
01057         }
01058     }
01059     else
01060     {
01061         // usb cable disconnected
01062         if (usb_state == STATE_USB_MOUNT_PENDING)
01063         {
01064             usb_set_state(STATE_USB_DISCONNECT_PENDING);
01065         }
01066         else
01067         {
01068             usb_set_state(STATE_USB_DISCONNECTED);
01069         }
01070     }
01071 }
01072 
01073 
01074 void sys_update_hardware(const char *hardware)
01075 {
01076     LOGPRINTF("entry");
01077     
01078     static gint         old_state           = 0;
01079     gint                cur_state           = 0;
01080  
01081     sscanf(hardware, "%d", &cur_state);
01082     
01083     LOGPRINTF("old state [%d] cur state [%d]", old_state, cur_state);
01084 
01085     if ( ((old_state & ST_HW_CARD) != (cur_state & ST_HW_CARD))
01086          || 
01087          (card_state == STATE_CARD_UNKNOWN) )
01088     {
01089         // NOTE reversed logic: 0 card is inserted, 1 card ejected
01090         //
01091         if (!(cur_state & ST_HW_CARD))
01092         {
01093             // event not handled here as storage device and volume will be added through HAL 
01094             LOGPRINTF("SD/MMC card inserted");
01095         }
01096         else
01097         {
01098             // event not handled here as storage device and volume will be removed through HAL
01099             LOGPRINTF("SD/MMC card ejected");
01100             stop_demo_mode();
01101         }
01102     }
01103 
01104     update_usb_state(cur_state & ST_HW_USB);
01105     
01106     // keep device awake for a while as HAL events can follow
01107     sys_reset_idle_time();
01108 
01109     // store state
01110     old_state = cur_state;
01111 }
01112 
01113 
01114 gboolean sys_has_network(void)
01115 {
01116     gboolean ignore          = FALSE;
01117     gboolean found_wifi      = FALSE;
01118     gboolean found_bluetooth = FALSE;
01119     gboolean found_3g        = FALSE;
01120     
01121     sys_get_device_capabilities(&ignore, &found_wifi, &found_bluetooth, &found_3g);
01122     
01123     return (found_wifi || found_bluetooth || found_3g);
01124 }
01125 
01126 
01127 gboolean sys_has_stylus(void)
01128 {
01129     gboolean found_stylus    = FALSE;
01130     gboolean ignore          = FALSE;
01131     
01132     sys_get_device_capabilities(&found_stylus, &ignore, &ignore, &ignore);
01133     
01134     return (found_stylus);
01135 }
01136 
01137 
01138 gboolean sys_is_dr800(void)
01139 {
01140     int type = 0;
01141     int rc = read_ionkbd("device_type", "%d", &type);
01142     if ((rc > 0) && ((type == 3) || (type == 4) || (type == 5)))
01143     {
01144         return TRUE;
01145     }
01146     
01147     return FALSE;
01148 }
01149 
01150 
01151 gboolean sys_is_emulator(void)
01152 {
01153     char hostname[100] = {0};
01154     int rc = gethostname(hostname, sizeof(hostname));
01155     if ((rc == 0) && (strcmp(hostname, "qemuarm") == 0))
01156     {
01157         return TRUE;
01158     }
01159     return FALSE;
01160 }
01161 
01162 
01163 void sys_get_device_capabilities(gboolean *has_stylus, gboolean *has_wifi, gboolean *has_bluetooth, gboolean *has_3g)
01164 {
01165     LOGPRINTF("entry");
01166 
01167     gboolean found_stylus    = FALSE;
01168     gboolean found_wifi      = FALSE;
01169     gboolean found_bluetooth = FALSE;
01170     gboolean found_3g        = FALSE;
01171     char data[64];
01172     
01173     bzero(data, sizeof(data));
01174     read_sysset("wacom/serial", "%s", &data);
01175     if ((data[0] != '\0') && (data[0] != '\xFF')) 
01176     {
01177         LOGPRINTF("data %s", data);
01178         if ((strlen(data) > 0) && (strtoul(data,NULL,16) != 0))
01179         {
01180             found_stylus = TRUE;
01181         }
01182     }
01183 
01184     bzero(data, sizeof(data));
01185     read_sysset("wifi/address", "%s", &data);
01186     if ((data[0] != '\0') && (data[0] != '\xFF')) 
01187     {
01188         if (strlen(data) > 0)
01189         {
01190             found_wifi = TRUE;
01191         }
01192     }
01193 
01194     bzero(data, sizeof(data));
01195     read_sysset("bluetooth/address", "%s", &data);
01196     if ((data[0] != '\0') && (data[0] != '\xFF')) 
01197     {
01198         if (strlen(data) > 0)
01199         {
01200             found_bluetooth = TRUE;
01201         }
01202     }
01203 
01204     bzero(data, sizeof(data));
01205     read_sysset("3g/imei", "%s", &data);
01206     if ((data[0] != '\0') && (data[0] != '\xFF')) 
01207     {
01208         if (strlen(data) > 0)
01209         {
01210             found_3g = TRUE;
01211         }
01212     }
01213     
01214     bzero(data, sizeof(data));
01215     read_sysset("3g/meid", "%s", &data);
01216     if ((data[0] != '\0') && (data[0] != '\xFF')) 
01217     {
01218         if (strlen(data) > 0)
01219         {
01220             found_3g = TRUE;
01221         }
01222     }
01223     
01224     if (sys_is_emulator())
01225     {
01226         found_stylus = TRUE;
01227         found_3g     = TRUE;
01228     }
01229 
01230     LOGPRINTF("capabilities from sysset: wacom %d, wifi %d, bluetooth %d, 3g %d", found_stylus, found_wifi, found_bluetooth, found_3g);
01231         
01232     *has_stylus    = found_stylus;
01233     *has_wifi      = found_wifi;
01234     *has_bluetooth = found_bluetooth;
01235     *has_3g        = found_3g;
01236 }
01237 
01238 
01239 static gboolean check_disk_free(void)
01240 {
01241     LOGPRINTF("entry");
01242 
01243     if (card_state == STATE_CARD_MOUNTED)
01244     {
01245         // check available free space
01246         gint64      mbfree   = -1;
01247         
01248         LOGPRINTF("mbfree [%lld]", mbfree);
01249     
01250         struct statvfs s;
01251         if (statvfs(MOUNTPOINT_CARD, &s) == 0) 
01252         {
01253             mbfree   = s.f_frsize * s.f_bavail >> 20;
01254         }
01255         
01256         if (mbfree == -1)
01257         {
01258             ERRORPRINTF("failed to get free space from mount point [%s]", MOUNTPOINT_CARD);
01259         }
01260         else if (mbfree <= SD_FREE_MB_WARN_LEVEL)
01261         {
01262             WARNPRINTF("sdcard disk space low, free %lld Mb", mbfree);
01263             ipc_show_message("sdfullwarn", NULL, NULL);
01264             return TRUE;
01265         }
01266     }
01267     return FALSE;
01268 }
01269 
01270 
01271 static void on_card_indexed(GPid pid, gint status, gpointer data)
01272 {
01273     LOGPRINTF("entry pid [%d] status [%d]", (gint) pid, status);
01274 
01275     g_spawn_close_pid(pid);
01276     
01277     busy_remove_foreground(0);
01278 
01279     sys_set_card(STATE_CARD_MOUNTED);
01280     
01281     if (g_index_splash_enabled)
01282     {
01283         ipc_show_splash("hide");
01284         gboolean do_drz = check_and_install_drz();
01285         gboolean do_firmware = sys_check_and_install_firmware();
01286         gboolean do_disk = check_disk_free();
01287 
01288         if (!(do_drz || do_firmware || do_disk)) {
01289             if (g_file_test(MOUNTPOINT_CARD"/"DEMO_FILE, G_FILE_TEST_EXISTS)) {
01290                 start_demo_mode();
01291             }
01292         }
01293     }
01294     else
01295     {
01296         // enable splash again for next mount
01297         g_index_splash_enabled = TRUE;
01298     }
01299 }
01300 
01301 
01302 void sys_set_card(enum state_card new_state)
01303 {
01304 #if (LOGGING_ON)
01305     const gchar *state_str[] = { "UKNOWN", "INACCESSIBLE", "EJECTED", "UNMOUNTING", "UNMOUNTED", "INDEXING", "MOUNTED" };
01306     LOGPRINTF("prepare card_state %s > %s", state_str[card_state], state_str[new_state]);
01307 #endif        
01308     
01309     switch (new_state)
01310     {
01311     case STATE_CARD_EJECTED:
01312         ipc_show_splash("nosd");
01313 
01314         // delete private settings from registry
01315         sys_spawn_async(ERCONFTOOL_DELETE);
01316     
01317         if (   (usb_state != STATE_USB_DISCONNECTED)
01318             && (usb_state != STATE_USB_UNMOUNTED) )
01319         {
01320             // set new state before unmounting USB
01321             LOGPRINTF("change card_state %s > %s", state_str[card_state], state_str[new_state]);
01322             card_state = new_state;
01323             usb_set_state(STATE_USB_UNMOUNTED);
01324         }
01325         break;
01326         
01327     case STATE_CARD_INDEXING:
01328     {
01329         busy_add_foreground(0, BUSY_DIALOG_NONE, NULL);
01330         if (g_index_splash_enabled)
01331         {
01332             ipc_show_splash("indexing");
01333         }
01334         sys_spawn_sync(ERCONFTOOL_IMPORT);
01335         
01336         // synchronize with Adobe Digital Editions
01337         sys_spawn_sync(ADOBE_SYNC);
01338         
01339         gchar *command = g_strdup_printf("%s %s %s", 
01340                                          MDB_INDEXER,
01341                                          MOUNTPOINT_CARD,
01342                                          g_index_with_metadata ? "" : "--quick");
01343         sys_spawn_async_with_callback(command, on_card_indexed, (gpointer) FALSE);
01344         g_free(command);
01345         // busy is reset by "on_card_indexed" callback
01346     }
01347     break;
01348 
01349     case STATE_CARD_MOUNTED:
01350         ipc_send_volume_mounted(MOUNTPOINT_CARD);
01351         g_card_device = hal_get_mountpoint_device();
01352         break;
01353     
01354     case STATE_CARD_INACCESSIBLE:
01355     case STATE_CARD_UNMOUNTED:
01356     default:
01357         break;
01358     }
01359 
01360     LOGPRINTF("change card_state %s > %s", state_str[card_state], state_str[new_state]);
01361     
01362     card_state = new_state;
01363 }
01364 
01365 
01366 enum state_card sys_get_card()
01367 {
01368     return card_state;    
01369 }
01370 
01371 
01372 void sys_usb_no_connect()
01373 {
01374     LOGPRINTF("entry");
01375     if (usb_state == STATE_USB_MOUNT_CONFIRM)
01376     {
01377         usb_set_state(STATE_USB_UNMOUNTED);
01378     }
01379 }
01380 
01381 
01382 gboolean sys_request_popup(const char *state)
01383 {
01384     g_return_val_if_fail(state!=NULL, FALSE);
01385     
01386     if (strcmp(state, "localblock") == 0)
01387     {
01388         g_popup_enabled = FALSE;
01389     }
01390     else if (strcmp(state, "block") == 0)
01391     {
01392         g_popup_enabled = FALSE;
01393         ipc_show_popup(state);
01394     }
01395     else if (strcmp(state, "localunblock") == 0)
01396     {
01397         g_popup_enabled = TRUE;
01398     }
01399     else if (strcmp(state, "unblock") == 0)
01400     {
01401         g_popup_enabled = TRUE;
01402         ipc_show_popup(state);
01403     }
01404     else if (g_popup_enabled)
01405     {
01406         ipc_show_popup(state);
01407     }
01408     return TRUE;
01409 }
01410 
01411 
01412 gboolean sys_set_power(const char *device, gint mode)
01413 {
01414     LOGPRINTF("entry");
01415     
01416     gboolean retval = FALSE;
01417     
01418     gchar *modestr = g_strdup_printf("%d", mode);
01419     retval = write_power(device, modestr);
01420     g_free(modestr);
01421     
01422     return retval;
01423 }
01424 
01425 
01426 gboolean sys_get_power(const char *device, gint *mode)
01427 {
01428     LOGPRINTF("entry");
01429     
01430     gboolean retval = FALSE;
01431     retval = read_power(device, "%d", &mode);
01432     
01433     return retval;
01434 }
01435 
01436 
01437 guint sys_get_orientation(void)
01438 {
01439     return g_orientation;
01440 }
01441 
01442 
01443 gboolean sys_get_pageturn_inverted(void)
01444 {
01445     return g_pageturn_inverted; 
01446 }
01447 
01448 
01449 static void on_install_drz_ready(GPid pid, gint status, gpointer data)
01450 {
01451     WARNPRINTF("pid [%d] exit status [%d]", (gint) pid, status);
01452     g_spawn_close_pid(pid);
01453 }
01454 
01455 
01456 void sys_install_drz(void)
01457 {
01458     // NOTE installation of AdobeID account requires network connections (IPC) so
01459     //      this must be called asynchronous
01460     gchar *command = g_strdup_printf(DRZINSTALL_TOOL" -s %s", DRZ_PATH);
01461     sys_spawn_async_with_callback(command, on_install_drz_ready, NULL);
01462     g_free(command);
01463     return;
01464 }
01465 
01466 
01467 static gboolean check_and_install_drz(void)
01468 {
01469     LOGPRINTF("entry");
01470 
01471     if (card_state == STATE_CARD_MOUNTED)
01472     {
01473         if (g_file_test(DRZ_PATH, G_FILE_TEST_IS_DIR))
01474         {
01475             LOGPRINTF("DRZ path found");
01476 
01477             if (g_file_test(DRZ_AUTO_FILE, G_FILE_TEST_IS_REGULAR))
01478             {
01479                 // don't prompt, install automatically
01480                 LOGPRINTF("Autoinstall file found, install DRZ");
01481                 sys_install_drz();
01482             }
01483             else
01484             {
01485                 // prompt to install
01486                 ipc_confirm_install_drz(TRUE);
01487             }
01488             
01489             return TRUE;
01490         }
01491     }
01492     
01493     return FALSE;
01494 }
01495 
01496 
01497 enum state_device sys_get_device_state(void)
01498 {
01499 #if (LOGGING_ON)
01500         const gchar *state_str[] = { "UKNOWN", "STARTING", "STARTED", "STOPPING" };
01501         LOGPRINTF("device_state [%s]", state_str[device_state]);
01502 #endif        
01503     return device_state;
01504 }
01505 
01506 
01507 enum state_power sys_get_power_state(void)
01508 {
01509 #if (LOGGING_ON)
01510 //        const gchar *state_str[] = { "UKNOWN",  "OFF", "RUN", "IDLE", "STANDBY" };
01511 //        LOGPRINTF("power_state [%s]", state_str[power_state]);
01512 #endif        
01513     return power_state;
01514 }
01515 
01516 
01517 void sys_set_device_state(enum state_device new_state)
01518 {
01519     LOGPRINTF("entry, new state: %d", new_state);
01520 
01521     device_state = new_state;
01522 }
01523 
01524 
01525 void sys_update_rgb_led()
01526 {
01527     LOGPRINTF("entry");
01528     
01529     if (is_busy_foreground())
01530     {
01531         // Device Busy
01532         sys_set_rgb_led(COLOR_GREEN, 500);
01533         return;
01534     }
01535     
01536     if (conn_is_online())
01537     {
01538         // Connection Online
01539         sys_set_rgb_led(COLOR_BLUE, 0);
01540         return;
01541     }
01542     
01543     if (charge_state == STATE_CHARGE_CHARGING)
01544     {
01545         // Battery Charging
01546         sys_set_rgb_led(COLOR_YELLOW, 0);
01547         return;
01548     }
01549     else if (charge_state == STATE_CHARGE_FULL)
01550     {
01551         // Battery Fully Charged & USB attached
01552         if ((usb_state != STATE_USB_DISCONNECTED) && (usb_state != STATE_USB_UNKNOWN))
01553         {
01554             sys_set_rgb_led(COLOR_GREEN, 0);
01555             return;
01556         }
01557     }
01558     else if (charge_state == STATE_CHARGE_LOW)
01559     {
01560         // Battery Critically Low
01561         sys_set_rgb_led(COLOR_RED, 0);
01562         return;
01563     }
01564     
01565     // Device On -- default state
01566     sys_set_rgb_led(COLOR_OFF, 0);
01567 }
01568 
01569 
01570 gboolean sys_get_enable_index_splash(void)
01571 {
01572     return g_index_splash_enabled;
01573 }
01574 
01575 
01576 void sys_set_enable_index_splash(gboolean value)
01577 {
01578     g_index_splash_enabled = value; 
01579 }
01580 
01581 
01582 //============================================================================
01583 // Local Function Implementation
01584 //============================================================================
01585 
01586 static gint read_sysfs(const char *device, const char *filename, const char *format, ...)
01587 {
01588     va_list ap;
01589     gint    retval = 0;
01590     gchar   *file = NULL;
01591     gint    fd = 0;
01592     char    buffer[256 + 1] = {0};
01593 
01594     if (!device)
01595     {
01596         return retval;
01597     }
01598     va_start(ap, format);
01599 
01600     file = g_strconcat(device, "/", filename, NULL);
01601     
01602     fd = open(file, O_RDONLY);
01603     if (fd >= 0) 
01604     {
01605         retval = read(fd, buffer, sizeof(buffer));
01606         close(fd);
01607         
01608         if (retval > -1)
01609         {
01610 //            LOGPRINTF("buffer: `%s`", buffer);
01611             retval = vsscanf(buffer, format, ap);
01612         }
01613         else 
01614         {
01615             WARNPRINTF("Could not read %s", file);
01616         }
01617     } 
01618     else 
01619     {
01620         WARNPRINTF("Could not open %s", file);
01621     }
01622     
01623     g_free(file);
01624 
01625     va_end(ap);
01626     
01627     return retval;
01628 }
01629 
01630 
01631 static gboolean write_ionkbd_orientation(gint orientation)
01632 {
01633     LOGPRINTF("entry");
01634     
01635     gboolean retval = FALSE;
01636     
01637     switch (orientation)
01638     {
01639     case ORIENTATION_PORTRAIT:
01640         write_ionkbd("orientation", "portrait");
01641         retval = TRUE;
01642         break;
01643         
01644     case ORIENTATION_LANDSCAPE_CLOCKWISE:
01645         write_ionkbd("orientation", "lh-landscape");
01646         retval = TRUE;
01647         break;
01648             
01649     case ORIENTATION_LANDSCAPE_ANTICLOCKWISE:
01650         write_ionkbd("orientation", "rh-landscape");
01651         retval = TRUE;
01652         break;
01653     
01654     default:
01655         WARNPRINTF("Unknown orientation: %d", g_orientation);
01656         break;
01657     }
01658     
01659     return retval;
01660 }
01661 
01662 
01663 static gboolean write_ionkbd_battery_alerts(gint l1, gint l2, gint l3, gint l4, gint l5)
01664 {
01665     LOGPRINTF("entry");
01666     
01667     gchar *message = g_strdup_printf("%d %d %d %d %d", l1, l2, l3, l4, l5);
01668     
01669     write_ionkbd("battery_alerts", message);
01670     
01671     g_free(message);
01672     
01673     return TRUE;
01674 }
01675 
01676 
01677 static gboolean write_sysfs(const char *device, const char *filename, const char *buffer)
01678 {
01679     LOGPRINTF("entry");
01680     
01681     gboolean retval = FALSE;
01682     char *file = NULL;
01683     gint fd = 0;
01684     gint result = 0;
01685     
01686     if (!device)
01687     {
01688         return FALSE;
01689     }
01690     
01691     file = g_strconcat(device, "/", filename, NULL);
01692     
01693     fd = open(file, O_WRONLY);
01694     if (fd >= 0)
01695     {
01696         result = write(fd, buffer, strlen(buffer));
01697         close(fd);
01698         
01699         if (result > -1)
01700         {
01701             retval = TRUE;
01702         }
01703         else
01704         {
01705             WARNPRINTF("Could not write to `%s` (%d), %s", file, errno, strerror(errno));
01706         }
01707     }
01708     else
01709     {
01710         WARNPRINTF("Could not open %s", filename);
01711     }
01712     
01713     g_free(file);
01714     
01715     return retval;
01716 }
01717 
01718 
01719 static char *find_dir(const char *dir, const char *name, gboolean recurse)
01720 {
01721     LOGPRINTF("entry: [%s] [%s]", dir, name);
01722     
01723     struct  dirent **namelist;
01724     char   *full_name = NULL;
01725     int     i         = 0;
01726     int     count     = 0;
01727 
01728     count = scandir(dir, &namelist, 0, alphasort);
01729     for(i = 0; i < count; i++) 
01730     {
01731         char *filename = namelist[i]->d_name;
01732         
01733         if (filename && (strcmp(filename, ".") != 0) && (strcmp(filename, "..") != 0)) 
01734         {
01735             char fullpath[512] = "";
01736             strcat(fullpath, dir);
01737             strcat(fullpath, "/");
01738             strcat(fullpath, filename);
01739 
01740             struct stat attributs;
01741             if (lstat(fullpath, &attributs) == -1)
01742             {
01743                 WARNPRINTF("Error reading attributes of '%s'", fullpath);
01744             }
01745 
01746             if S_ISDIR(attributs.st_mode)
01747             {
01748                 if (name != NULL)
01749                 {
01750                     if (strncmp(filename, name, strlen(name)) == 0)
01751                     {
01752                         // dir found
01753                         full_name = g_strdup(fullpath);
01754                         break;
01755                     }
01756                     else if (recurse && name != NULL) 
01757                     {
01758                         // recursive search 
01759                         full_name = find_dir(fullpath, name, recurse);
01760                         if (full_name)
01761                         {
01762                             // dir found
01763                             break;
01764                         }
01765                         g_free(full_name);
01766                     }
01767                 }
01768             } 
01769         }
01770     }
01771     
01772     g_free(namelist);
01773     return full_name;
01774 }
01775 
01776 
01777 static void report_unmounting_volumes()
01778 {
01779     LOGPRINTF("entry");
01780     
01781     hal_device *device = hal_device_list_get_root();
01782     hal_device_property *property;
01783 
01784     while (device != NULL)
01785     {
01786         property = hal_device_list_get_property("volume.mount_point", device);
01787         if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
01788         {
01789             LOGPRINTF("about to unmount: %s", *property->values);
01790             ipc_send_prepare_unmount(*property->values);            
01791         }
01792         device = device->next;
01793     }
01794 }
01795 
01796 
01797 static enum state_charge get_battery_state(gint level, gint charging)
01798 {
01799     LOGPRINTF("entry");
01800 
01801     enum state_charge cur_state;
01802     
01803     if (charging == 1)
01804     {
01805 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
01806         if (level >= BATTERY_FULL_THRESHOLD)
01807         {
01808             cur_state = STATE_CHARGE_FULL;
01809         }
01810         else
01811 #endif
01812         {
01813             cur_state = STATE_CHARGE_CHARGING;
01814         }
01815     }
01816     else
01817     {
01818 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01819         if (level >= BATTERY_FULL_THRESHOLD)
01820         {
01821             cur_state = STATE_CHARGE_FULL;
01822         }
01823         else
01824 #endif
01825         if (level <= BATTERY_LOW_THRESHOLD)
01826         {
01827             cur_state = STATE_CHARGE_LOW;
01828         }
01829         else 
01830         {
01831             cur_state = STATE_CHARGE_DISCHARGING;
01832         }
01833     }
01834 
01835     LOGPRINTF("returns %d", cur_state);
01836     return cur_state;
01837 }
01838 
01839 
01840 static void check_hardware()
01841 {
01842     LOGPRINTF("entry");
01843 
01844     char hardware[5] = {0};
01845     gint rc = 0;
01846     
01847     rc = read_ionkbd("hardware_state", "%s", &hardware);
01848     if (rc > 0)
01849     {
01850         LOGPRINTF("hardware: %s", hardware);
01851         sys_update_hardware(hardware);
01852     }
01853 }
01854 
01855 
01856 static void update_battery_info(gint cur_level, enum state_charge cur_state, gboolean force_send)
01857 {
01858     LOGPRINTF("entry");
01859     
01860     enum state_charge     old_state = charge_state;
01861     
01862     // update battery information when:
01863     // - forced by argument in call
01864     // - charge state changed
01865     // - value has changed
01866     if ( (force_send == TRUE) ||
01867          (cur_state != old_state) ||
01868          (g_battery_level != cur_level)
01869        )
01870     {
01871         // save level and state for later
01872         g_battery_level = cur_level;
01873         charge_state = cur_state;
01874         
01875         ipc_send_battery_state(cur_level, cur_state, -1);
01876 
01877         // if cur_state != "low" then any splash screen is removed during
01878         // charge/discharge of battery.
01879         switch (old_state)
01880         {
01881             case STATE_CHARGE_LOW:
01882                 if ( cur_state == STATE_CHARGE_CHARGING )
01883                 {   
01884                     ipc_show_splash("hide");
01885                     break;
01886                 }
01887                 if ( cur_state == STATE_CHARGE_LOW )
01888                 {
01889                     ipc_show_splash("batterylow");
01890                     break;
01891                 }
01892             case STATE_CHARGE_CHARGING:
01893             case STATE_CHARGE_DISCHARGING:
01894                 if ( cur_state == STATE_CHARGE_LOW )
01895                 {
01896                     ipc_show_splash("batterylow");
01897                 }
01898                 break;
01899             default:
01900                 // do nothing
01901                 break;
01902         }
01903 
01904         // update led to new state
01905         sys_update_rgb_led();
01906     }
01907     
01908     if ( (charge_state == STATE_CHARGE_LOW) && (cur_level <= BATTERY_SHUTDOWN_THRESHOLD) )
01909     {
01910         if (g_standby_if_plugged || (usb_state == STATE_USB_DISCONNECTED) || (usb_state == STATE_USB_UNKNOWN))
01911         {
01912             LOGPRINTF("Power off now");
01913             do_poweroff();
01914             return;
01915         }
01916         else
01917         {
01918             LOGPRINTF("Don't power off as device is plugged in. usb_state [%d] if_plugged [%d]", usb_state, g_standby_if_plugged);
01919         }
01920     }
01921     
01922     conn_check_battery(cur_level);
01923 }
01924 
01925 
01926 static void usb_set_state(enum state_usb new_state)
01927 {
01928 #if (LOGGING_ON)
01929     static const gchar *state_str[] =
01930     {
01931         [STATE_USB_UNKNOWN]             = "STATE_USB_UNKNOWN",
01932         [STATE_USB_DISCONNECT_PENDING]  = "STATE_USB_DISCONNECT_PENDING",
01933         [STATE_USB_DISCONNECTED]        = "STATE_USB_DISCONNECTED",
01934         [STATE_USB_UNMOUNTED]           = "STATE_USB_UNMOUNTED",
01935         [STATE_USB_MOUNT_CONFIRM]       = "STATE_USB_MOUNT_CONFIRM",
01936         [STATE_USB_MOUNT_PENDING]       = "STATE_USB_MOUNT_PENDING",
01937         [STATE_USB_MOUNTED]             = "STATE_USB_MOUNTED",
01938     };
01939 #endif
01940     enum state_usb old_state = usb_state;
01941     if (old_state == new_state)
01942     {
01943         WARNPRINTF("huh? already in state [%d]", new_state);
01944         return;
01945     }
01946     usb_state = new_state;
01947     LOGPRINTF("change usb_state %s > %s", state_str[old_state],  state_str[new_state]);
01948 
01949     if (new_state == STATE_USB_DISCONNECTED || new_state == STATE_USB_UNMOUNTED)
01950     {
01951         if (old_state == STATE_USB_MOUNT_CONFIRM)
01952         {
01953             // remove confirmation dialog
01954             ipc_confirm_usbconnect(FALSE);
01955         }
01956 
01957         if (   (old_state == STATE_USB_MOUNT_CONFIRM) 
01958             || (old_state == STATE_USB_DISCONNECT_PENDING) 
01959             || (old_state == STATE_USB_MOUNTED)
01960             || (old_state == STATE_USB_UNMOUNTED) )
01961         {
01962             // unload volume and drivers
01963             usb_driver_unload();
01964             g_wallcharger_found = FALSE;
01965         }
01966             
01967         if (   (old_state == STATE_USB_MOUNTED)
01968             || (old_state == STATE_USB_DISCONNECT_PENDING))
01969         {
01970             if (card_state == STATE_CARD_EJECTED)
01971             {
01972                 // don't try to remount volume(s) 
01973                 usb_connection_finish();
01974                 ipc_show_splash("nosd");
01975             }
01976             else
01977             {
01978                 // remount volume(s)
01979                 hal_remount_all_volumes(on_usb_disconnected, NULL);
01980             }
01981         }   
01982     }
01983 
01984     switch (new_state)
01985     {
01986     case STATE_USB_UNKNOWN:
01987         break;
01988     case STATE_USB_DISCONNECTED:
01989         ipc_send_usb_state("disconnected");
01990         break;
01991     case STATE_USB_UNMOUNTED:
01992         ipc_send_usb_state("unmounted");
01993         break;
01994     case STATE_USB_MOUNT_CONFIRM:
01995 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01996         // ask user to confirm USB export if not in demo mode
01997         if (!g_demo_mode)
01998         {
01999             ipc_confirm_usbconnect(TRUE);
02000         }
02001         else
02002 #endif
02003         {
02004             // don't ask confirmation from user, connect immediately
02005             sys_usb_connect();
02006         }
02007         break;
02008     case STATE_USB_DISCONNECT_PENDING:
02009     case STATE_USB_MOUNT_PENDING:
02010         break;
02011     case STATE_USB_MOUNTED:
02012         ipc_send_usb_state("mounted");
02013         break;
02014     }
02015 }
02016 
02017 
02018 static gboolean usb_driver_load()
02019 {
02020     LOGPRINTF("entry");
02021     
02022     // wait a bit to let USB settle
02023     g_usleep(G_USEC_PER_SEC * 2);
02024 
02025     gboolean retval = sys_spawn_sync("modprobe g_file_storage removable=y");
02026     if (retval)
02027     {
02028         // find usb device
02029         if (g_usb) g_free(g_usb);
02030         g_usb = find_dir(sys_devices, usb_device_name, TRUE);
02031         if (!g_usb) 
02032         {
02033             ERRORPRINTF("%s not found or not unique", usb_device_name);
02034             retval = FALSE;            
02035         }
02036     }
02037     return retval;
02038 }
02039 
02040 
02041 static gboolean usb_driver_unload()
02042 {
02043     LOGPRINTF("entry");
02044     
02045     gboolean retval = sys_spawn_sync("modprobe -r g_file_storage");
02046     if (retval)
02047     {
02048         g_usb = NULL;
02049     }
02050     return retval;
02051 }
02052 
02053 
02054 static gboolean usb_connect()
02055 {
02056     gboolean retval = FALSE;
02057 
02058     LOGPRINTF("entry");
02059 
02060     if (g_volume_unmount_source)
02061     {
02062         g_source_remove(g_volume_unmount_source);
02063     }
02064     
02065     // find usb gadget lun
02066     if (g_lun) g_free(g_lun);
02067     g_lun = find_dir(sys_devices, lun_device_name, TRUE);
02068     if (g_lun) 
02069     {
02070         // mount device for gadget
02071         if (g_card_device)
02072         {
02073             write_sysfs(g_lun, "file", g_card_device);
02074             
02075             // set poll timer to check connection
02076             busy_add_background(0);                    
02077             g_usb_device_source = g_timeout_add_seconds(USB_DEVICE_POLL_INTERVAL, on_usb_read_online, NULL);
02078 
02079             usb_set_state(STATE_USB_MOUNTED);
02080             retval = TRUE;
02081         }
02082         else
02083         {
02084             ERRORPRINTF("device of mountpoint not found");
02085         }
02086     }
02087     else
02088     {
02089         ERRORPRINTF("%s not found or not unique", lun_device_name);
02090     }
02091     
02092     return retval;
02093 }
02094 
02095 
02096 static void on_usb_connected(gpointer data)
02097 {
02098     LOGPRINTF("entry");
02099     
02100     if (usb_state == STATE_USB_MOUNT_PENDING)
02101     {
02102         usb_connect();
02103     }
02104     else if (usb_state == STATE_USB_DISCONNECT_PENDING)
02105     {
02106         usb_set_state(STATE_USB_DISCONNECTED);
02107     }
02108     
02109     busy_remove_foreground(0);
02110 }
02111 
02112 
02113 static gboolean on_usb_disconnected(gpointer data)
02114 {
02115     LOGPRINTF("entry");
02116     
02117     usb_connection_finish();
02118     
02119     if (usb_state == STATE_USB_MOUNTED)
02120     {
02121         usb_set_state(STATE_USB_UNMOUNTED);
02122     }
02123 
02124     // stop timeout
02125     return FALSE;
02126 }
02127 
02128 
02129 static void usb_connection_finish()
02130 {
02131     LOGPRINTF("entry");
02132     
02133     // stop polling for usb state
02134     if (g_usb_device_source)
02135     {
02136         g_source_remove(g_usb_device_source);
02137         g_usb_device_source = 0;
02138     }
02139 }
02140 
02141 
02142 static gboolean on_usb_read_device_state(gpointer data)
02143 {
02144     static gint count = 0;
02145     gboolean continue_polling = TRUE;
02146     gboolean host_available   = FALSE;
02147     
02148     char state[80] = {0};
02149     read_usb("device_state", "%*d:%s", &state);
02150     LOGPRINTF("device_state [%s]", state);
02151 
02152     if (strcmp(state, "address") == 0)
02153     {
02154         host_available = TRUE;
02155     }
02156     
02157     if (usb_state == STATE_USB_UNMOUNTED)
02158     {
02159         if ((host_available) && (card_state == STATE_CARD_MOUNTED))
02160         {
02161             LOGPRINTF("USB host found, connect immediately");
02162             usb_set_state(STATE_USB_MOUNT_CONFIRM);
02163             continue_polling = FALSE;
02164         }
02165         else if (count > USB_DEVICE_POLL_TIMEOUT)
02166         {
02167             LOGPRINTF("USB not host found (is charger), stop polling and unload");
02168             usb_driver_unload();
02169 
02170             g_wallcharger_found = TRUE;
02171             continue_polling = FALSE;
02172         }
02173     }
02174     else
02175     {
02176         if (!host_available)
02177         {
02178             if (usb_state != STATE_USB_DISCONNECTED)
02179             {
02180                 LOGPRINTF("USB suspended, remove dialog and disconnect");
02181                 usb_set_state(STATE_USB_UNMOUNTED);
02182             }
02183             continue_polling = FALSE;
02184         }
02185     }
02186     
02187     if (continue_polling)    
02188     {
02189         count++;
02190     }
02191     else
02192     {
02193         busy_remove_background(0);
02194         g_usb_device_source = 0;
02195         count = 0;
02196     }
02197     
02198     return continue_polling;
02199 }
02200 
02201 
02202 static gboolean on_usb_read_online(gpointer data)
02203 {
02204     static gint count = 0;
02205     gboolean continue_polling = TRUE;
02206 
02207     gint state = -1;
02208     read_lun("online", "%d", &state);
02209     LOGPRINTF("online [%d]", state);
02210 
02211     if (state == 0 && count > USB_DEVICE_ONLINE_DELAY)
02212     {
02213         if (usb_state != STATE_USB_DISCONNECTED)
02214         {
02215             LOGPRINTF("OFFLINE, remove dialog and disconnect");
02216             usb_set_state(STATE_USB_UNMOUNTED);
02217         }
02218         continue_polling = FALSE;
02219     }
02220     else if (state == -1)
02221     {
02222         LOGPRINTF("Can't read OFFLINE state, gadget probably unloaded");
02223         continue_polling = FALSE;
02224     }
02225 
02226     if (continue_polling)    
02227     {
02228         count++;
02229     }
02230     else
02231     {
02232         busy_remove_background(0);
02233         g_usb_device_source = 0;
02234         count = 0;
02235     }
02236     
02237     return continue_polling;
02238 }
02239 
02240 
02241 static void on_poweroff_continue(gpointer data)
02242 {
02243     LOGPRINTF("entry");
02244 
02245     // enable/unlock all three sensors before power off
02246     write_ionkbd("sensor_enable", "7"); 
02247 
02248     // power off and wait
02249     sys_spawn_sync("shutdown -h now");
02250 
02251     while (1)
02252     {
02253         g_usleep(G_USEC_PER_SEC * 1);
02254     }
02255 
02256     WARNPRINTF("this should never be reached");
02257 }
02258 
02259 
02260 static void on_restart_continue(gpointer data)
02261 {
02262     LOGPRINTF("entry");
02263 
02264     // cold reboot 
02265     sys_spawn_sync("reboot");
02266 }
02267 
02268 
02269 static void on_eject_continue(gpointer data)
02270 {
02271     LOGPRINTF("entry");
02272     
02273     gboolean silent = (gboolean) data;
02274     
02275     busy_remove_foreground(0);
02276 
02277     if (!silent)
02278     {
02279         ipc_show_splash("safelyremove");
02280     }
02281 }
02282 
02283 
02284 static void set_idle_time(gint time)
02285 {
02286     if (!g_idle_enabled)
02287     {
02288         return;
02289     }
02290     
02291     if ((power_state == STATE_POWER_IDLE) || (power_state == STATE_POWER_STANDBY))
02292     {
02293         if (g_idle_time_source)
02294         {
02295             // stop idle time when preparing for idle or standby
02296             LOGPRINTF("stop idle time when preparing for idle or standby");
02297             g_source_remove(g_idle_time_source);
02298             g_idle_time_source = 0;
02299         }
02300         return;
02301     }
02302 
02303 #if (LOGGING_ON)
02304     GTimeVal curtime;
02305     g_get_current_time(&curtime);
02306     LOGPRINTF(" %ld:%3ld Reset idle >>> STATE_POWER_RUN", curtime.tv_sec, curtime.tv_usec / 1000);
02307 #endif
02308     
02309     power_state = STATE_POWER_RUN;
02310 
02311     if (time <= 0)
02312     {
02313         time = IDLE_TIMEOUT_SEC;
02314     }
02315     
02316     if (g_idle_time_source)
02317     {
02318         g_source_remove(g_idle_time_source);
02319     }
02320     g_idle_time_source = g_timeout_add_seconds(time, on_idle_timeout, NULL);
02321 }
02322 
02323 
02324 static gboolean on_idle_timeout(gpointer data)
02325 {
02326     LOGPRINTF("entry");
02327 
02328 #if (LOGGING_ON)
02329     GTimeVal curtime;
02330     g_get_current_time(&curtime);
02331     LOGPRINTF(" %ld:%3ld Idle for %d seconds, idle pending >>> STATE_POWER_IDLE", 
02332               curtime.tv_sec, curtime.tv_usec / 1000, IDLE_TIMEOUT_SEC);
02333 #endif
02334     
02335     if (!g_idle_enabled)
02336     {
02337         return FALSE;
02338     }
02339 
02340     if ( is_busy_background() ||
02341          conn_is_online() || conn_is_initialising() || 
02342          (usb_state    == STATE_USB_MOUNT_CONFIRM) || (usb_state    == STATE_USB_MOUNT_PENDING) || (usb_state  == STATE_USB_MOUNTED ) || 
02343          (device_state == STATE_DEVICE_STOPPING) ||
02344          (power_state  == STATE_POWER_IDLE) )
02345     {
02346         LOGPRINTF("Don't idle as system is busy (bgbusy [%d] online [%d] usb_state [%d] device_state [%d] power_state [%d])", 
02347                    is_busy_background(), conn_is_online(), usb_state, device_state, power_state);
02348         return TRUE;
02349     }
02350     else 
02351     {
02352         gint x_idle = window_get_idle_time();
02353         
02354         if ((x_idle != -1) && (x_idle < IDLE_TIMEOUT_SEC))
02355         {
02356             LOGPRINTF("Don't idle as X is idle for %d sec, wait %d sec more", x_idle, IDLE_TIMEOUT_SEC-x_idle);
02357             set_idle_time(IDLE_TIMEOUT_SEC-x_idle);
02358         }
02359         else
02360         {
02361             do_idle();
02362         }
02363     }
02364     
02365     // stop timer
02366     return FALSE;
02367 }
02368 
02369 
02370 static void do_unmount(gboolean show_busy, const char *splash, gpointer callback_function, gpointer user_data)
02371 {
02372     LOGPRINTF("entry");
02373     
02374     if (show_busy)
02375     {
02376         busy_add_foreground(0, BUSY_DIALOG_DIRECT, NULL);
02377     }
02378    
02379     if (splash)
02380     {
02381         ipc_show_splash(splash);
02382     }
02383 
02384     // stop optional demo mode
02385     stop_demo_mode();
02386 
02387     // have applications close their files
02388     report_unmounting_volumes();
02389 
02390     // run export settings and wait
02391     sys_spawn_sync(ERCONFTOOL_EXPORT);
02392 
02393     // synchronize with Adobe Digital Editions
02394     sys_spawn_sync(ADOBE_SYNC);
02395 
02396     // unmount volumes
02397     hal_unmount_all_volumes(callback_function, user_data);
02398 }
02399 
02400 
02401 static void do_poweroff(void)
02402 {
02403     LOGPRINTF("entry");
02404     
02405     if (device_state != STATE_DEVICE_STOPPING)
02406     {
02407         device_state = STATE_DEVICE_STOPPING;
02408         busy_add_foreground(0, BUSY_DIALOG_NONE, NULL);
02409         if (card_state == STATE_CARD_MOUNTED)
02410         {
02411             do_unmount(TRUE, "shutdown", on_poweroff_continue, NULL);
02412         }
02413         else
02414         {
02415             // skip unmounting, power off immediately
02416             on_poweroff_continue(NULL);
02417         }
02418     }
02419 }
02420 
02421 
02422 static gint get_wakeup_reason()
02423 {
02424     // get reason
02425     gint reason = WAKEUP_NO_REASON;
02426     gint rc = 0;
02427        
02428     g_usleep(75*1000); // wait while micro driver reads new values from microcontroller
02429     rc = read_ionkbd("wakeup_reason", "%d", &reason);
02430     if (rc <= 0)
02431     {
02432         reason = WAKEUP_NO_REASON;
02433     }
02434         
02435 #if (LOGGING_ON)
02436     const gchar *reason_str[] = { "NO_REASON", "KEY", "PEN", "TIMER (standby)", "BATTERY", "COVER", "CARD", "USB", "CHARGE_DETECTED" };
02437     LOGPRINTF("Wakeup reason: %s", reason_str[reason]);
02438 #endif        
02439     
02440     return reason;
02441 }    
02442 
02443 
02444 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S  || MACHINE_IS_DR800SW
02445 static gboolean on_check_standby(gpointer data)
02446 {
02447     LOGPRINTF("entry");
02448 
02449     g_timeout_add(CHECK_STANDBY_TIMEOUT_MS, on_standby, NULL);
02450     return FALSE;
02451 }
02452 
02453 
02454 static void prepare_standby()
02455 {
02456     LOGPRINTF("entry");
02457 
02458     if ( (device_state == STATE_DEVICE_STOPPING) ||                               /* preparing power off */
02459          (power_state == STATE_POWER_STANDBY) ||                                  /* preparing standby */
02460          (power_state == STATE_POWER_IDLE) ||                                     /* preparing idle */
02461          ((usb_state == STATE_USB_UNMOUNTED) && (g_usb_device_source != 0)) )     /* polling for USB charger/host */
02462     {
02463         LOGPRINTF("Don't enter standby now! (device_state [%d] power_state [%d] usb_state [%d][%d])", 
02464           device_state, power_state, usb_state, g_usb_device_source);
02465         return;
02466     }
02467     
02468     power_state = STATE_POWER_STANDBY;
02469 
02470     LOGPRINTF("Prepare standby");
02471 
02472     // suppress all updates and erase display
02473     display_splash_lock();
02474     display_blank();
02475 
02476     // stop optional demo mode
02477     stop_demo_mode();
02478 
02479     // let application prepare for standby
02480     ipc_send_prepare_standby();
02481     conn_stop();
02482 
02483     g_timeout_add(PREPARE_STANDBY_TIMEOUT_MS, on_check_standby, NULL);
02484 }
02485 
02486 
02487 static gboolean on_holdoff_timeout(gpointer data)
02488 {
02489     g_holdoff_standby = 0;
02490     return FALSE;
02491 }
02492 
02493 
02494 static gboolean on_standby(gpointer data)
02495 {
02496     LOGPRINTF("entry");
02497     
02498     gint cur_level = 0;
02499     gint retval = 0;
02500     enum state_charge cur_state = STATE_CHARGE_UNKNOWN;
02501 
02502     if (device_state == STATE_DEVICE_STOPPING)
02503     {
02504         WARNPRINTF("Device is stopping, don't enter standby now!");
02505         return FALSE;
02506     }
02507     
02508     // call standby script and wait for it to return
02509     
02510     LOGPRINTF("Enter standby");
02511     
02512     // export gconf to INI here so changes made during "prepare standby" as saved
02513     sys_spawn_sync(ERCONFTOOL_EXPORT);
02514 
02515     // commit buffer cache to disk
02516     sync();
02517     
02518     // suspend wacom to save power
02519     gboolean wacom_enabled = wacom_is_enabled();
02520     if (wacom_enabled)
02521     {
02522         wacom_disable();
02523     }
02524 
02525     // do any connection related suspend work
02526     conn_on_enter_standby();
02527 
02528     if (g_wallcharger_found)
02529     {
02530         // enable fast-fast charge
02531         // will be reset in standby.sh
02532         write_ionkbd("fastcharge", "1");
02533     }
02534     
02535     sys_spawn_sync("standby.sh");
02536    
02537     //
02538     // Back from standby
02539     //
02540     
02541     LOGPRINTF("Back from standby");
02542 
02543     gint reason = get_wakeup_reason();
02544     if ( reason == WAKEUP_BATTERY )
02545     {
02546         WARNPRINTF("Low battery, power off now");
02547         do_poweroff();
02548         return FALSE;
02549     }
02550 
02551     // reinitialize delta
02552     display_init();
02553     display_set_vcom(sys_get_display_vcom());
02554     display_set_waveforms();
02555     
02556     // redraw screen
02557     display_splash_unlock();
02558     display_update_return_control(DM_HINT_FULL);
02559 
02560     // check hardware state as it might have changed during standby
02561     check_hardware();
02562     
02563     // check battery state as it might have changed during standby
02564     retval = sys_get_battery(&cur_level, &cur_state, NULL);
02565     if (retval == TRUE)
02566     {                    
02567         // wakeup to update battery, force!
02568         update_battery_info(cur_level, cur_state, TRUE);
02569     }
02570 
02571     sys_update_rgb_led();
02572         
02573     power_state = STATE_POWER_RUN;
02574     // dislay updates are resumed from here
02575 
02576     sys_reset_idle_time();
02577 
02578     // power on wacom again
02579     if (wacom_enabled)
02580     {
02581         wacom_enable();
02582     }
02583 
02584     g_holdoff_standby = g_timeout_add_seconds(HOLDOFF_STANDBY_TIMEOUT, on_holdoff_timeout, NULL);
02585     
02586     gboolean do_drz = check_and_install_drz();
02587     gboolean do_firmware = sys_check_and_install_firmware();
02588     gboolean do_disk = check_disk_free();
02589 
02590     conn_on_leave_standby();
02591 
02592     if (!(do_drz || do_firmware || do_disk)) {
02593         if (g_file_test(MOUNTPOINT_CARD"/"DEMO_FILE, G_FILE_TEST_EXISTS)) {
02594             start_demo_mode();
02595         }
02596     }
02597 
02598     return FALSE;
02599 }
02600 
02601 #endif
02602 
02603 
02604 static void do_idle()
02605 {
02606     LOGPRINTF("entry");
02607 
02608     gint cur_level = 0;
02609     gint retval = 0;
02610     static glong standby_time = 0;
02611     enum state_charge cur_state = STATE_CHARGE_UNKNOWN;
02612     
02613     if (!g_idle_enabled)
02614     {
02615         return;
02616     }
02617 
02618     if ((device_state == STATE_DEVICE_STOPPING) || (power_state == STATE_POWER_STANDBY))
02619     {
02620         LOGPRINTF("Don't enter idle now! (device_state [%d] power_state [%d])",
02621                     device_state, power_state);
02622         return;
02623     }
02624     
02625     power_state = STATE_POWER_IDLE;
02626     // dislay updates are resumed from here
02627 
02628     // suspend wacom to save power
02629     if (wacom_is_enabled())
02630     {
02631         wacom_suspend();
02632     }
02633 
02634     if ( (g_standby_timeout_sec > 0) 
02635         && (g_standby_if_plugged || (usb_state == STATE_USB_DISCONNECTED)) )
02636     {
02637         // calculate and set standby time
02638         GTimeVal curtime;
02639         g_get_current_time(&curtime);
02640         
02641         if ((standby_time == 0) || (standby_time <= curtime.tv_sec))
02642         {
02643             standby_time = curtime.tv_sec + g_standby_timeout_sec;
02644         }
02645 
02646         gint min_before_standby = (standby_time - curtime.tv_sec) / 60;
02647         
02648         LOGPRINTF("Minutes before standby: %d, standby time: %ld, now: %ld",
02649                   min_before_standby, standby_time, curtime.tv_sec); 
02650             
02651         if (min_before_standby > 0)
02652         {
02653             // call idle script and wait for it to return
02654             gchar *command = g_strdup_printf("idle.sh %d", min_before_standby);
02655             sys_spawn_sync(command);
02656             g_free(command);
02657         }
02658         else
02659         {
02660             WARNPRINTF("Go to standby immediately");
02661             sys_standby();
02662             return;
02663         }
02664     }
02665     else
02666     {
02667         // call idle script and wait for it to return
02668         LOGPRINTF("Enter idle without standby");
02669         sys_spawn_sync("idle.sh");
02670     }
02671 
02672     //
02673     // Back from idle
02674     //
02675     
02676     LOGPRINTF("Back from idle");
02677 
02678     gint reason = get_wakeup_reason();
02679     if ( (reason == WAKEUP_TIMER) && 
02680          (g_standby_if_plugged || (usb_state == STATE_USB_DISCONNECTED)) )
02681     {
02682         WARNPRINTF("Idle timed out, go to standby now");
02683         standby_time = 0;
02684         power_state = STATE_POWER_RUN;
02685         sys_standby();
02686     }
02687     else
02688     {
02689         // check hardware state as it might have changed during idle
02690         if (reason == WAKEUP_USB)
02691         {
02692             check_hardware();
02693         }
02694         
02695         // check battery state as it might have changed during idle
02696         retval = sys_get_battery(&cur_level, &cur_state, NULL);
02697         if (retval == TRUE)
02698         {                    
02699             // reflect new battery/charge state
02700             if (reason == WAKEUP_BATTERY)                
02701             {
02702                 // wakeup to update battery, force!
02703                 update_battery_info(cur_level, cur_state, TRUE);
02704             }
02705             else
02706             {
02707                 update_battery_info(cur_level, cur_state, FALSE);
02708             }
02709         }
02710 
02711         sys_update_rgb_led();
02712             
02713         standby_time = 0;
02714         power_state = STATE_POWER_RUN;
02715         sys_reset_idle_time(); 
02716 
02717         if (wacom_is_enabled())
02718         {
02719             if (reason == WAKEUP_PEN)
02720             {
02721                 // resume Wacom from suspend
02722                 wacom_resume();
02723             }
02724             else
02725             {
02726                 // reset Wacom hardware as it may be stuck
02727                 wacom_reset();
02728             }
02729         }
02730     }
02731 }
Generated by  doxygen 1.6.2-20100208