sna_acpi.c revision 46edf8f1
142542f5fSchristos/* 242542f5fSchristos * Copyright (c) 2013 Intel Corporation 342542f5fSchristos * 442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a 542542f5fSchristos * copy of this software and associated documentation files (the "Software"), 642542f5fSchristos * to deal in the Software without restriction, including without limitation 742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense, 842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the 942542f5fSchristos * Software is furnished to do so, subject to the following conditions: 1042542f5fSchristos * 1142542f5fSchristos * The above copyright notice and this permission notice (including the next 1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the 1342542f5fSchristos * Software. 1442542f5fSchristos * 1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2142542f5fSchristos * SOFTWARE. 2242542f5fSchristos * 2342542f5fSchristos * Authors: 2442542f5fSchristos * Chris Wilson <chris@chris-wilson.co.uk> 2542542f5fSchristos * 2642542f5fSchristos */ 2742542f5fSchristos 2842542f5fSchristos#ifdef HAVE_CONFIG_H 2942542f5fSchristos#include "config.h" 3042542f5fSchristos#endif 3142542f5fSchristos 3242542f5fSchristos#include <sys/types.h> 3342542f5fSchristos#include <sys/socket.h> 3442542f5fSchristos#include <sys/un.h> 3542542f5fSchristos#include <unistd.h> 3642542f5fSchristos#include <dirent.h> 3742542f5fSchristos#include <fcntl.h> 3842542f5fSchristos#include <errno.h> 3942542f5fSchristos 4042542f5fSchristos#include "sna.h" 4142542f5fSchristos 4242542f5fSchristos#define ACPI_SOCKET "/var/run/acpid.socket" 4342542f5fSchristos 4442542f5fSchristosint sna_acpi_open(void) 4542542f5fSchristos{ 4642542f5fSchristos struct sockaddr_un addr; 4742542f5fSchristos int fd, ret; 4842542f5fSchristos 4942542f5fSchristos DBG(("%s\n", __FUNCTION__)); 5042542f5fSchristos 5142542f5fSchristos fd = socket(AF_UNIX, SOCK_STREAM, 0); 5242542f5fSchristos if (fd < 0) 5342542f5fSchristos return -1; 5442542f5fSchristos 5542542f5fSchristos memset(&addr, 0, sizeof(addr)); 5642542f5fSchristos addr.sun_family = AF_UNIX; 5742542f5fSchristos strcpy(addr.sun_path, ACPI_SOCKET); 5842542f5fSchristos 5942542f5fSchristos ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); 6042542f5fSchristos if (ret < 0) { 6142542f5fSchristos close(fd); 6242542f5fSchristos return -1; 6342542f5fSchristos } 6442542f5fSchristos 6542542f5fSchristos DBG(("%s: opened socket to APCI daemon, fd=%d\n", __FUNCTION__, fd)); 6642542f5fSchristos 6742542f5fSchristos return fd; 6842542f5fSchristos} 6942542f5fSchristos 7042542f5fSchristosvoid _sna_acpi_wakeup(struct sna *sna) 7142542f5fSchristos{ 7242542f5fSchristos char *eol; 7342542f5fSchristos int n; 7442542f5fSchristos 7542542f5fSchristos n = read(sna->acpi.fd, 7642542f5fSchristos sna->acpi.event + sna->acpi.offset, 7742542f5fSchristos sna->acpi.remain); 7842542f5fSchristos DBG(("%s: read %d bytes from acpid\n", __FUNCTION__, n)); 7942542f5fSchristos if (n <= 0) { 8042542f5fSchristos /* We will get '0' if we run out of space whilst reading 8142542f5fSchristos * one event - that should never happen, so treat it as 8242542f5fSchristos * an error and give up. 8342542f5fSchristos */ 8442542f5fSchristos if (n < 0) 8542542f5fSchristos n = errno; 8642542f5fSchristos switch (n) { 8742542f5fSchristos case EAGAIN: 8842542f5fSchristos case EINTR: 8942542f5fSchristos return; 9042542f5fSchristos } 9142542f5fSchristos 9242542f5fSchristos DBG(("%s: error [%d], detaching from acpid\n", __FUNCTION__, n)); 9342542f5fSchristos 9442542f5fSchristos /* XXX reattach later? */ 9546edf8f1Smrg#if HAVE_NOTIFY_FD 9646edf8f1Smrg RemoveNotifyFd(sna->acpi.fd); 9746edf8f1Smrg#else 9842542f5fSchristos RemoveGeneralSocket(sna->acpi.fd); 9946edf8f1Smrg#endif 10042542f5fSchristos sna_acpi_fini(sna); 10142542f5fSchristos return; 10242542f5fSchristos } 10342542f5fSchristos 10442542f5fSchristos sna->acpi.event[sna->acpi.offset + n] = '\0'; 10542542f5fSchristos sna->acpi.offset += n; 10642542f5fSchristos sna->acpi.remain -= n; 10742542f5fSchristos 10842542f5fSchristos DBG(("%s: event string [%d]: '%s'\n", __FUNCTION__, sna->acpi.offset, sna->acpi.event)); 10942542f5fSchristos 11042542f5fSchristos do { 11142542f5fSchristos eol = strchr(sna->acpi.event, '\n'); 11242542f5fSchristos if (eol == NULL) 11342542f5fSchristos return; 11442542f5fSchristos 11542542f5fSchristos if (strncmp(sna->acpi.event, "ac_adapter", 10) == 0) { 11642542f5fSchristos char *space = sna->acpi.event; 11742542f5fSchristos int state = -1; 11842542f5fSchristos 11942542f5fSchristos /* ac_adapter ACAD 00000080 00000001 */ 12042542f5fSchristos 12142542f5fSchristos space = strchr(space, ' '); 12242542f5fSchristos if (space) 12342542f5fSchristos space = strchr(space + 1, ' '); 12442542f5fSchristos if (space) 12542542f5fSchristos space = strchr(space + 1, ' '); 12642542f5fSchristos if (space) 12742542f5fSchristos state = atoi(space + 1); 12842542f5fSchristos 12942542f5fSchristos DBG(("%s: ac_adapter event new state=%d\n", __FUNCTION__, state)); 13042542f5fSchristos if (state) 13142542f5fSchristos sna->flags &= ~SNA_POWERSAVE; 13242542f5fSchristos else 13342542f5fSchristos sna->flags |= SNA_POWERSAVE; 13442542f5fSchristos } 13542542f5fSchristos 13642542f5fSchristos n = (sna->acpi.event + sna->acpi.offset) - ++eol; 13742542f5fSchristos memmove(sna->acpi.event, eol, n+1); 13842542f5fSchristos sna->acpi.offset = n; 13942542f5fSchristos sna->acpi.remain = sizeof(sna->acpi.event) - 1 - n; 14042542f5fSchristos } while (n); 14142542f5fSchristos} 14242542f5fSchristos 14342542f5fSchristosstatic int read_power_state(const char *path) 14442542f5fSchristos{ 14542542f5fSchristos DIR *dir; 14642542f5fSchristos struct dirent *de; 14742542f5fSchristos int i = -1; 14842542f5fSchristos 14942542f5fSchristos DBG(("%s: searching '%s'\n", __FUNCTION__, path)); 15042542f5fSchristos 15142542f5fSchristos dir = opendir(path); 15242542f5fSchristos if (dir == NULL) 15342542f5fSchristos return -1; 15442542f5fSchristos 15542542f5fSchristos while ((de = readdir(dir))) { 15642542f5fSchristos char buf[1024]; 15742542f5fSchristos int fd; 15842542f5fSchristos 15942542f5fSchristos if (*de->d_name == '.') 16042542f5fSchristos continue; 16142542f5fSchristos 16242542f5fSchristos DBG(("%s: checking '%s'\n", __FUNCTION__, de->d_name)); 16342542f5fSchristos 16442542f5fSchristos snprintf(buf, sizeof(buf), "%s/%s/type", path, de->d_name); 16542542f5fSchristos fd = open(buf, 0); 16642542f5fSchristos if (fd < 0) 16742542f5fSchristos continue; 16842542f5fSchristos 16942542f5fSchristos i = read(fd, buf, sizeof(buf)); 17042542f5fSchristos buf[i > 0 ? i - 1: 0] = '\0'; 17142542f5fSchristos close(fd); 17242542f5fSchristos 17342542f5fSchristos DBG(("%s: %s is of type '%s'\n", __FUNCTION__, de->d_name, buf)); 17442542f5fSchristos 17542542f5fSchristos if (strcmp(buf, "Mains")) 17642542f5fSchristos continue; 17742542f5fSchristos 17842542f5fSchristos snprintf(buf, sizeof(buf), "%s/%s/online", path, de->d_name); 17942542f5fSchristos fd = open(buf, 0); 18042542f5fSchristos if (fd < 0) 18142542f5fSchristos continue; 18242542f5fSchristos 18342542f5fSchristos i = read(fd, buf, sizeof(buf)); 18442542f5fSchristos buf[i > 0 ? i - 1: 0] = '\0'; 18542542f5fSchristos if (i > 0) 18642542f5fSchristos i = atoi(buf); 18742542f5fSchristos DBG(("%s: %s is online? '%s'\n", __FUNCTION__, de->d_name, buf)); 18842542f5fSchristos close(fd); 18942542f5fSchristos 19042542f5fSchristos break; 19142542f5fSchristos } 19242542f5fSchristos closedir(dir); 19342542f5fSchristos 19442542f5fSchristos return i; 19542542f5fSchristos} 19642542f5fSchristos 19742542f5fSchristosvoid sna_acpi_init(struct sna *sna) 19842542f5fSchristos{ 19942542f5fSchristos if (sna->acpi.fd < 0) 20042542f5fSchristos return; 20142542f5fSchristos 20242542f5fSchristos if (sna->flags & SNA_PERFORMANCE) 20342542f5fSchristos return; 20442542f5fSchristos 20542542f5fSchristos DBG(("%s: attaching to acpid\n", __FUNCTION__)); 20642542f5fSchristos 20746edf8f1Smrg#if HAVE_NOTIFY_FD 20846edf8f1Smrg SetNotifyFd(sna->acpi.fd, NULL, X_NOTIFY_NONE, NULL); 20946edf8f1Smrg#else 21042542f5fSchristos AddGeneralSocket(sna->acpi.fd); 21146edf8f1Smrg#endif 21242542f5fSchristos sna->acpi.remain = sizeof(sna->acpi.event) - 1; 21342542f5fSchristos sna->acpi.offset = 0; 21442542f5fSchristos 21542542f5fSchristos /* Read initial states */ 21642542f5fSchristos if (read_power_state("/sys/class/power_supply") == 0) { 21742542f5fSchristos DBG(("%s: AC adapter is currently offline\n", __FUNCTION__)); 21842542f5fSchristos sna->flags |= SNA_POWERSAVE; 21942542f5fSchristos } 22042542f5fSchristos} 22142542f5fSchristos 22242542f5fSchristosvoid sna_acpi_fini(struct sna *sna) 22342542f5fSchristos{ 22442542f5fSchristos if (sna->acpi.fd < 0) 22542542f5fSchristos return; 22642542f5fSchristos 22742542f5fSchristos close(sna->acpi.fd); 22842542f5fSchristos sna->acpi.fd = -1; 22942542f5fSchristos 23042542f5fSchristos sna->flags &= ~SNA_POWERSAVE; 23142542f5fSchristos} 232