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