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 
37 static HalDevice *devinfo_acpi_add(HalDevice *, di_node_t, char *, char *);
38 static HalDevice *devinfo_power_button_add(HalDevice *parent, di_node_t node,
39     char *devfs_path, char *device_type);
40 static void devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type,
41     gint return_code, char **error, gpointer userdata1, gpointer userdata2);
42 
43 DevinfoDevHandler devinfo_acpi_handler = {
44 	devinfo_acpi_add,
45 	NULL,
46 	NULL,
47 	NULL,
48 	NULL,
49 	devinfo_acpi_get_prober
50 };
51 
52 DevinfoDevHandler devinfo_power_button_handler = {
53 	devinfo_power_button_add,
54 	NULL,
55 	NULL,
56 	NULL,
57 	NULL,
58 	NULL
59 };
60 
61 static HalDevice *
devinfo_acpi_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)62 devinfo_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 
119 void
devinfo_acpi_add_minor(HalDevice * parent,di_node_t node,char * minor_path,dev_t dev)120 devinfo_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 
130 static HalDevice *
devinfo_power_button_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)131 devinfo_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 
156 void
devinfo_power_button_event(void)157 devinfo_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 
169 void
devinfo_brightness_hotkeys_event(char * subclass)170 devinfo_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 
188 void
devinfo_battery_rescan(char * parent_devfs_path,gchar * udi)189 devinfo_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 
204 void
devinfo_lid_event(char * subclass,gchar * udi)205 devinfo_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 
220 gboolean
devinfo_lid_rescan(HalDevice * d)221 devinfo_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 
235 static void
devinfo_battery_rescan_probing_done(HalDevice * d,guint32 exit_type,gint return_code,char ** error,gpointer userdata1,gpointer userdata2)236 devinfo_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 
242 const gchar *
devinfo_acpi_get_prober(HalDevice * d,int * timeout)243 devinfo_acpi_get_prober(HalDevice *d, int *timeout)
244 {
245 	*timeout = DEVINFO_PROBE_ACPI_TIMEOUT;    /* 30 second timeout */
246 	return ("hald-probe-acpi");
247 }
248