| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <sys/un.h> |
| #include <sys/ioctl.h> |
| #include <pthread.h> |
| #ifdef NAME_MAX |
| #undef NAME_MAX |
| #endif |
| #include <sys/socket.h> |
| #include <linux/types.h> |
| #include <linux/netlink.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <arpa/inet.h> |
| #include <netinet/in.h> |
| #include <sys/time.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <linux/input.h> |
| |
| #include <libubox/blob.h> |
| #include <libubox/blobmsg.h> |
| #include <libubox/ustream.h> |
| #include <libubus.h> |
| #include <ubusmsg.h> |
| #include "charger.h" |
| #include "aoc.h" |
| |
| #ifdef CONFIG_CHARGER_SERVICE |
| |
| #define POWEROFF_BAT_LEVEL 1 |
| |
| static const char *bat_health_array[] = { |
| BAT_HEALTH_UNKNOWN, |
| BAT_HEALTH_GOOD, |
| BAT_HEALTH_OVERHEAT, |
| BAT_HEALTH_DEAD, |
| BAT_HEALTH_OVERVOLTAGE, |
| BAT_HEALTH_UNSPEC_FAILURE, |
| BAT_HEALTH_COLD, |
| BAT_HEALTH_WATCHDOG_TIMER_EXPIRE, |
| BAT_HEALTH_SAFETY_TIMER_EXPIRE, |
| }; |
| |
| static const char *bat_tech_array[] = { |
| BAT_TECHNOLOGY_UNKNOWN, |
| BAT_TECHNOLOGY_NiMH, |
| BAT_TECHNOLOGY_LION, |
| BAT_TECHNOLOGY_LIPO, |
| BAT_TECHNOLOGY_LiFe, |
| BAT_TECHNOLOGY_NiCd, |
| BAT_TECHNOLOGY_LiMn, |
| }; |
| |
| static const char *bat_type_array[] = { |
| PSY_TYPE_UNKNOWN, |
| PSY_TYPE_BATTERY, |
| PSY_TYPE_UPS, |
| PSY_TYPE_MAINS, |
| PSY_TYPE_USB, |
| PSY_TYPE_USBDCP, |
| PSY_TYPE_USBCDP, |
| PSY_TYPE_USBACA, |
| }; |
| |
| static const char *chgbat_stat_array[] = { |
| CHGBAT_STATUS_UNKNOWN, |
| CHGBAT_STATUS_CHARGING, |
| CHGBAT_STATUS_DISCHARGING, |
| CHGBAT_STATUS_NOTCHARGING, |
| CHGBAT_STATUS_FULL, |
| }; |
| |
| static int should_exit = 0; |
| static struct chg_bat_stat global_chgbat_info = {0}; |
| static struct chg_bat_tag global_chgbat_array = {0}; |
| |
| static struct ubus_object *charger_object; |
| static struct blob_buf charger_blob_msg_buf; |
| struct ubus_context *charger_ctx; |
| |
| static int read_chgbat_sys_info(void); |
| #ifdef DEBUG_CHARGER |
| static void dump_chg_bat_sysinfo(void); |
| static int read_bat_sys_info(void); |
| static int read_acchg_sys_info(void); |
| static int read_usbchg_sys_info(void); |
| static int read_chg_sys_info(); |
| #endif |
| int read_chg_bat_info(unsigned int file_mask); |
| |
| static void convert_chginfo_to_tag(void) |
| { |
| unsigned int i; |
| |
| global_chgbat_array.capacity = global_chgbat_info.capacity; |
| |
| for(i = 0; i < sizeof(bat_health_array)/sizeof(bat_health_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.health, |
| bat_health_array[i], strlen(bat_health_array[i]))) { |
| global_chgbat_array.health = i; |
| break; |
| } |
| } |
| |
| global_chgbat_array.present= global_chgbat_info.present; |
| for(i = 0; i < sizeof(bat_type_array)/sizeof(bat_type_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.type, |
| bat_type_array[i], strlen(bat_type_array[i]))) { |
| global_chgbat_array.type = i; |
| break; |
| } |
| } |
| global_chgbat_array.voltage_now= global_chgbat_info.voltage_now; |
| for(i = 0; i < sizeof(chgbat_stat_array)/sizeof(chgbat_stat_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.bat_status, |
| chgbat_stat_array[i], strlen(chgbat_stat_array[i]))) { |
| global_chgbat_array.bat_status = i; |
| break; |
| } |
| } |
| global_chgbat_array.bat_temp= global_chgbat_info.bat_temp; |
| for(i = 0; i < sizeof(bat_tech_array)/sizeof(bat_tech_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.bat_technology, |
| bat_tech_array[i], strlen(bat_tech_array[i]))) { |
| global_chgbat_array.bat_technology = i; |
| break; |
| } |
| } |
| |
| global_chgbat_array.acchg_online= global_chgbat_info.acchg_online; |
| for(i = 0; i < sizeof(bat_type_array)/sizeof(bat_type_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.acchg_type, |
| bat_type_array[i], strlen(bat_type_array[i]))) { |
| global_chgbat_array.acchg_type = i; |
| break; |
| } |
| } |
| for(i = 0; i < sizeof(chgbat_stat_array)/sizeof(chgbat_stat_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.acchg_status, |
| chgbat_stat_array[i], strlen(chgbat_stat_array[i]))) { |
| global_chgbat_array.acchg_status = i; |
| break; |
| } |
| } |
| |
| global_chgbat_array.usbchg_online= global_chgbat_info.usbchg_online; |
| for(i = 0; i < sizeof(bat_type_array)/sizeof(bat_type_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.usbchg_type, |
| bat_type_array[i], strlen(bat_type_array[i]))) { |
| global_chgbat_array.usbchg_type= i; |
| break; |
| } |
| } |
| for(i = 0; i < sizeof(chgbat_stat_array)/sizeof(chgbat_stat_array[0]); i++) { |
| if(!strncmp((const char *)global_chgbat_info.usbchg_status, |
| chgbat_stat_array[i], strlen(chgbat_stat_array[i]))) { |
| global_chgbat_array.usbchg_status= i; |
| break; |
| } |
| } |
| } |
| |
| static void prepare_chgbat_info(int sysfs_ok) |
| { |
| if(!sysfs_ok) |
| ERROR("%s: sysfs_ok = 0\n", __func__); |
| |
| convert_chginfo_to_tag(); |
| |
| blob_buf_init(&charger_blob_msg_buf, 0); |
| blobmsg_add_u32(&charger_blob_msg_buf, "capacity", global_chgbat_array.capacity); |
| blobmsg_add_u32(&charger_blob_msg_buf, "health", global_chgbat_array.health); |
| blobmsg_add_u32(&charger_blob_msg_buf, "present", global_chgbat_array.present); |
| blobmsg_add_u32(&charger_blob_msg_buf, "type", global_chgbat_array.type); |
| blobmsg_add_u32(&charger_blob_msg_buf, "voltage_now", global_chgbat_array.voltage_now); |
| blobmsg_add_u32(&charger_blob_msg_buf, "bat_status", global_chgbat_array.bat_status); |
| blobmsg_add_u32(&charger_blob_msg_buf, "bat_temp", global_chgbat_array.bat_temp); |
| blobmsg_add_u32(&charger_blob_msg_buf, "bat_technology", global_chgbat_array.bat_technology); |
| |
| blobmsg_add_u32(&charger_blob_msg_buf, "acchg_online", global_chgbat_array.acchg_online); |
| blobmsg_add_u32(&charger_blob_msg_buf, "acchg_type", global_chgbat_array.acchg_type); |
| blobmsg_add_u32(&charger_blob_msg_buf, "acchg_status", global_chgbat_array.acchg_status); |
| |
| blobmsg_add_u32(&charger_blob_msg_buf, "usbchg_online", global_chgbat_array.usbchg_online); |
| blobmsg_add_u32(&charger_blob_msg_buf, "usbchg_type", global_chgbat_array.usbchg_type); |
| blobmsg_add_u32(&charger_blob_msg_buf, "usbchg_status", global_chgbat_array.usbchg_status); |
| } |
| |
| #ifdef DEBUG_CHARGER |
| static void dump_chg_bat_info(void) |
| { |
| DEBUG(1, "\nBattery capacity: %d/100\n",global_chgbat_info.capacity); |
| DEBUG(1, " Battery type: %s\n",global_chgbat_info.type); |
| DEBUG(1, " Battery present: %d\n",global_chgbat_info.present); |
| DEBUG(1, " Battery health: %s\n",global_chgbat_info.health); |
| DEBUG(1, " Battery voltage: %d\n",global_chgbat_info.voltage_now); |
| DEBUG(1, " Battery temp: %d\n",global_chgbat_info.bat_temp); |
| DEBUG(1, " Battery status: %s\n",global_chgbat_info.bat_status); |
| DEBUG(1, " Battery tech: %s\n",global_chgbat_info.bat_technology); |
| DEBUG(1, " Acchg online: %d\n",global_chgbat_info.acchg_online); |
| DEBUG(1, " Acchg type: %s\n",global_chgbat_info.acchg_type); |
| DEBUG(1, " Acchg status: %s\n",global_chgbat_info.acchg_status); |
| DEBUG(1, " USBchg online: %d\n",global_chgbat_info.usbchg_online); |
| DEBUG(1, " USBchg type: %s\n",global_chgbat_info.usbchg_type); |
| DEBUG(1, " USBchg status: %s\n",global_chgbat_info.usbchg_status); |
| } |
| #endif |
| |
| int send_chg_msg(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg) |
| { |
| (void)obj; |
| (void)method; |
| (void)msg; |
| |
| DEBUG(2, "[%s]\n", __FUNCTION__); |
| |
| pthread_mutex_lock(&aoc_ubus_mutex); |
| ubus_send_reply(ctx, req, charger_blob_msg_buf.head); |
| pthread_mutex_unlock(&aoc_ubus_mutex); |
| |
| DEBUG(2, "[%s] ubus_send_reply OK\n", __FUNCTION__); |
| |
| return UBUS_STATUS_OK; |
| } |
| |
| extern void poweroff_system(void); |
| static void handle_lowbat_poweroff(void) |
| { |
| if(global_chgbat_array.capacity <= POWEROFF_BAT_LEVEL |
| && global_chgbat_array.bat_status != STATUS_CHARGING) { |
| LOG("%s: power off, battery too low\n", __FUNCTION__); |
| poweroff_system(); |
| } |
| } |
| |
| static void handle_tbat_poweroff(void) |
| { |
| if(global_chgbat_array.health == HEALTH_DEAD) { |
| LOG("%s: power off, BAT Temperature Abnormal\n", __FUNCTION__); |
| poweroff_system(); |
| } |
| } |
| |
| static int notify_chg_msg(int event_type) |
| { |
| int ret = 0; |
| char ev_type[16] = "\0"; |
| |
| if(event_type == BAT_EVENT) |
| strcpy(ev_type, "bat_event"); |
| else if(event_type == ACCHG_EVENT) |
| strcpy(ev_type, "acchg_event"); |
| else if(event_type == USBCHG_EVENT) |
| strcpy(ev_type, "usbchg_event"); |
| |
| ret = read_chgbat_sys_info(); |
| if(ret) { |
| ERROR("%s: read chgbat info error\n", __FUNCTION__); |
| /* return -UBUS_STATUS_NO_DATA; */ |
| } |
| if(ret) |
| prepare_chgbat_info(0); |
| else |
| prepare_chgbat_info(1); |
| |
| handle_tbat_poweroff(); |
| handle_lowbat_poweroff(); |
| |
| pthread_mutex_lock(&aoc_ubus_mutex); |
| ret = ubus_notify(charger_ctx, charger_object, "chginfo", |
| charger_blob_msg_buf.head, -1); |
| pthread_mutex_unlock(&aoc_ubus_mutex); |
| if (ret) |
| ERROR("%s: ubus notify error: ret=%d\n", __FUNCTION__, ret); |
| |
| return ret; |
| } |
| |
| |
| static int |
| file_check_and_open(struct chg_file_desc * file_desc, |
| struct chg_bat_stat * chg_bat_status) |
| { |
| int ret = 0; |
| |
| if(!file_desc || !chg_bat_status) { |
| ERROR("%s: %d: file_desc or chg_bat_status NULL\n", __func__, __LINE__); |
| ret = -EINVAL; |
| goto out_err; |
| } |
| |
| if(!file_desc->file_name && (file_desc->fd == -1)) { |
| ERROR("%s: %d: file name NULL\n", __func__, __LINE__); |
| ret = -EINVAL; |
| goto out_err; |
| } |
| |
| file_desc->fd = open(file_desc->file_name, O_RDONLY); |
| if(file_desc->fd < 0) { |
| ERROR("[%s] file-%s open error\n", __FUNCTION__, file_desc->file_name); |
| ret = -ENOENT; |
| goto out_err; |
| } |
| return 0; |
| |
| out_err: |
| return ret; |
| } |
| |
| static void close_chg_file(struct chg_file_desc * file_desc) |
| { |
| close(file_desc->fd); |
| file_desc->fd = -1; |
| } |
| |
| static int |
| read_bat_files(struct chg_file_desc * file_desc, |
| struct chg_bat_stat * chg_bat_status, int attrib_idx) |
| { |
| int ret = 0; |
| unsigned char str[CHGBAT_STR_NAME_LEN]; |
| unsigned char *str_temp = NULL; |
| int * p_value = 0x0; |
| |
| ret = file_check_and_open(file_desc, chg_bat_status); |
| if(ret) { |
| ERROR("%s: %d: file check and open error\n", __func__, __LINE__); |
| goto out_err; |
| } |
| |
| switch(attrib_idx) |
| { |
| case BAT_CAPACITY_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->capacity); |
| break; |
| |
| case BAT_HEALTH_FILE_IDX: |
| str_temp = chg_bat_status->health; |
| break; |
| |
| case BAT_PRESENT_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->present); |
| break; |
| |
| case BAT_TEMP_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->bat_temp); |
| break; |
| |
| case BAT_STATUS_FILE_IDX: |
| str_temp = chg_bat_status->bat_status; |
| break; |
| |
| case BAT_TECH_FILE_IDX: |
| str_temp = chg_bat_status->bat_technology; |
| break; |
| |
| case BAT_TYPE_FILE_IDX: |
| str_temp = chg_bat_status->type; |
| break; |
| |
| case BAT_VOLT_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->voltage_now); |
| break; |
| |
| case ACCHG_ONLINE_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->acchg_online); |
| break; |
| |
| case ACCHG_TYPE_FILE_IDX: |
| str_temp = chg_bat_status->acchg_type; |
| break; |
| |
| case ACCHG_STATUS_FILE_IDX: |
| str_temp = chg_bat_status->acchg_status; |
| break; |
| |
| case USBCHG_ONLINE_FILE_IDX: |
| str_temp = str; |
| p_value = (int *)&(chg_bat_status->usbchg_online); |
| break; |
| |
| case USBCHG_TYPE_FILE_IDX: |
| str_temp = chg_bat_status->usbchg_type; |
| break; |
| |
| case USBCHG_STATUS_FILE_IDX: |
| str_temp = chg_bat_status->usbchg_status; |
| break; |
| |
| default: |
| ERROR("[%s]: attribute_idx %d error\n", __func__, attrib_idx); |
| return -1; |
| } |
| |
| ret = read(file_desc->fd, str_temp, CHGBAT_STR_NAME_LEN); |
| if(ret < 0) { |
| ERROR("[%s] file read error\n", __FUNCTION__); |
| close_chg_file(file_desc); |
| goto out_err; |
| } |
| |
| if(p_value) |
| *p_value = atoi((const char *)str_temp); |
| |
| close_chg_file(file_desc); |
| return 0; |
| |
| out_err: |
| return ret; |
| } |
| |
| static struct chg_file_desc chg_files[] = { |
| [BAT_CAPACITY_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_CAPACITY_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_HEALTH_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_HEALTH_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_PRESENT_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_PRESENT_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_TEMP_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_TEMP_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_STATUS_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_STATUS_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_TECH_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_TECH_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_TYPE_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_TYPE_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [BAT_VOLT_FILE_IDX] = { |
| .fd = -1, |
| .file_name = BAT_VOLT_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [ACCHG_ONLINE_FILE_IDX] = { |
| .fd = -1, |
| .file_name = ACCHG_ONLINE_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [ACCHG_TYPE_FILE_IDX] = { |
| .fd = -1, |
| .file_name = ACCHG_TYPE_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [ACCHG_STATUS_FILE_IDX] = { |
| .fd = -1, |
| .file_name = ACCHG_STATUS_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [USBCHG_ONLINE_FILE_IDX] = { |
| .fd = -1, |
| .file_name = USBCHG_ONLINE_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [USBCHG_TYPE_FILE_IDX] = { |
| .fd = -1, |
| .file_name = USBCHG_TYPE_FILE, |
| .read_file = &read_bat_files, |
| }, |
| [USBCHG_STATUS_FILE_IDX] = { |
| .fd = -1, |
| .file_name = USBCHG_STATUS_FILE, |
| .read_file = &read_bat_files, |
| }, |
| }; |
| |
| int read_chg_bat_info(unsigned int file_mask) |
| { |
| int i, ret = 0; |
| |
| for(i = 0; i < NR_CHG_USB_FILE_IDX; i++) |
| { |
| if((0x1 << i) & file_mask) { |
| ret |= chg_files[i].read_file(&chg_files[i], &global_chgbat_info, i); |
| if(ret) |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int read_chgbat_sys_info(void) |
| { |
| int ret; |
| ret = read_chg_bat_info(ALL_CHG_BAT_FILES); |
| return ret; |
| } |
| |
| #ifdef DEBUG_CHARGER |
| static int read_bat_sys_info(void) |
| { |
| int ret; |
| ret = read_chg_bat_info(ALL_BAT_FILES); |
| return ret; |
| } |
| |
| static int read_acchg_sys_info(void) |
| { |
| int ret; |
| ret = read_chg_bat_info(ALL_AC_CHG_FILES); |
| return ret; |
| } |
| |
| static int read_usbchg_sys_info(void) |
| { |
| int ret; |
| ret = read_chg_bat_info(ALL_USB_CHG_FILES); |
| return ret; |
| } |
| |
| static int read_chg_sys_info(void) |
| { |
| int ret; |
| ret = read_chg_bat_info(ALL_USB_CHG_FILES|ALL_AC_CHG_FILES); |
| return ret; |
| } |
| #endif |
| |
| #ifdef DEBUG_CHARGER |
| static void dump_chg_bat_sysinfo(void) |
| { |
| int ret; |
| ret = read_chgbat_sys_info(); |
| if(ret) { |
| ERROR("[%s] read chg bat info error\n", __FUNCTION__); |
| return; |
| } |
| |
| dump_chg_bat_info(); |
| } |
| #endif |
| |
| static int handle_battery_event(void) |
| { |
| notify_chg_msg(BAT_EVENT); |
| return 0; |
| } |
| |
| static int handle_acchg_event(void) |
| { |
| notify_chg_msg(ACCHG_EVENT); |
| return 0; |
| } |
| |
| static int handle_usbchg_event(void) |
| { |
| notify_chg_msg(USBCHG_EVENT); |
| return 0; |
| } |
| |
| static int get_chgevent_to_deliver(int uevent_sock) |
| { |
| char uevent_buf[UEVENT_BUFFER_SIZE * 2] = {0}; |
| |
| while(!should_exit) |
| { |
| memset(uevent_buf, 0x0, sizeof(uevent_buf)); |
| recv(uevent_sock, &uevent_buf, sizeof(uevent_buf), 0); |
| uevent_buf[sizeof(uevent_buf) - 1] = 0x0; |
| if(strstr(uevent_buf,"power_supply/bat")) |
| { |
| DEBUG(2, "recevied battery event\n"); |
| handle_battery_event(); |
| } |
| else if (strstr(uevent_buf,"power_supply/ac")) |
| { |
| DEBUG(2, "recevied ac charger event\n"); |
| handle_acchg_event(); |
| } |
| else if(strstr(uevent_buf,"power_supply/usb")) |
| { |
| DEBUG(2, "recevied usb charger event\n"); |
| handle_usbchg_event(); |
| } |
| } |
| |
| close(uevent_sock); |
| return 0; |
| } |
| |
| static int init_uevent_sock(void) |
| { |
| const int buffersize = UEVENT_BUFFER_SIZE; |
| int ret, sock_fd; |
| struct sockaddr_nl snl; |
| |
| bzero(&snl, sizeof(struct sockaddr_nl)); |
| snl.nl_family = AF_NETLINK; |
| snl.nl_pid = getpid(); |
| snl.nl_groups = 1; |
| |
| sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); |
| if (sock_fd < 0) |
| { |
| ERROR("[%s] socket error\n", __FUNCTION__); |
| return -1; |
| } |
| |
| setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize)); |
| |
| ret = bind(sock_fd, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)); |
| if (ret < 0) |
| { |
| ERROR("%s: bind error\n", __FUNCTION__); |
| close(sock_fd); |
| return -1; |
| } |
| |
| return sock_fd; |
| } |
| |
| static void chgevent_mon_thread_handler(void *arg) |
| { |
| int sock_fd; |
| (void)arg; |
| |
| sock_fd = init_uevent_sock(); |
| if(sock_fd == -1) |
| goto out_err; |
| |
| get_chgevent_to_deliver(sock_fd); |
| return; |
| |
| out_err: |
| close(sock_fd); |
| return; |
| } |
| |
| static pthread_t create_chgevent_mon_thread(void * arg) |
| { |
| int ret; |
| pthread_t chgevent_mon_thread; |
| |
| DEBUG(2, "%s\n",__func__); |
| ret = pthread_create(&chgevent_mon_thread, NULL, |
| (void *)chgevent_mon_thread_handler, arg); |
| if(ret) { |
| ERROR("[%s] pthread_create error\n", __FUNCTION__); |
| return (pthread_t)0; |
| } |
| |
| return chgevent_mon_thread; |
| } |
| |
| static void sigkill_func(int sig) |
| { |
| DEBUG(2, "received sig: %d\n",sig); |
| should_exit = 1; |
| if(sig == SIGSEGV) { |
| exit(1); |
| } |
| } |
| |
| int charger_init(struct ubus_context *ctx, struct ubus_object *obj) |
| { |
| int ret; |
| pthread_t chgevent_mon_thread; |
| |
| DEBUG(2, "dump charger battery info\n"); |
| |
| /* check if the charger driver is there */ |
| ret = read_chgbat_sys_info(); |
| if(ret) { |
| ERROR("kernel charger driver not loaded\n"); |
| prepare_chgbat_info(0); |
| } else { |
| DEBUG(2, "Kernel charger driver loaded\n"); |
| prepare_chgbat_info(1); |
| } |
| charger_ctx = ctx; |
| charger_object = obj; |
| |
| chgevent_mon_thread = create_chgevent_mon_thread(NULL); |
| if (!chgevent_mon_thread) { |
| DEBUG(2, "create chgevent monitor thread\n"); |
| return -1; |
| } |
| |
| DEBUG(2, "charger service running up ...\n"); |
| signal(SIGTERM, sigkill_func); |
| signal(SIGKILL, sigkill_func); |
| signal(SIGSEGV, sigkill_func); |
| |
| return 0; |
| } |
| #endif //#ifdef CONFIG_CHARGER_SERVICE |
| |