1/***************************************************************************
2 *
3 * devinfo_acpi : acpi devices
4 *
5 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
6 * Use is subject to license terms.
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 **************************************************************************/
11
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include <stdio.h>
17#include <string.h>
18#include <sys/utsname.h>
19#include <libdevinfo.h>
20#include <sys/mkdev.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <sys/sysevent/dev.h>
24#include <sys/sysevent/pwrctl.h>
25
26#include "../osspec.h"
27#include "../logger.h"
28#include "../hald.h"
29#include "../hald_dbus.h"
30#include "../device_info.h"
31#include "../util.h"
32#include "../hald_runner.h"
33#include "devinfo_acpi.h"
34
35#define		DEVINFO_PROBE_ACPI_TIMEOUT	30000
36
37static HalDevice *devinfo_acpi_add(HalDevice *, di_node_t, char *, char *);
38static HalDevice *devinfo_power_button_add(HalDevice *parent, di_node_t node,
39    char *devfs_path, char *device_type);
40static void devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type,
41    gint return_code, char **error, gpointer userdata1, gpointer userdata2);
42
43DevinfoDevHandler devinfo_acpi_handler = {
44	devinfo_acpi_add,
45	NULL,
46	NULL,
47	NULL,
48	NULL,
49	devinfo_acpi_get_prober
50};
51
52DevinfoDevHandler devinfo_power_button_handler = {
53	devinfo_power_button_add,
54	NULL,
55	NULL,
56	NULL,
57	NULL,
58	NULL
59};
60
61static HalDevice *
62devinfo_acpi_add(HalDevice *parent, di_node_t node, char *devfs_path,
63    char *device_type)
64{
65	HalDevice *d, *computer;
66	char	*driver_name;
67	di_devlink_handle_t devlink_hdl;
68	int	major;
69	di_minor_t minor;
70	dev_t   dev;
71	char    *minor_path = NULL;
72	char    *devpath;
73
74	driver_name = di_driver_name(node);
75	if ((driver_name == NULL) || (strcmp(driver_name, "acpi_drv") != 0)) {
76		return (NULL);
77	}
78
79	d = hal_device_new();
80
81	if ((computer = hal_device_store_find(hald_get_gdl(),
82	    "/org/freedesktop/Hal/devices/computer")) ||
83	    (computer = hal_device_store_find(hald_get_tdl(),
84	    "/org/freedesktop/Hal/devices/computer"))) {
85		hal_device_property_set_string(computer,
86		    "system.formfactor", "laptop");
87		hal_device_property_set_string(computer,
88		    "power_management.type", "acpi");
89	}
90	devinfo_set_default_properties(d, parent, node, devfs_path);
91	devinfo_add_enqueue(d, devfs_path, &devinfo_acpi_handler);
92
93	major = di_driver_major(node);
94	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
95		return (d);
96	}
97	minor = DI_MINOR_NIL;
98	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
99		dev = di_minor_devt(minor);
100		if ((major != major(dev)) ||
101		    (di_minor_type(minor) != DDM_MINOR) ||
102		    (di_minor_spectype(minor) != S_IFCHR) ||
103		    ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
104			continue;
105		}
106
107		if (hal_device_store_match_key_value_string(hald_get_gdl(),
108		    "solaris.devfs_path", minor_path) == NULL) {
109			devinfo_acpi_add_minor(d, node, minor_path, dev);
110		}
111
112		di_devfs_path_free(minor_path);
113	}
114	di_devlink_fini(&devlink_hdl);
115
116	return (d);
117}
118
119void
120devinfo_acpi_add_minor(HalDevice *parent, di_node_t node, char *minor_path,
121    dev_t dev)
122{
123	HalDevice *d;
124
125	d = hal_device_new();
126	devinfo_set_default_properties(d, parent, node, minor_path);
127	devinfo_add_enqueue(d, minor_path, &devinfo_acpi_handler);
128}
129
130static HalDevice *
131devinfo_power_button_add(HalDevice *parent, di_node_t node, char *devfs_path,
132    char *device_type)
133{
134	HalDevice *d;
135	char *driver_name;
136
137	driver_name = di_driver_name(node);
138	if ((driver_name == NULL) || (strcmp(driver_name, "power") != 0)) {
139		return (NULL);
140	}
141
142	d = hal_device_new();
143
144	devinfo_set_default_properties(d, parent, node, devfs_path);
145	hal_device_add_capability(d, "button");
146	hal_device_property_set_bool(d, "button.has_state", FALSE);
147	hal_device_property_set_string(d, "info.category", "input");
148	hal_device_property_set_string(d, "button.type", "power");
149	hal_device_property_set_string(d, "info.product", "Power Button");
150
151	devinfo_add_enqueue(d, devfs_path, &devinfo_power_button_handler);
152
153	return (d);
154}
155
156void
157devinfo_power_button_event(void)
158{
159	HalDevice *d = NULL;
160	HalDeviceStore *store = hald_get_gdl();
161
162	d = hal_device_store_match_key_value_string (store, "button.type",
163	    "power");
164	if (d != NULL) {
165		device_send_signal_condition(d, "ButtonPressed", "power");
166	}
167}
168
169void
170devinfo_brightness_hotkeys_event(char *subclass)
171{
172	HalDevice *d = NULL;
173
174	if ((d = hal_device_store_find(hald_get_gdl(),
175	    "/org/freedesktop/Hal/devices/computer")) ||
176	    (d = hal_device_store_find(hald_get_tdl(),
177	    "/org/freedesktop/Hal/devices/computer"))) {
178		if (strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_UP) == 0) {
179			device_send_signal_condition(d, "ButtonPressed",
180			    "brightness-up");
181		} else {
182			device_send_signal_condition(d, "ButtonPressed",
183			    "brightness-down");
184		}
185	}
186}
187
188void
189devinfo_battery_rescan(char *parent_devfs_path, gchar *udi)
190{
191	HalDevice *d = NULL;
192
193	d = hal_device_store_find(hald_get_gdl(), udi);
194	if (d == NULL) {
195		HAL_INFO(("device not found %s", udi));
196		return;
197	}
198
199	hald_runner_run(d, "hald-probe-acpi", NULL,
200	    DEVINFO_PROBE_ACPI_TIMEOUT, devinfo_battery_rescan_probing_done,
201	    NULL, NULL);
202}
203
204void
205devinfo_lid_event(char *subclass, gchar *udi)
206{
207	HalDevice *d = NULL;
208
209	d = hal_device_store_find(hald_get_gdl(), udi);
210	if (d == NULL) {
211		HAL_INFO(("device not found %s", udi));
212		return;
213	}
214
215	hal_device_property_set_bool(d, "button.state.value",
216	    (strcmp(subclass, ESC_PWRCTL_REMOVE) == 0));
217	device_send_signal_condition(d, "ButtonPressed", "lid");
218}
219
220gboolean
221devinfo_lid_rescan(HalDevice *d)
222{
223	if (hal_device_property_get_bool(d, "button.workaround")) {
224		/* Set lid state to open for workaround */
225		hal_device_property_set_bool(d, "button.state.value", FALSE);
226	} else {
227		hald_runner_run(d, "hald-probe-acpi", NULL,
228		    DEVINFO_PROBE_ACPI_TIMEOUT,
229		    devinfo_battery_rescan_probing_done, NULL, NULL);
230	}
231
232	return (TRUE);
233}
234
235static void
236devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type,
237    gint return_code, char **error, gpointer userdata1, gpointer userdata2)
238{
239	/* hald_runner_run() requires this function since cannot pass NULL */
240}
241
242const gchar *
243devinfo_acpi_get_prober(HalDevice *d, int *timeout)
244{
245	*timeout = DEVINFO_PROBE_ACPI_TIMEOUT;    /* 30 second timeout */
246	return ("hald-probe-acpi");
247}
248