2010-05-15 22:26:29 -07:00
|
|
|
#include "e.h"
|
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
/* TODO:
|
|
|
|
*
|
|
|
|
* Sanatize data received from acpi for message status into something
|
|
|
|
* meaningful (ie: 00000002 == LID_CLOSED, etc, etc).
|
|
|
|
*
|
|
|
|
* Find someone with a WIFI that actually emits ACPI events and add/debug the
|
|
|
|
* E_EVENT_ACPI for wifi.
|
|
|
|
*
|
|
|
|
* Add e_actions for bindings.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* local structures */
|
|
|
|
typedef struct _ACPIDevice ACPIDevice; // for mapping device names to type
|
|
|
|
struct _ACPIDevice
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
int type;
|
|
|
|
};
|
|
|
|
|
2010-05-15 22:26:29 -07:00
|
|
|
/* local function prototypes */
|
|
|
|
static int _e_acpi_cb_server_del(void *data __UNUSED__, int type __UNUSED__, void *event);
|
|
|
|
static int _e_acpi_cb_server_data(void *data __UNUSED__, int type __UNUSED__, void *event);
|
|
|
|
static void _e_acpi_cb_event_free(void *data __UNUSED__, void *event);
|
2010-05-17 15:46:28 -07:00
|
|
|
static int _e_acpi_lid_status_get(const char *device, const char *bus);
|
2010-05-29 12:57:13 -07:00
|
|
|
static int _e_acpi_cb_event(void *data __UNUSED__, int type __UNUSED__, void *event);
|
2010-05-15 22:26:29 -07:00
|
|
|
|
|
|
|
/* local variables */
|
2010-06-03 09:57:09 -07:00
|
|
|
static int _e_acpi_events_frozen = 0;
|
2010-05-15 22:26:29 -07:00
|
|
|
static Ecore_Con_Server *_e_acpid = NULL;
|
|
|
|
static Eina_List *_e_acpid_hdls = NULL;
|
2010-05-16 17:03:55 -07:00
|
|
|
static Eina_Hash *_e_acpid_devices = NULL;
|
|
|
|
static ACPIDevice _devices[] =
|
|
|
|
{
|
|
|
|
/* DO NOT TRANSLATE THESE. */
|
|
|
|
/* standardized ACPI device name, corresponding E_ACPI_TYPE */
|
|
|
|
{"ac_adapter", E_ACPI_TYPE_AC_ADAPTER},
|
|
|
|
{"battery", E_ACPI_TYPE_BATTERY},
|
|
|
|
{"button/lid", E_ACPI_TYPE_LID},
|
|
|
|
{"button/power", E_ACPI_TYPE_POWER},
|
|
|
|
{"button/sleep", E_ACPI_TYPE_SLEEP},
|
|
|
|
{"fan", E_ACPI_TYPE_FAN},
|
|
|
|
{"processor", E_ACPI_TYPE_PROCESSOR},
|
|
|
|
{"thermal_zone", E_ACPI_TYPE_THERMAL},
|
|
|
|
{"video", E_ACPI_TYPE_VIDEO},
|
|
|
|
{NULL, E_ACPI_TYPE_UNKNOWN}
|
|
|
|
};
|
2010-05-15 22:26:29 -07:00
|
|
|
|
|
|
|
/* public variables */
|
2010-05-16 17:03:55 -07:00
|
|
|
EAPI int E_EVENT_ACPI_UNKNOWN = 0;
|
|
|
|
EAPI int E_EVENT_ACPI_AC_ADAPTER = 0;
|
2010-05-15 22:26:29 -07:00
|
|
|
EAPI int E_EVENT_ACPI_BATTERY = 0;
|
2010-05-16 17:03:55 -07:00
|
|
|
EAPI int E_EVENT_ACPI_FAN = 0;
|
|
|
|
EAPI int E_EVENT_ACPI_LID = 0;
|
|
|
|
EAPI int E_EVENT_ACPI_POWER = 0;
|
|
|
|
EAPI int E_EVENT_ACPI_PROCESSOR = 0;
|
2010-05-15 22:26:29 -07:00
|
|
|
EAPI int E_EVENT_ACPI_SLEEP = 0;
|
2010-05-16 17:03:55 -07:00
|
|
|
EAPI int E_EVENT_ACPI_THERMAL = 0;
|
|
|
|
EAPI int E_EVENT_ACPI_VIDEO = 0;
|
2010-05-15 22:26:29 -07:00
|
|
|
EAPI int E_EVENT_ACPI_WIFI = 0;
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
EAPI int
|
|
|
|
e_acpi_init(void)
|
|
|
|
{
|
2010-05-16 17:03:55 -07:00
|
|
|
const ACPIDevice *dev;
|
|
|
|
|
|
|
|
E_EVENT_ACPI_UNKNOWN = ecore_event_type_new();
|
|
|
|
E_EVENT_ACPI_AC_ADAPTER = ecore_event_type_new();
|
2010-05-15 22:26:29 -07:00
|
|
|
E_EVENT_ACPI_BATTERY = ecore_event_type_new();
|
2010-05-16 17:03:55 -07:00
|
|
|
E_EVENT_ACPI_FAN = ecore_event_type_new();
|
|
|
|
E_EVENT_ACPI_LID = ecore_event_type_new();
|
|
|
|
E_EVENT_ACPI_POWER = ecore_event_type_new();
|
|
|
|
E_EVENT_ACPI_PROCESSOR = ecore_event_type_new();
|
2010-05-15 22:26:29 -07:00
|
|
|
E_EVENT_ACPI_SLEEP = ecore_event_type_new();
|
2010-05-16 17:03:55 -07:00
|
|
|
E_EVENT_ACPI_THERMAL = ecore_event_type_new();
|
|
|
|
E_EVENT_ACPI_VIDEO = ecore_event_type_new();
|
2010-05-15 22:26:29 -07:00
|
|
|
E_EVENT_ACPI_WIFI = ecore_event_type_new();
|
|
|
|
|
|
|
|
/* check for running acpid */
|
|
|
|
if (!ecore_file_exists("/var/run/acpid.socket")) return 1;
|
|
|
|
|
|
|
|
/* try to connect to acpid socket */
|
|
|
|
_e_acpid = ecore_con_server_connect(ECORE_CON_LOCAL_SYSTEM,
|
|
|
|
"/var/run/acpid.socket", -1, NULL);
|
|
|
|
if (!_e_acpid) return 1;
|
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
/* create new device hash and fill it */
|
|
|
|
_e_acpid_devices = eina_hash_string_superfast_new(NULL);
|
|
|
|
for (dev = _devices; dev->type > E_ACPI_TYPE_UNKNOWN; dev++)
|
|
|
|
eina_hash_direct_add(_e_acpid_devices, dev->name, dev);
|
|
|
|
|
2010-05-15 22:26:29 -07:00
|
|
|
/* setup handlers */
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL,
|
|
|
|
_e_acpi_cb_server_del, NULL));
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
|
|
|
|
_e_acpi_cb_server_data, NULL));
|
2010-05-29 12:57:13 -07:00
|
|
|
|
|
|
|
/* Add handlers for standard acpi events */
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(E_EVENT_ACPI_AC_ADAPTER,
|
|
|
|
_e_acpi_cb_event, NULL));
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(E_EVENT_ACPI_LID,
|
|
|
|
_e_acpi_cb_event, NULL));
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(E_EVENT_ACPI_POWER,
|
|
|
|
_e_acpi_cb_event, NULL));
|
|
|
|
_e_acpid_hdls =
|
|
|
|
eina_list_append(_e_acpid_hdls,
|
|
|
|
ecore_event_handler_add(E_EVENT_ACPI_SLEEP,
|
|
|
|
_e_acpi_cb_event, NULL));
|
2010-05-15 22:26:29 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
e_acpi_shutdown(void)
|
|
|
|
{
|
|
|
|
Ecore_Event_Handler *hdl;
|
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
/* destroy the device hash */
|
|
|
|
if (_e_acpid_devices) eina_hash_free(_e_acpid_devices);
|
|
|
|
_e_acpid_devices = NULL;
|
|
|
|
|
2010-05-15 22:26:29 -07:00
|
|
|
/* cleanup event handlers */
|
|
|
|
EINA_LIST_FREE(_e_acpid_hdls, hdl)
|
|
|
|
ecore_event_handler_del(hdl);
|
|
|
|
|
|
|
|
/* kill the server if existing */
|
|
|
|
if (_e_acpid) ecore_con_server_del(_e_acpid);
|
|
|
|
_e_acpid = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-06-03 09:57:09 -07:00
|
|
|
EAPI void
|
|
|
|
e_acpi_events_freeze(void)
|
|
|
|
{
|
|
|
|
_e_acpi_events_frozen++;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
e_acpi_events_thaw(void)
|
|
|
|
{
|
|
|
|
_e_acpi_events_frozen--;
|
2010-06-03 10:35:41 -07:00
|
|
|
if (_e_acpi_events_frozen < 0) _e_acpi_events_frozen = 0;
|
2010-06-03 09:57:09 -07:00
|
|
|
}
|
|
|
|
|
2010-05-15 22:26:29 -07:00
|
|
|
/* local functions */
|
|
|
|
static int
|
|
|
|
_e_acpi_cb_server_del(void *data __UNUSED__, int type __UNUSED__, void *event)
|
|
|
|
{
|
|
|
|
Ecore_Con_Event_Server_Del *ev;
|
|
|
|
Ecore_Event_Handler *hdl;
|
|
|
|
|
|
|
|
ev = event;
|
|
|
|
if (ev->server != _e_acpid) return 1;
|
|
|
|
|
|
|
|
/* cleanup event handlers */
|
|
|
|
EINA_LIST_FREE(_e_acpid_hdls, hdl)
|
|
|
|
ecore_event_handler_del(hdl);
|
|
|
|
|
|
|
|
/* kill the server if existing */
|
|
|
|
if (_e_acpid) ecore_con_server_del(_e_acpid);
|
|
|
|
_e_acpid = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_e_acpi_cb_server_data(void *data __UNUSED__, int type __UNUSED__, void *event)
|
|
|
|
{
|
|
|
|
Ecore_Con_Event_Server_Data *ev;
|
2010-05-16 17:03:55 -07:00
|
|
|
ACPIDevice *dev;
|
|
|
|
E_Event_Acpi *acpi_event;
|
|
|
|
int res, sig, status, event_type;
|
|
|
|
char device[1024], bus[1024];
|
2010-05-15 22:26:29 -07:00
|
|
|
|
|
|
|
ev = event;
|
|
|
|
|
2010-05-25 19:29:48 -07:00
|
|
|
/* write out actual acpi received data to stdout for debugging
|
2010-05-17 15:46:28 -07:00
|
|
|
res = fwrite(ev->data, ev->size, 1, stdout);
|
2010-05-25 19:29:48 -07:00
|
|
|
*/
|
2010-05-17 15:46:28 -07:00
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
/* parse out this acpi string into separate pieces */
|
2010-05-25 19:29:48 -07:00
|
|
|
if (sscanf(ev->data, "%s %s %d %d", device, bus, &sig, &status) != 4)
|
2010-05-16 17:03:55 -07:00
|
|
|
return 1;
|
2010-05-15 22:26:29 -07:00
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
/* create new event structure to raise */
|
2010-05-15 22:26:29 -07:00
|
|
|
acpi_event = E_NEW(E_Event_Acpi, 1);
|
2010-05-16 17:03:55 -07:00
|
|
|
acpi_event->bus_id = eina_stringshare_add(bus);
|
|
|
|
acpi_event->signal = sig;
|
|
|
|
acpi_event->status = status;
|
|
|
|
|
|
|
|
/* determine which device this event is for */
|
|
|
|
if ((dev = eina_hash_find(_e_acpid_devices, device)))
|
|
|
|
{
|
|
|
|
acpi_event->device = eina_stringshare_add(dev->name);
|
|
|
|
acpi_event->type = dev->type;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-16 17:11:55 -07:00
|
|
|
acpi_event->device = eina_stringshare_add(device);
|
2010-05-16 17:03:55 -07:00
|
|
|
acpi_event->type = E_ACPI_TYPE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* based on device type, determine the event to raise */
|
|
|
|
switch (acpi_event->type)
|
|
|
|
{
|
|
|
|
case E_ACPI_TYPE_AC_ADAPTER:
|
|
|
|
event_type = E_EVENT_ACPI_AC_ADAPTER;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_BATTERY:
|
|
|
|
event_type = E_EVENT_ACPI_BATTERY;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_FAN:
|
|
|
|
event_type = E_EVENT_ACPI_FAN;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_LID:
|
|
|
|
event_type = E_EVENT_ACPI_LID;
|
2010-05-17 15:46:28 -07:00
|
|
|
acpi_event->status =
|
|
|
|
_e_acpi_lid_status_get(acpi_event->device, acpi_event->bus_id);
|
2010-05-16 17:03:55 -07:00
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_POWER:
|
|
|
|
event_type = E_EVENT_ACPI_POWER;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_PROCESSOR:
|
|
|
|
event_type = E_EVENT_ACPI_PROCESSOR;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_SLEEP:
|
|
|
|
event_type = E_EVENT_ACPI_SLEEP;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_THERMAL:
|
|
|
|
event_type = E_EVENT_ACPI_THERMAL;
|
|
|
|
break;
|
|
|
|
case E_ACPI_TYPE_VIDEO:
|
|
|
|
event_type = E_EVENT_ACPI_VIDEO;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
event_type = E_EVENT_ACPI_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actually raise the event */
|
|
|
|
ecore_event_add(event_type, acpi_event, _e_acpi_cb_event_free, NULL);
|
2010-05-15 22:26:29 -07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_e_acpi_cb_event_free(void *data __UNUSED__, void *event)
|
|
|
|
{
|
2010-05-15 23:21:48 -07:00
|
|
|
E_Event_Acpi *ev;
|
|
|
|
|
2010-05-16 17:03:55 -07:00
|
|
|
if (!(ev = event)) return;
|
2010-05-15 23:21:48 -07:00
|
|
|
if (ev->device) eina_stringshare_del(ev->device);
|
|
|
|
if (ev->bus_id) eina_stringshare_del(ev->bus_id);
|
|
|
|
E_FREE(ev);
|
2010-05-15 22:26:29 -07:00
|
|
|
}
|
2010-05-17 15:46:28 -07:00
|
|
|
|
|
|
|
static int
|
|
|
|
_e_acpi_lid_status_get(const char *device, const char *bus)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int i = 0;
|
|
|
|
char buff[PATH_MAX], *ret;
|
|
|
|
|
|
|
|
/* the acpi driver code in the kernel has a nice acpi function to return
|
|
|
|
* the lid status easily, but that function is not exposed for user_space
|
|
|
|
* so we need to check the proc fs to get the actual status */
|
|
|
|
|
|
|
|
/* make sure we have a device and bus */
|
|
|
|
if ((!device) || (!bus)) return E_ACPI_LID_UNKNOWN;
|
|
|
|
|
|
|
|
/* open the state file from /proc */
|
|
|
|
snprintf(buff, sizeof(buff), "/proc/acpi/%s/%s/state", device, bus);
|
|
|
|
if (!(f = fopen(buff, "r"))) return E_ACPI_LID_UNKNOWN;
|
|
|
|
|
|
|
|
/* read the line from state file */
|
|
|
|
buff[0] = '\0';
|
|
|
|
ret = fgets(buff, 1024, f);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
/* parse out state file */
|
|
|
|
i = 0;
|
|
|
|
while (buff[i] != ':') i++;
|
|
|
|
while (!isalnum(buff[i])) i++;
|
|
|
|
|
|
|
|
/* compare value from state file and return something sane */
|
|
|
|
if (!strcmp(buff, "open"))
|
|
|
|
return E_ACPI_LID_OPEN;
|
|
|
|
else if (!strcmp(buff, "closed"))
|
|
|
|
return E_ACPI_LID_CLOSED;
|
|
|
|
else
|
|
|
|
return E_ACPI_LID_UNKNOWN;
|
|
|
|
}
|
2010-05-29 12:57:13 -07:00
|
|
|
|
|
|
|
static int
|
|
|
|
_e_acpi_cb_event(void *data __UNUSED__, int type __UNUSED__, void *event)
|
|
|
|
{
|
|
|
|
E_Event_Acpi *ev;
|
|
|
|
|
|
|
|
ev = event;
|
2010-06-03 09:57:09 -07:00
|
|
|
if (_e_acpi_events_frozen > 0) return 1;
|
2010-05-29 12:57:13 -07:00
|
|
|
e_bindings_acpi_event_handle(E_BINDING_CONTEXT_NONE, NULL, ev);
|
|
|
|
return 1;
|
|
|
|
}
|