blob: a1e743e2e102f3cf00e95ea5245f5c28612ab2a3 [file] [log] [blame]
/* 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