Home | History | Annotate | Download | only in liblight
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * Copyright (C) 2014 The  Linux Foundation. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 
     19 // #define LOG_NDEBUG 0
     20 
     21 #include <cutils/log.h>
     22 
     23 #include <stdint.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <unistd.h>
     27 #include <errno.h>
     28 #include <fcntl.h>
     29 #include <pthread.h>
     30 
     31 #include <sys/ioctl.h>
     32 #include <sys/types.h>
     33 
     34 #include <hardware/lights.h>
     35 
     36 /******************************************************************************/
     37 
     38 static pthread_once_t g_init = PTHREAD_ONCE_INIT;
     39 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
     40 static struct light_state_t g_notification;
     41 static struct light_state_t g_battery;
     42 static int g_attention = 0;
     43 
     44 char const*const RED_LED_FILE
     45         = "/sys/class/leds/red/brightness";
     46 
     47 char const*const GREEN_LED_FILE
     48         = "/sys/class/leds/green/brightness";
     49 
     50 char const*const BLUE_LED_FILE
     51         = "/sys/class/leds/blue/brightness";
     52 
     53 char const*const BLUETOOTH_LED_FILE
     54         = "/sys/class/leds/bt/brightness";
     55 
     56 char const*const LCD_FILE
     57         = "/sys/class/leds/lcd-backlight/brightness";
     58 
     59 char const*const BUTTON_FILE
     60         = "/sys/class/leds/button-backlight/brightness";
     61 
     62 char const*const RED_BLINK_FILE
     63         = "/sys/class/leds/red/blink";
     64 
     65 char const*const GREEN_BLINK_FILE
     66         = "/sys/class/leds/green/blink";
     67 
     68 char const*const BLUE_BLINK_FILE
     69         = "/sys/class/leds/blue/blink";
     70 
     71 /**
     72  * device methods
     73  */
     74 
     75 void init_globals(void)
     76 {
     77     // init the mutex
     78     pthread_mutex_init(&g_lock, NULL);
     79 }
     80 
     81 static int
     82 write_int(char const* path, int value)
     83 {
     84     int fd;
     85     static int already_warned = 0;
     86 
     87     fd = open(path, O_RDWR);
     88     if (fd >= 0) {
     89         char buffer[20];
     90         int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
     91         ssize_t amt = write(fd, buffer, (size_t)bytes);
     92         close(fd);
     93         return amt == -1 ? -errno : 0;
     94     } else {
     95         if (already_warned == 0) {
     96             ALOGE("write_int failed to open %s\n", path);
     97             already_warned = 1;
     98         }
     99         return -errno;
    100     }
    101 }
    102 
    103 static int
    104 is_lit(struct light_state_t const* state)
    105 {
    106     return state->color & 0x00ffffff;
    107 }
    108 
    109 static int
    110 rgb_to_brightness(struct light_state_t const* state)
    111 {
    112     int color = state->color & 0x00ffffff;
    113     return ((77*((color>>16)&0x00ff))
    114             + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
    115 }
    116 
    117 static int
    118 set_light_backlight(struct light_device_t* dev,
    119         struct light_state_t const* state)
    120 {
    121     int err = 0;
    122     int brightness = rgb_to_brightness(state);
    123     if(!dev) {
    124         return -1;
    125     }
    126     pthread_mutex_lock(&g_lock);
    127     err = write_int(LCD_FILE, brightness);
    128     pthread_mutex_unlock(&g_lock);
    129     return err;
    130 }
    131 
    132 static int
    133 set_speaker_light_locked(struct light_device_t* dev,
    134         struct light_state_t const* state)
    135 {
    136     int red, green, blue;
    137     int blink;
    138     int onMS, offMS;
    139     unsigned int colorRGB;
    140 
    141     if(!dev) {
    142         return -1;
    143     }
    144 
    145     switch (state->flashMode) {
    146         case LIGHT_FLASH_TIMED:
    147             onMS = state->flashOnMS;
    148             offMS = state->flashOffMS;
    149             break;
    150         case LIGHT_FLASH_NONE:
    151         default:
    152             onMS = 0;
    153             offMS = 0;
    154             break;
    155     }
    156 
    157     colorRGB = state->color;
    158 
    159 #if 0
    160     ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n",
    161             state->flashMode, colorRGB, onMS, offMS);
    162 #endif
    163 
    164     red = (colorRGB >> 16) & 0xFF;
    165     green = (colorRGB >> 8) & 0xFF;
    166     blue = colorRGB & 0xFF;
    167 
    168     if (onMS > 0 && offMS > 0) {
    169         /*
    170          * if ON time == OFF time
    171          *   use blink mode 2
    172          * else
    173          *   use blink mode 1
    174          */
    175         if (onMS == offMS)
    176             blink = 2;
    177         else
    178             blink = 1;
    179     } else {
    180         blink = 0;
    181     }
    182 
    183     if (blink) {
    184         if (red) {
    185             if (write_int(RED_BLINK_FILE, blink))
    186                 write_int(RED_LED_FILE, 0);
    187 	}
    188         if (green) {
    189             if (write_int(GREEN_BLINK_FILE, blink))
    190                 write_int(GREEN_LED_FILE, 0);
    191 	}
    192         if (blue) {
    193             if (write_int(BLUE_BLINK_FILE, blink))
    194                 write_int(BLUE_LED_FILE, 0);
    195 	}
    196     } else {
    197         write_int(RED_LED_FILE, red);
    198         write_int(GREEN_LED_FILE, green);
    199         write_int(BLUE_LED_FILE, blue);
    200     }
    201 
    202     return 0;
    203 }
    204 
    205 static void
    206 handle_speaker_battery_locked(struct light_device_t* dev)
    207 {
    208     if (is_lit(&g_battery)) {
    209         set_speaker_light_locked(dev, &g_battery);
    210     } else {
    211         set_speaker_light_locked(dev, &g_notification);
    212     }
    213 }
    214 
    215 static int
    216 set_light_battery(struct light_device_t* dev,
    217         struct light_state_t const* state)
    218 {
    219     pthread_mutex_lock(&g_lock);
    220     g_battery = *state;
    221     handle_speaker_battery_locked(dev);
    222     pthread_mutex_unlock(&g_lock);
    223     return 0;
    224 }
    225 
    226 static int
    227 set_light_notifications(struct light_device_t* dev,
    228         struct light_state_t const* state)
    229 {
    230     pthread_mutex_lock(&g_lock);
    231     g_notification = *state;
    232     handle_speaker_battery_locked(dev);
    233     pthread_mutex_unlock(&g_lock);
    234     return 0;
    235 }
    236 
    237 static int
    238 set_light_attention(struct light_device_t* dev,
    239         struct light_state_t const* state)
    240 {
    241     pthread_mutex_lock(&g_lock);
    242     if (state->flashMode == LIGHT_FLASH_HARDWARE) {
    243         g_attention = state->flashOnMS;
    244     } else if (state->flashMode == LIGHT_FLASH_NONE) {
    245         g_attention = 0;
    246     }
    247     handle_speaker_battery_locked(dev);
    248     pthread_mutex_unlock(&g_lock);
    249     return 0;
    250 }
    251 
    252 static int
    253 set_light_buttons(struct light_device_t* dev,
    254         struct light_state_t const* state)
    255 {
    256     int err = 0;
    257     if(!dev) {
    258         return -1;
    259     }
    260     pthread_mutex_lock(&g_lock);
    261     err = write_int(BUTTON_FILE, state->color & 0xFF);
    262     pthread_mutex_unlock(&g_lock);
    263     return err;
    264 }
    265 
    266 static int
    267 set_light_bluetooth(struct light_device_t* dev,
    268         struct light_state_t const* state)
    269 {
    270     int err = 0;
    271     if(!dev) {
    272         return -1;
    273     }
    274     pthread_mutex_lock(&g_lock);
    275     err = write_int(BLUETOOTH_LED_FILE, state->color & 0xFF);
    276     pthread_mutex_unlock(&g_lock);
    277     return err;
    278 }
    279 
    280 /** Close the lights device */
    281 static int
    282 close_lights(struct light_device_t *dev)
    283 {
    284     if (dev) {
    285         free(dev);
    286     }
    287     return 0;
    288 }
    289 
    290 
    291 /******************************************************************************/
    292 
    293 /**
    294  * module methods
    295  */
    296 
    297 /** Open a new instance of a lights device using name */
    298 static int open_lights(const struct hw_module_t* module, char const* name,
    299         struct hw_device_t** device)
    300 {
    301     int (*set_light)(struct light_device_t* dev,
    302             struct light_state_t const* state);
    303 
    304     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
    305         set_light = set_light_backlight;
    306     else if (0 == strcmp(LIGHT_ID_BATTERY, name))
    307         set_light = set_light_battery;
    308     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
    309         set_light = set_light_notifications;
    310     else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
    311         set_light = set_light_buttons;
    312     else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
    313         set_light = set_light_attention;
    314     else if (0 == strcmp(LIGHT_ID_BLUETOOTH, name))
    315         set_light = set_light_bluetooth;
    316     else
    317         return -EINVAL;
    318 
    319     pthread_once(&g_init, init_globals);
    320 
    321     struct light_device_t *dev = malloc(sizeof(struct light_device_t));
    322 
    323     if(!dev)
    324         return -ENOMEM;
    325 
    326     memset(dev, 0, sizeof(*dev));
    327 
    328     dev->common.tag = HARDWARE_DEVICE_TAG;
    329     dev->common.version = 0;
    330     dev->common.module = (struct hw_module_t*)module;
    331     dev->common.close = (int (*)(struct hw_device_t*))close_lights;
    332     dev->set_light = set_light;
    333 
    334     *device = (struct hw_device_t*)dev;
    335     return 0;
    336 }
    337 
    338 static struct hw_module_methods_t lights_module_methods = {
    339     .open =  open_lights,
    340 };
    341 
    342 /*
    343  * The lights Module
    344  */
    345 struct hw_module_t HAL_MODULE_INFO_SYM = {
    346     .tag = HARDWARE_MODULE_TAG,
    347     .version_major = 1,
    348     .version_minor = 0,
    349     .id = LIGHTS_HARDWARE_MODULE_ID,
    350     .name = "lights Module",
    351     .author = "Google, Inc.",
    352     .methods = &lights_module_methods,
    353 };
    354