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
29struct 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
37struct 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
55static device_manager_info *sDeviceManager;
56static acpi_module_info* gACPI;
57
58DeviceList *gDeviceList = NULL;
59static mutex sDriverLock;
60
61
62static acpi_object_type*
63acpi_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/*
98status_t
99i2c_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
141static status_t
142i2c_hid_init_device(void *driverCookie, void **cookie)
143{
144	*cookie = driverCookie;
145	return B_OK;
146}
147
148
149static void
150i2c_hid_uninit_device(void *_cookie)
151{
152
153}
154
155
156static status_t
157i2c_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
189static status_t
190i2c_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
200static status_t
201i2c_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
212static status_t
213i2c_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
222static status_t
223i2c_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
232static status_t
233i2c_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
259static float
260i2c_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
307static status_t
308i2c_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
341static status_t
342i2c_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
384static void
385i2c_hid_uninit_driver(void *driverCookie)
386{
387	CALLED();
388	hid_driver_cookie *device = (hid_driver_cookie*)driverCookie;
389
390	free(device);
391}
392
393
394static status_t
395i2c_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
441static status_t
442std_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
470driver_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
487struct 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
511module_dependency module_dependencies[] = {
512	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
513	{ B_ACPI_MODULE_NAME, (module_info**)&gACPI },
514	{}
515};
516
517
518module_info *modules[] = {
519	(module_info *)&i2c_hid_driver_module,
520	(module_info *)&i2c_hid_device_module,
521	NULL
522};
523