1 /*
2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de.
3 *
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include <ACPI.h>
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14
15 #define ACPI_AC_MODULE_NAME "drivers/power/acpi_ac/driver_v1"
16
17 #define ACPI_AC_DEVICE_MODULE_NAME "drivers/power/acpi_ac/device_v1"
18
19 /* Base Namespace devices are published to */
20 #define ACPI_AC_BASENAME "power/acpi_ac/%d"
21
22 // name of pnp generator of path ids
23 #define ACPI_AC_PATHID_GENERATOR "acpi_ac/path_id"
24
25 #define TRACE_AC
26 #ifdef TRACE_AC
27 # define TRACE(x...) dprintf("acpi_ac: " x)
28 #else
29 # define TRACE(x...)
30 #endif
31 #define ERROR(x...) dprintf("acpi_ac: " x)
32
33 static device_manager_info *sDeviceManager;
34
35
36 typedef struct acpi_ns_device_info {
37 device_node *node;
38 acpi_device_module_info *acpi;
39 acpi_device acpi_cookie;
40 uint8 last_status;
41 } acpi_ac_device_info;
42
43
44 static void
acpi_ac_update_status(acpi_ac_device_info * device)45 acpi_ac_update_status(acpi_ac_device_info* device)
46 {
47 acpi_data buf;
48 buf.pointer = NULL;
49 buf.length = ACPI_ALLOCATE_BUFFER;
50
51 if (device->acpi->evaluate_method(device->acpi_cookie, "_PSR", NULL, &buf) != B_OK
52 || buf.pointer == NULL
53 || ((acpi_object_type*)buf.pointer)->object_type != ACPI_TYPE_INTEGER) {
54 ERROR("couldn't get status\n");
55 } else {
56 acpi_object_type* object = (acpi_object_type*)buf.pointer;
57 device->last_status = object->integer.integer;
58 TRACE("status %d\n", device->last_status);
59 }
60 free(buf.pointer);
61 }
62
63
64 static void
acpi_ac_notify_handler(acpi_handle device,uint32 value,void * context)65 acpi_ac_notify_handler(acpi_handle device, uint32 value, void *context)
66 {
67 if (value != 0x80) {
68 dprintf("acpi_ac: unknown notification (%d)\n", value);
69 return;
70 }
71
72 acpi_ac_device_info* dev = (acpi_ac_device_info*) context;
73 acpi_ac_update_status(dev);
74 }
75
76
77 // #pragma mark - device module API
78
79
80 static status_t
acpi_ac_init_device(void * driverCookie,void ** cookie)81 acpi_ac_init_device(void *driverCookie, void **cookie)
82 {
83 *cookie = driverCookie;
84 return B_OK;
85 }
86
87
88 static void
acpi_ac_uninit_device(void * _cookie)89 acpi_ac_uninit_device(void *_cookie)
90 {
91
92 }
93
94
95 static status_t
acpi_ac_open(void * _cookie,const char * path,int flags,void ** cookie)96 acpi_ac_open(void *_cookie, const char *path, int flags, void** cookie)
97 {
98 acpi_ac_device_info *device = (acpi_ac_device_info *)_cookie;
99 *cookie = device;
100 return B_OK;
101 }
102
103
104 static status_t
acpi_ac_read(void * _cookie,off_t position,void * buf,size_t * num_bytes)105 acpi_ac_read(void* _cookie, off_t position, void *buf, size_t* num_bytes)
106 {
107 acpi_ac_device_info* device = (acpi_ac_device_info*)_cookie;
108 if (*num_bytes < 1)
109 return B_IO_ERROR;
110
111 if (position > 0) {
112 *num_bytes = 0;
113 return B_OK;
114 }
115
116 if (user_memcpy(buf, &device->last_status, sizeof(uint8)) < B_OK)
117 return B_BAD_ADDRESS;
118
119 *num_bytes = 1;
120 return B_OK;
121 }
122
123
124 static status_t
acpi_ac_write(void * cookie,off_t position,const void * buffer,size_t * num_bytes)125 acpi_ac_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
126 {
127 return B_ERROR;
128 }
129
130
131 static status_t
acpi_ac_control(void * _cookie,uint32 op,void * arg,size_t len)132 acpi_ac_control(void* _cookie, uint32 op, void* arg, size_t len)
133 {
134 return B_ERROR;
135 }
136
137
138 static status_t
acpi_ac_close(void * cookie)139 acpi_ac_close (void* cookie)
140 {
141 return B_OK;
142 }
143
144
145 static status_t
acpi_ac_free(void * cookie)146 acpi_ac_free (void* cookie)
147 {
148 return B_OK;
149 }
150
151
152 // #pragma mark - driver module API
153
154
155 static float
acpi_ac_support(device_node * parent)156 acpi_ac_support(device_node *parent)
157 {
158 const char *bus;
159 uint32 device_type;
160 const char *hid;
161
162 // make sure parent is really the ACPI bus manager
163 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
164 return -1;
165
166 if (strcmp(bus, "acpi"))
167 return 0.0;
168
169 // check whether it's really a device
170 if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM,
171 &device_type, false) != B_OK
172 || device_type != ACPI_TYPE_DEVICE) {
173 return 0.0;
174 }
175
176 // check whether it's an ac device
177 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid,
178 false) != B_OK || strcmp(hid, "ACPI0003")) {
179 return 0.0;
180 }
181
182 dprintf("acpi_ac_support ac device found\n");
183
184 return 0.6;
185 }
186
187
188 static status_t
acpi_ac_register_device(device_node * node)189 acpi_ac_register_device(device_node *node)
190 {
191 device_attr attrs[] = {
192 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "ACPI AC" }},
193 { NULL }
194 };
195
196 return sDeviceManager->register_node(node, ACPI_AC_MODULE_NAME, attrs,
197 NULL, NULL);
198 }
199
200
201 static status_t
acpi_ac_init_driver(device_node * node,void ** _driverCookie)202 acpi_ac_init_driver(device_node *node, void **_driverCookie)
203 {
204 acpi_ac_device_info *device;
205 device_node *parent;
206 status_t status;
207
208 device = (acpi_ac_device_info *)calloc(1, sizeof(*device));
209 if (device == NULL)
210 return B_NO_MEMORY;
211
212 device->node = node;
213
214 parent = sDeviceManager->get_parent_node(node);
215 sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
216 (void **)&device->acpi_cookie);
217 sDeviceManager->put_node(parent);
218
219 status = device->acpi->install_notify_handler(device->acpi_cookie,
220 ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, device);
221 if (status != B_OK) {
222 ERROR("can't install notify handler\n");
223 }
224
225 device->last_status = 0;
226
227 acpi_ac_update_status(device);
228
229 *_driverCookie = device;
230 return B_OK;
231 }
232
233
234 static void
acpi_ac_uninit_driver(void * driverCookie)235 acpi_ac_uninit_driver(void *driverCookie)
236 {
237 acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
238
239 device->acpi->remove_notify_handler(device->acpi_cookie,
240 ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler);
241
242 free(device);
243 }
244
245
246 static status_t
acpi_ac_register_child_devices(void * driverCookie)247 acpi_ac_register_child_devices(void *driverCookie)
248 {
249 acpi_ac_device_info *device = (acpi_ac_device_info *)driverCookie;
250 int path_id;
251 char name[128];
252
253 path_id = sDeviceManager->create_id(ACPI_AC_PATHID_GENERATOR);
254 if (path_id < 0) {
255 ERROR("register_child_devices: couldn't create a path_id\n");
256 return B_ERROR;
257 }
258
259 snprintf(name, sizeof(name), ACPI_AC_BASENAME, path_id);
260
261 return sDeviceManager->publish_device(device->node, name,
262 ACPI_AC_DEVICE_MODULE_NAME);
263 }
264
265
266 module_dependency module_dependencies[] = {
267 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
268 {}
269 };
270
271
272 driver_module_info acpi_ac_driver_module = {
273 {
274 ACPI_AC_MODULE_NAME,
275 0,
276 NULL
277 },
278
279 acpi_ac_support,
280 acpi_ac_register_device,
281 acpi_ac_init_driver,
282 acpi_ac_uninit_driver,
283 acpi_ac_register_child_devices,
284 NULL, // rescan
285 NULL, // removed
286 };
287
288
289 struct device_module_info acpi_ac_device_module = {
290 {
291 ACPI_AC_DEVICE_MODULE_NAME,
292 0,
293 NULL
294 },
295
296 acpi_ac_init_device,
297 acpi_ac_uninit_device,
298 NULL,
299
300 acpi_ac_open,
301 acpi_ac_close,
302 acpi_ac_free,
303 acpi_ac_read,
304 acpi_ac_write,
305 NULL,
306 acpi_ac_control,
307
308 NULL,
309 NULL
310 };
311
312 module_info *modules[] = {
313 (module_info *)&acpi_ac_driver_module,
314 (module_info *)&acpi_ac_device_module,
315 NULL
316 };
317