| /* onkey management servicest |
| * (C) Copyright Marvell 2015 |
| * Licensed under the GPLv2 |
| * |
| * This service makes sure the onkeytimer & RTC wakeup code is |
| * functioning. |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <time.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <pthread.h> |
| #include <assert.h> |
| #include <sys/time.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <linux/input.h> |
| #include <errno.h> |
| #include <asm/ioctl.h> |
| |
| #include <libubox/blob.h> |
| #include <libubox/blobmsg.h> |
| #include <libubox/ustream.h> |
| #include <libubus.h> |
| #include <ubusmsg.h> |
| #include <libubox/blobmsg_json.h> |
| #include "onkey.h" |
| #include "aoc.h" |
| |
| #ifdef CONFIG_ONKEY_SERVICE |
| |
| static uint32_t onkey_ril_id; |
| struct blob_buf onkey_ril_buf; |
| struct blob_buf onkey_event_buf; |
| |
| struct ubus_context *onkey_ctx; |
| typedef void (* signal_handler)(int ); |
| static int longpress; |
| #define ONKEY_DEV "/dev/input/event0" |
| static int onkey_thread(void *arg); |
| |
| static int onkey_press_notify(struct ubus_context *ctx, int type) |
| { |
| DEBUG(2, "onkey_press_notify-----\n"); |
| pthread_mutex_lock(&aoc_ubus_mutex); |
| blobmsg_buf_init(&onkey_event_buf); |
| blobmsg_add_u32(&onkey_event_buf, "type", type); |
| ubus_notify(ctx, &aoc_object, "onkey_pressed", onkey_event_buf.head, -1); |
| blob_buf_free(&onkey_event_buf); |
| pthread_mutex_unlock(&aoc_ubus_mutex); |
| return 0; |
| } |
| |
| static void key_timer_handler(void) |
| { |
| FILE *fd; |
| longpress = 1; |
| LOG("longpress large than 3s, poweroff system...\n"); |
| fd = fopen("/sys/power/wake_lock", "w"); |
| fprintf(fd, "onkey"); |
| fclose(fd); |
| poweroff_system(3); |
| } |
| |
| static int onkey_thread(void *arg) |
| { |
| struct input_event data; |
| struct itimerval tick; |
| struct itimerval timeroff = { { 0, 0 }, { 0, 0 } }; |
| int fd = -1; |
| (void)arg; |
| |
| tick.it_value.tv_sec = 3; |
| tick.it_value.tv_usec = 0; |
| tick.it_interval.tv_sec = 0; |
| tick.it_interval.tv_usec = 0; |
| |
| pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
| |
| fd = open(ONKEY_DEV, O_RDONLY); |
| if (fd < 0) { |
| ERROR("open onkey device error!\n"); |
| return -1; |
| } |
| do { |
| int ret = |
| read(fd, &data, sizeof(data)); |
| (void) ret; |
| if (data.type == EV_KEY) |
| { |
| DEBUG(2, "type: %d, event = %d, value = %d\n", data.type, data.code, data.value); |
| if (data.value) |
| { /* key pressed */ |
| DEBUG(2, "pressed.\n"); |
| longpress = 0 ; |
| setitimer(ITIMER_REAL, &tick, NULL); |
| /*TODO: wake up GUI*/ |
| } else |
| { /* key released */ |
| DEBUG(2, "released.\n"); |
| setitimer(ITIMER_REAL, &timeroff, NULL); |
| if (!longpress) |
| { |
| DEBUG(2, "short pressed\n"); |
| /*TODO: short press ubus*/ |
| onkey_press_notify(onkey_ctx, 0); |
| } |
| } |
| } |
| } while(1); |
| |
| close(fd); |
| return 0; |
| } |
| |
| void poweroff_system(int sec) |
| { |
| struct ubus_context *ctx; |
| const char *ubus_socket = NULL; |
| struct ubus_request * req; |
| int ret_val; |
| int power_off=0; |
| DEBUG(2, "----onkey press time %d.\n", sec); |
| req = (struct ubus_request *)malloc(sizeof(struct ubus_request)); |
| |
| rilutil_makeRequestBlob(&onkey_ril_buf, RIL_REQUEST_RADIO_POWER, &power_off, 1); |
| if ((ret_val = |
| ubus_invoke_async(onkey_ctx, onkey_ril_id, "ril_request", onkey_ril_buf.head, req)) != UBUS_STATUS_OK) { |
| DEBUG(2, "exit %s, fail: %s\n", __FUNCTION__, ubus_strerror(ret_val)); |
| free(req); |
| } else { |
| DEBUG(2, "%s: ubus_invoke_async success\n", __FUNCTION__); |
| } |
| |
| ret_val = |
| system("logread > /dev/console"); |
| sync(); |
| DEBUG(2, "Start to Notify Service\n"); |
| ctx = ubus_connect(ubus_socket); |
| blob_buf_init(&onkey_event_buf, 0); |
| blobmsg_add_string(&onkey_event_buf, "poweroff", "1"); |
| ubus_send_event(ctx, "System.OnKey.Event", onkey_event_buf.head); |
| |
| sleep(1); |
| sync(); |
| sleep(1); |
| ret_val = |
| system("poweroff"); |
| } |
| |
| int onkey_method(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg) |
| { |
| struct blob_attr *tb[__ONKEY_MAX]; |
| (void)ctx; |
| (void)obj; |
| (void)req; |
| (void)method; |
| |
| blobmsg_parse(onkey_policy, __ONKEY_MAX, tb, blob_data(msg), blob_len(msg)); |
| if (!tb[ONKEY_CALL]) |
| return UBUS_STATUS_INVALID_ARGUMENT; |
| |
| poweroff_system(blobmsg_get_u32(tb[ONKEY_CALL])); |
| |
| return 0; |
| } |
| |
| static int RilIdReady(struct ubus_context *ctx) |
| { |
| if (!ubus_lookup_id(ctx, RildName, &onkey_ril_id)) |
| return 1; |
| |
| return 0; |
| } |
| |
| int onkey_init(struct ubus_context *ctx) |
| { |
| int retries = 0; |
| int ret = 0; |
| pthread_t onkey; |
| |
| DEBUG(2, "Start ONKEY service,time:%s, date:%s\n",__TIME__,__DATE__); |
| onkey_ctx = ctx; |
| do { |
| if (RilIdReady(ctx)) |
| break; |
| sleep(1); |
| } while (retries++ < RIL_MAX_RETRIES); |
| |
| if (retries >= RIL_MAX_RETRIES) { |
| ERROR("%s: Failed to look up RIL object\n", __func__); |
| return -1; |
| } |
| DEBUG(2, "%s: RIL is ready\n", __func__); |
| |
| signal(SIGALRM, (signal_handler)key_timer_handler); |
| ret = pthread_create(&onkey, NULL, (void *)onkey_thread, NULL); |
| if (ret != 0) { |
| ERROR("onkey pthread create error %d\n", ret); |
| return -1; |
| } |
| |
| return 0; |
| } |
| #endif //#ifdef CONFIG_CHARGER_SERVICE |