1 /*
2 * Copyright 2020, Jérôme Duval, jerome.duval@gmail.com.
3 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
4 * Distributed under the terms of the MIT license.
5 */
6
7
8 //! Driver for I2C Human Interface Devices.
9
10
11 #include <ACPI.h>
12 #include <device_manager.h>
13 #include <i2c.h>
14
15 #include "DeviceList.h"
16 #include "Driver.h"
17 #include "HIDDevice.h"
18 #include "ProtocolHandler.h"
19
20 #include <lock.h>
21 #include <util/AutoLock.h>
22
23 #include <new>
24 #include <stdio.h>
25 #include <string.h>
26
27
28
29 struct hid_driver_cookie {
30 device_node* node;
31 i2c_device_interface* i2c;
32 i2c_device i2c_cookie;
33 uint32 descriptorAddress;
34 HIDDevice* hidDevice;
35 };
36
37 struct device_cookie {
38 ProtocolHandler* handler;
39 uint32 cookie;
40 hid_driver_cookie* driver_cookie;
41 };
42
43
44 #define I2C_HID_DRIVER_NAME "drivers/input/i2c_hid/driver_v1"
45 #define I2C_HID_DEVICE_NAME "drivers/input/i2c_hid/device_v1"
46
47 /* Base Namespace devices are published to */
48 #define I2C_HID_BASENAME "input/i2c_hid/%d"
49
50 // name of pnp generator of path ids
51 #define I2C_HID_PATHID_GENERATOR "i2c_hid/path_id"
52
53 #define ACPI_NAME_HID_DEVICE "PNP0C50"
54
55 static device_manager_info *sDeviceManager;
56 static acpi_module_info* gACPI;
57
58 DeviceList *gDeviceList = NULL;
59 static mutex sDriverLock;
60
61
62 static acpi_object_type*
acpi_evaluate_dsm(acpi_handle handle,const uint8 * guid,uint64 revision,uint64 function)63 acpi_evaluate_dsm(acpi_handle handle, const uint8 *guid, uint64 revision, uint64 function)
64 {
65 acpi_data buffer;
66 buffer.pointer = NULL;
67 buffer.length = ACPI_ALLOCATE_BUFFER;
68
69 acpi_object_type array[4];
70 acpi_objects acpi_objects;
71 acpi_objects.count = 4;
72 acpi_objects.pointer = array;
73
74 array[0].object_type = ACPI_TYPE_BUFFER;
75 array[0].buffer.buffer = (void*)guid;
76 array[0].buffer.length = 16;
77
78 array[1].object_type = ACPI_TYPE_INTEGER;
79 array[1].integer.integer = revision;
80
81 array[2].object_type = ACPI_TYPE_INTEGER;
82 array[2].integer.integer = function;
83
84 array[3].object_type = ACPI_TYPE_PACKAGE;
85 array[3].package.objects = NULL;
86 array[3].package.count = 0;
87
88 if (gACPI->evaluate_method(handle, "_DSM", &acpi_objects, &buffer) == B_OK)
89 return (acpi_object_type*)buffer.pointer;
90 return NULL;
91 }
92
93
94 // #pragma mark - notify hooks
95
96
97 /*
98 status_t
99 i2c_hid_device_removed(void *cookie)
100 {
101 mutex_lock(&sDriverLock);
102 int32 parentCookie = (int32)(addr_t)cookie;
103 TRACE("device_removed(%" B_PRId32 ")\n", parentCookie);
104
105 for (int32 i = 0; i < gDeviceList->CountDevices(); i++) {
106 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i);
107 if (!handler)
108 continue;
109
110 HIDDevice *device = handler->Device();
111 if (device->ParentCookie() != parentCookie)
112 continue;
113
114 // remove all the handlers
115 for (uint32 i = 0;; i++) {
116 handler = device->ProtocolHandlerAt(i);
117 if (handler == NULL)
118 break;
119
120 gDeviceList->RemoveDevice(NULL, handler);
121 }
122
123 // this handler's device belongs to the one removed
124 if (device->IsOpen()) {
125 // the device and it's handlers will be deleted in the free hook
126 device->Removed();
127 } else
128 delete device;
129
130 break;
131 }
132
133 mutex_unlock(&sDriverLock);
134 return B_OK;
135 }*/
136
137
138 // #pragma mark - driver hooks
139
140
141 static status_t
i2c_hid_init_device(void * driverCookie,void ** cookie)142 i2c_hid_init_device(void *driverCookie, void **cookie)
143 {
144 *cookie = driverCookie;
145 return B_OK;
146 }
147
148
149 static void
i2c_hid_uninit_device(void * _cookie)150 i2c_hid_uninit_device(void *_cookie)
151 {
152
153 }
154
155
156 static status_t
i2c_hid_open(void * initCookie,const char * path,int flags,void ** _cookie)157 i2c_hid_open(void *initCookie, const char *path, int flags, void **_cookie)
158 {
159 TRACE("open(%s, %" B_PRIu32 ", %p)\n", path, flags, _cookie);
160
161 device_cookie *cookie = new(std::nothrow) device_cookie();
162 if (cookie == NULL)
163 return B_NO_MEMORY;
164 cookie->driver_cookie = (hid_driver_cookie*)initCookie;
165
166 MutexLocker locker(sDriverLock);
167
168 ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(path);
169 TRACE(" path %s: handler %p\n", path, handler);
170
171 cookie->handler = handler;
172 cookie->cookie = 0;
173
174 status_t result = handler == NULL ? B_ENTRY_NOT_FOUND : B_OK;
175 if (result == B_OK)
176 result = handler->Open(flags, &cookie->cookie);
177
178 if (result != B_OK) {
179 delete cookie;
180 return result;
181 }
182
183 *_cookie = cookie;
184
185 return B_OK;
186 }
187
188
189 static status_t
i2c_hid_read(void * _cookie,off_t position,void * buffer,size_t * numBytes)190 i2c_hid_read(void *_cookie, off_t position, void *buffer, size_t *numBytes)
191 {
192 device_cookie *cookie = (device_cookie *)_cookie;
193
194 TRACE("read(%p, %" B_PRIu64 ", %p, %p (%" B_PRIuSIZE ")\n", cookie, position, buffer, numBytes,
195 numBytes != NULL ? *numBytes : 0);
196 return cookie->handler->Read(&cookie->cookie, position, buffer, numBytes);
197 }
198
199
200 static status_t
i2c_hid_write(void * _cookie,off_t position,const void * buffer,size_t * numBytes)201 i2c_hid_write(void *_cookie, off_t position, const void *buffer,
202 size_t *numBytes)
203 {
204 device_cookie *cookie = (device_cookie *)_cookie;
205
206 TRACE("write(%p, %" B_PRIu64 ", %p, %p (%" B_PRIuSIZE ")\n", cookie, position, buffer, numBytes,
207 numBytes != NULL ? *numBytes : 0);
208 return cookie->handler->Write(&cookie->cookie, position, buffer, numBytes);
209 }
210
211
212 static status_t
i2c_hid_control(void * _cookie,uint32 op,void * buffer,size_t length)213 i2c_hid_control(void *_cookie, uint32 op, void *buffer, size_t length)
214 {
215 device_cookie *cookie = (device_cookie *)_cookie;
216
217 TRACE("control(%p, %" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", cookie, op, buffer, length);
218 return cookie->handler->Control(&cookie->cookie, op, buffer, length);
219 }
220
221
222 static status_t
i2c_hid_close(void * _cookie)223 i2c_hid_close(void *_cookie)
224 {
225 device_cookie *cookie = (device_cookie *)_cookie;
226
227 TRACE("close(%p)\n", cookie);
228 return cookie->handler->Close(&cookie->cookie);
229 }
230
231
232 static status_t
i2c_hid_free(void * _cookie)233 i2c_hid_free(void *_cookie)
234 {
235 device_cookie *cookie = (device_cookie *)_cookie;
236 TRACE("free(%p)\n", cookie);
237
238 mutex_lock(&sDriverLock);
239
240 HIDDevice *device = cookie->handler->Device();
241 if (device->IsOpen()) {
242 // another handler of this device is still open so we can't free it
243 } else if (device->IsRemoved()) {
244 // the parent device is removed already and none of its handlers are
245 // open anymore so we can free it here
246 delete device;
247 }
248
249 mutex_unlock(&sDriverLock);
250
251 delete cookie;
252 return B_OK;
253 }
254
255
256 // #pragma mark - driver module API
257
258
259 static float
i2c_hid_support(device_node * parent)260 i2c_hid_support(device_node *parent)
261 {
262 CALLED();
263
264 // make sure parent is really the I2C bus manager
265 const char *bus;
266 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
267 return -1;
268
269 if (strcmp(bus, "i2c"))
270 return 0.0;
271 TRACE("i2c_hid_support found an i2c device %p\n", parent);
272
273 // check whether it's an HID device
274 uint64 handlePointer;
275 if (sDeviceManager->get_attr_uint64(parent, ACPI_DEVICE_HANDLE_ITEM,
276 &handlePointer, false) != B_OK) {
277 TRACE("i2c_hid_support found an i2c device without acpi handle\n");
278 return B_ERROR;
279 }
280
281 const char *name;
282 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
283 false) == B_OK && strcmp(name, ACPI_NAME_HID_DEVICE) == 0) {
284 TRACE("i2c_hid_support found an hid i2c device\n");
285 return 0.6;
286 }
287
288 if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_CID_ITEM, &name,
289 false) == B_OK && strcmp(name, ACPI_NAME_HID_DEVICE) == 0) {
290 TRACE("i2c_hid_support found a compatible hid i2c device\n");
291 return 0.6;
292 }
293
294 uint16 slaveAddress;
295 if (sDeviceManager->get_attr_uint16(parent, I2C_DEVICE_SLAVE_ADDR_ITEM,
296 &slaveAddress, false) != B_OK) {
297 TRACE("i2c_hid_support found a non hid without addr i2c device\n");
298 return B_ERROR;
299 }
300
301 TRACE("i2c_hid_support found a non hid i2c device\n");
302
303 return 0.0;
304 }
305
306
307 static status_t
i2c_hid_register_device(device_node * node)308 i2c_hid_register_device(device_node *node)
309 {
310 CALLED();
311
312 acpi_handle handle;
313 if (sDeviceManager->get_attr_uint64(node, ACPI_DEVICE_HANDLE_ITEM,
314 (uint64*)&handle, false) != B_OK) {
315 return B_DEVICE_NOT_FOUND;
316 }
317
318 static uint8_t acpiHidGuid[] = { 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55,
319 0x45, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE };
320 acpi_object_type* object = acpi_evaluate_dsm(handle, acpiHidGuid, 1, 1);
321 if (object == NULL)
322 return B_DEVICE_NOT_FOUND;
323 if (object->object_type != ACPI_TYPE_INTEGER) {
324 free(object);
325 return B_DEVICE_NOT_FOUND;
326 }
327
328 uint32 descriptorAddress = object->integer.integer;
329 free(object);
330 device_attr attrs[] = {
331 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "I2C HID Device" }},
332 { "descriptorAddress", B_UINT32_TYPE, { .ui32 = descriptorAddress }},
333 { NULL }
334 };
335
336 return sDeviceManager->register_node(node, I2C_HID_DRIVER_NAME, attrs,
337 NULL, NULL);
338 }
339
340
341 static status_t
i2c_hid_init_driver(device_node * node,void ** driverCookie)342 i2c_hid_init_driver(device_node *node, void **driverCookie)
343 {
344 CALLED();
345
346 uint32 descriptorAddress;
347 if (sDeviceManager->get_attr_uint32(node, "descriptorAddress",
348 &descriptorAddress, false) != B_OK) {
349 return B_DEVICE_NOT_FOUND;
350 }
351
352 hid_driver_cookie *device
353 = (hid_driver_cookie *)calloc(1, sizeof(hid_driver_cookie));
354 if (device == NULL)
355 return B_NO_MEMORY;
356
357 *driverCookie = device;
358
359 device->node = node;
360 device->descriptorAddress = descriptorAddress;
361
362 device_node *parent;
363 parent = sDeviceManager->get_parent_node(node);
364 sDeviceManager->get_driver(parent, (driver_module_info **)&device->i2c,
365 (void **)&device->i2c_cookie);
366 sDeviceManager->put_node(parent);
367
368 mutex_lock(&sDriverLock);
369 HIDDevice *hidDevice
370 = new(std::nothrow) HIDDevice(descriptorAddress, device->i2c,
371 device->i2c_cookie);
372
373 if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) {
374 device->hidDevice = hidDevice;
375 } else
376 delete hidDevice;
377
378 mutex_unlock(&sDriverLock);
379
380 return device->hidDevice != NULL ? B_OK : B_IO_ERROR;
381 }
382
383
384 static void
i2c_hid_uninit_driver(void * driverCookie)385 i2c_hid_uninit_driver(void *driverCookie)
386 {
387 CALLED();
388 hid_driver_cookie *device = (hid_driver_cookie*)driverCookie;
389
390 free(device);
391 }
392
393
394 static status_t
i2c_hid_register_child_devices(void * cookie)395 i2c_hid_register_child_devices(void *cookie)
396 {
397 CALLED();
398 hid_driver_cookie *device = (hid_driver_cookie*)cookie;
399 HIDDevice* hidDevice = device->hidDevice;
400 if (hidDevice == NULL)
401 return B_OK;
402 for (uint32 i = 0;; i++) {
403 ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i);
404 if (handler == NULL)
405 break;
406
407 // As devices can be un- and replugged at will, we cannot
408 // simply rely on a device count. If there is just one
409 // keyboard, this does not mean that it uses the 0 name.
410 // There might have been two keyboards and the one using 0
411 // might have been unplugged. So we just generate names
412 // until we find one that is not currently in use.
413 int32 index = 0;
414 char pathBuffer[128];
415 const char *basePath = handler->BasePath();
416 while (true) {
417 sprintf(pathBuffer, "%s%" B_PRId32, basePath, index++);
418 if (gDeviceList->FindDevice(pathBuffer) == NULL) {
419 // this name is still free, use it
420 handler->SetPublishPath(strdup(pathBuffer));
421 break;
422 }
423 }
424
425 gDeviceList->AddDevice(handler->PublishPath(), handler);
426
427 sDeviceManager->publish_device(device->node, pathBuffer,
428 I2C_HID_DEVICE_NAME);
429 }
430
431
432 /* int pathID = sDeviceManager->create_id(I2C_HID_PATHID_GENERATOR);
433 if (pathID < 0) {
434 ERROR("register_child_devices: couldn't create a path_id\n");
435 return B_ERROR;
436 }*/
437 return B_OK;
438 }
439
440
441 static status_t
std_ops(int32 op,...)442 std_ops(int32 op, ...)
443 {
444 switch (op) {
445 case B_MODULE_INIT:
446 gDeviceList = new(std::nothrow) DeviceList();
447 if (gDeviceList == NULL) {
448 return B_NO_MEMORY;
449 }
450 mutex_init(&sDriverLock, "i2c hid driver lock");
451
452 return B_OK;
453 case B_MODULE_UNINIT:
454 delete gDeviceList;
455 gDeviceList = NULL;
456 mutex_destroy(&sDriverLock);
457 return B_OK;
458
459 default:
460 break;
461 }
462
463 return B_ERROR;
464 }
465
466
467 // #pragma mark -
468
469
470 driver_module_info i2c_hid_driver_module = {
471 {
472 I2C_HID_DRIVER_NAME,
473 0,
474 &std_ops
475 },
476
477 i2c_hid_support,
478 i2c_hid_register_device,
479 i2c_hid_init_driver,
480 i2c_hid_uninit_driver,
481 i2c_hid_register_child_devices,
482 NULL, // rescan
483 NULL, // removed
484 };
485
486
487 struct device_module_info i2c_hid_device_module = {
488 {
489 I2C_HID_DEVICE_NAME,
490 0,
491 NULL
492 },
493
494 i2c_hid_init_device,
495 i2c_hid_uninit_device,
496 NULL,
497
498 i2c_hid_open,
499 i2c_hid_close,
500 i2c_hid_free,
501 i2c_hid_read,
502 i2c_hid_write,
503 NULL,
504 i2c_hid_control,
505
506 NULL,
507 NULL
508 };
509
510
511 module_dependency module_dependencies[] = {
512 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
513 { B_ACPI_MODULE_NAME, (module_info**)&gACPI },
514 {}
515 };
516
517
518 module_info *modules[] = {
519 (module_info *)&i2c_hid_driver_module,
520 (module_info *)&i2c_hid_device_module,
521 NULL
522 };
523