xref: /haiku/src/add-ons/kernel/drivers/input/i2c_hid/Driver.cpp (revision d1e42115d0b4c70d13f4d4956ada0c3ee50a4e6e)
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