1/*
2 * Copyright 2020, J��r��me Duval, jerome.duval@gmail.com.
3 * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
4 * Copyright 2020, 2022 Vladimir Kondratyev <wulf@FreeBSD.org>
5 * Copyright 2023 Vladimir Serbinenko <phcoder@gmail.com>
6 * Distributed under the terms of the MIT license.
7 */
8
9
10//!	Driver for I2C Elan Devices.
11// Partially based on FreeBSD ietp driver
12
13
14#include <ACPI.h>
15#include <device_manager.h>
16#include <i2c.h>
17
18#include "DeviceList.h"
19#include "Driver.h"
20#include "ELANDevice.h"
21
22#include <lock.h>
23#include <util/AutoLock.h>
24
25#include <new>
26#include <stdio.h>
27#include <string.h>
28
29
30
31struct elan_driver_cookie {
32	ELANDevice*				elanDevice;
33};
34
35#define I2C_ELAN_DRIVER_NAME "drivers/input/i2c_elan/driver_v1"
36#define I2C_ELAN_DEVICE_NAME "drivers/input/i2c_elan/device_v1"
37
38/* Base Namespace devices are published to */
39#define I2C_ELAN_BASENAME "input/i2c_elan/%d"
40
41static const char* elan_iic_devs[] = {
42	"ELAN0000",
43	"ELAN0100",
44	"ELAN0600",
45	"ELAN0601",
46	"ELAN0602",
47	"ELAN0603",
48	"ELAN0604",
49	"ELAN0605",
50	"ELAN0606",
51	"ELAN0607",
52	"ELAN0608",
53	"ELAN0609",
54	"ELAN060B",
55	"ELAN060C",
56	"ELAN060F",
57	"ELAN0610",
58	"ELAN0611",
59	"ELAN0612",
60	"ELAN0615",
61	"ELAN0616",
62	"ELAN0617",
63	"ELAN0618",
64	"ELAN0619",
65	"ELAN061A",
66	"ELAN061B",
67	"ELAN061C",
68	"ELAN061D",
69	"ELAN061E",
70	"ELAN061F",
71	"ELAN0620",
72	"ELAN0621",
73	"ELAN0622",
74	"ELAN0623",
75	"ELAN0624",
76	"ELAN0625",
77	"ELAN0626",
78	"ELAN0627",
79	"ELAN0628",
80	"ELAN0629",
81	"ELAN062A",
82	"ELAN062B",
83	"ELAN062C",
84	"ELAN062D",
85	"ELAN062E",	/* Lenovo V340 Whiskey Lake U */
86	"ELAN062F",	/* Lenovo V340 Comet Lake U */
87	"ELAN0631",
88	"ELAN0632",
89	"ELAN0633",	/* Lenovo S145 */
90	"ELAN0634",	/* Lenovo V340 Ice lake */
91	"ELAN0635",	/* Lenovo V1415-IIL */
92	"ELAN0636",	/* Lenovo V1415-Dali */
93	"ELAN0637",	/* Lenovo V1415-IGLR */
94	"ELAN1000"
95};
96
97static device_manager_info *sDeviceManager;
98
99DeviceList *gDeviceList = NULL;
100static mutex sDriverLock;
101
102
103// #pragma mark - driver hooks
104
105
106static status_t
107i2c_elan_init_device(void *driverCookie, void **cookie)
108{
109	*cookie = driverCookie;
110	return B_OK;
111}
112
113
114static void
115i2c_elan_uninit_device(void *_cookie)
116{
117
118}
119
120
121static status_t
122i2c_elan_open(void *initCookie, const char *path, int flags, void **_cookie)
123{
124	TRACE("open(%s, %" B_PRIu32 ", %p)\n", path, flags, _cookie);
125
126	elan_driver_cookie *cookie = new(std::nothrow) elan_driver_cookie();
127	if (cookie == NULL)
128		return B_NO_MEMORY;
129
130	MutexLocker locker(sDriverLock);
131
132	ELANDevice *elan = (ELANDevice *)gDeviceList->FindDevice(path);
133	TRACE("  path %s: handler %p (elan)\n", path, elan);
134
135	cookie->elanDevice = elan;
136
137	status_t result = elan == NULL ? B_ENTRY_NOT_FOUND : B_OK;
138	if (result == B_OK)
139		result = elan->Open(flags);
140
141	if (result != B_OK) {
142		delete cookie;
143		return result;
144	}
145
146	*_cookie = cookie;
147
148	return B_OK;
149}
150
151
152static status_t
153i2c_elan_read(void *_cookie, off_t position, void *buffer, size_t *numBytes)
154{
155	TRACE_ALWAYS("unhandled read on i2c_elan\n");
156	*numBytes = 0;
157	return B_ERROR;
158}
159
160
161static status_t
162i2c_elan_write(void *_cookie, off_t position, const void *buffer,
163	size_t *numBytes)
164{
165	TRACE_ALWAYS("unhandled write on i2c_elan\n");
166	*numBytes = 0;
167	return B_ERROR;
168}
169
170
171static status_t
172i2c_elan_control(void *_cookie, uint32 op, void *buffer, size_t length)
173{
174	elan_driver_cookie *cookie = (elan_driver_cookie *)_cookie;
175
176	TRACE("control(%p, %" B_PRIu32 ", %p, %" B_PRIuSIZE ")\n", cookie, op, buffer, length);
177	return cookie->elanDevice->Control(op, buffer, length);
178}
179
180
181static status_t
182i2c_elan_close(void *_cookie)
183{
184	elan_driver_cookie *cookie = (elan_driver_cookie *)_cookie;
185
186	TRACE("close(%p)\n", cookie);
187	return cookie->elanDevice->Close();
188}
189
190
191static status_t
192i2c_elan_free(void *_cookie)
193{
194	elan_driver_cookie *cookie = (elan_driver_cookie *)_cookie;
195	TRACE("free(%p)\n", cookie);
196
197	mutex_lock(&sDriverLock);
198
199	ELANDevice *device = cookie->elanDevice;
200	if (device->IsOpen()) {
201		// another handler of this device is still open so we can't free it
202	} else if (device->IsRemoved()) {
203		// the parent device is removed already and none of its handlers are
204		// open anymore so we can free it here
205		delete device;
206	}
207
208	mutex_unlock(&sDriverLock);
209
210	delete cookie;
211	return B_OK;
212}
213
214
215//	#pragma mark - driver module API
216
217static bool is_elan_name(const char *name) {
218	if (name == NULL)
219		return false;
220	for (unsigned i = 0; i < B_COUNT_OF(elan_iic_devs); i++)
221		if (strcmp(name, elan_iic_devs[i]) == 0)
222			return true;
223	return false;
224};
225
226static float
227i2c_elan_support(device_node *parent)
228{
229	CALLED();
230
231	// make sure parent is really the I2C bus manager
232	const char *bus;
233	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
234		return -1;
235
236	if (strcmp(bus, "i2c"))
237		return 0.0;
238	TRACE("i2c_elan_support found an i2c device %p\n", parent);
239
240	// check whether it's an ELAN device
241	uint64 handlePointer;
242	if (sDeviceManager->get_attr_uint64(parent, ACPI_DEVICE_HANDLE_ITEM,
243			&handlePointer, false) != B_OK) {
244		TRACE("i2c_elan_support found an i2c device without acpi handle\n");
245		return B_ERROR;
246	}
247
248	const char *name = nullptr;
249	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &name,
250					    false) == B_OK && is_elan_name(name)) {
251		TRACE("i2c_elan_support found an elan i2c device\n");
252		return 0.6;
253	}
254
255	if (sDeviceManager->get_attr_string(parent, ACPI_DEVICE_CID_ITEM, &name,
256		false) == B_OK && is_elan_name(name)) {
257		TRACE("i2c_elan_support found a compatible elan i2c device\n");
258		return 0.6;
259	}
260
261	return 0.0;
262}
263
264static status_t
265i2c_elan_register_device(device_node *node)
266{
267	CALLED();
268
269	device_attr attrs[] = {
270		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "I2C ELAN Device" }},
271		{ NULL }
272	};
273
274	return sDeviceManager->register_node(node, I2C_ELAN_DRIVER_NAME, attrs,
275		NULL, NULL);
276}
277
278
279static status_t
280i2c_elan_init_driver(device_node *node, void **driverCookie)
281{
282	CALLED();
283
284	elan_driver_cookie *device
285		= (elan_driver_cookie *)calloc(1, sizeof(elan_driver_cookie));
286	if (device == NULL)
287		return B_NO_MEMORY;
288
289	*driverCookie = device;
290
291	device_node *parent;
292	i2c_device_interface*	i2c;
293	i2c_device				i2c_cookie;
294
295	parent = sDeviceManager->get_parent_node(node);
296	sDeviceManager->get_driver(parent, (driver_module_info **)&i2c,
297		(void **)&i2c_cookie);
298	sDeviceManager->put_node(parent);
299
300	mutex_lock(&sDriverLock);
301	ELANDevice *elanDevice = new(std::nothrow) ELANDevice(node, i2c, i2c_cookie);
302
303	if (elanDevice != NULL && elanDevice->InitCheck() == B_OK) {
304		device->elanDevice = elanDevice;
305	} else
306		delete elanDevice;
307
308	mutex_unlock(&sDriverLock);
309
310	return device->elanDevice != NULL ? B_OK : B_IO_ERROR;
311}
312
313
314static void
315i2c_elan_uninit_driver(void *driverCookie)
316{
317	CALLED();
318	elan_driver_cookie *device = (elan_driver_cookie*)driverCookie;
319
320	free(device);
321}
322
323
324static status_t
325i2c_elan_register_child_devices(void *cookie)
326{
327	CALLED();
328	elan_driver_cookie *device = (elan_driver_cookie*)cookie;
329	ELANDevice* elanDevice = device->elanDevice;
330	if (elanDevice == NULL)
331		return B_OK;
332
333	// As devices can be un- and replugged at will, we cannot
334	// simply rely on a device count. If there is just one
335	// keyboard, this does not mean that it uses the 0 name.
336	// There might have been two keyboards and the one using 0
337	// might have been unplugged. So we just generate names
338	// until we find one that is not currently in use.
339	int32 index = 0;
340	char pathBuffer[128];
341	while (true) {
342		sprintf(pathBuffer, "input/mouse/" DEVICE_PATH_SUFFIX "/%" B_PRId32, index++);
343		if (gDeviceList->FindDevice(pathBuffer) == NULL) {
344			// this name is still free, use it
345			elanDevice->SetPublishPath(strdup(pathBuffer));
346			break;
347		}
348	}
349
350	gDeviceList->AddDevice(elanDevice->PublishPath(), elanDevice);
351
352	sDeviceManager->publish_device(device->elanDevice->Parent(), pathBuffer,
353		I2C_ELAN_DEVICE_NAME);
354
355	return B_OK;
356}
357
358
359static status_t
360std_ops(int32 op, ...)
361{
362	switch (op) {
363		case B_MODULE_INIT:
364			gDeviceList = new(std::nothrow) DeviceList();
365			if (gDeviceList == NULL) {
366				return B_NO_MEMORY;
367			}
368			mutex_init(&sDriverLock, "i2c elan driver lock");
369
370			return B_OK;
371		case B_MODULE_UNINIT:
372			delete gDeviceList;
373			gDeviceList = NULL;
374			mutex_destroy(&sDriverLock);
375			return B_OK;
376
377		default:
378			break;
379	}
380
381	return B_ERROR;
382}
383
384
385//	#pragma mark -
386
387
388driver_module_info i2c_elan_driver_module = {
389	{
390		I2C_ELAN_DRIVER_NAME,
391		0,
392		&std_ops
393	},
394
395	i2c_elan_support,
396	i2c_elan_register_device,
397	i2c_elan_init_driver,
398	i2c_elan_uninit_driver,
399	i2c_elan_register_child_devices,
400	NULL,	// rescan
401	NULL,	// removed
402};
403
404
405struct device_module_info i2c_elan_device_module = {
406	{
407		I2C_ELAN_DEVICE_NAME,
408		0,
409		NULL
410	},
411
412	i2c_elan_init_device,
413	i2c_elan_uninit_device,
414	NULL,
415
416	i2c_elan_open,
417	i2c_elan_close,
418	i2c_elan_free,
419	i2c_elan_read,
420	i2c_elan_write,
421	NULL,
422	i2c_elan_control,
423
424	NULL,
425	NULL
426};
427
428
429module_dependency module_dependencies[] = {
430	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
431	{}
432};
433
434
435module_info *modules[] = {
436	(module_info *)&i2c_elan_driver_module,
437	(module_info *)&i2c_elan_device_module,
438	NULL
439};
440