xref: /haiku/src/add-ons/kernel/drivers/input/usb_hid/Driver.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
1 /*
2  * Copyright 2008-2011 Michael Lotz <mmlr@mlotz.ch>
3  * Distributed under the terms of the MIT license.
4  */
5 
6 
7 //!	Driver for USB Human Interface Devices.
8 
9 
10 #include "DeviceList.h"
11 #include "Driver.h"
12 #include "HIDDevice.h"
13 #include "ProtocolHandler.h"
14 #include "QuirkyDevices.h"
15 
16 #include <lock.h>
17 #include <util/AutoLock.h>
18 
19 #include <new>
20 #include <stdio.h>
21 #include <string.h>
22 
23 
24 struct device_cookie {
25 	ProtocolHandler*	handler;
26 	uint32				cookie;
27 };
28 
29 
30 int32 api_version = B_CUR_DRIVER_API_VERSION;
31 usb_module_info *gUSBModule = NULL;
32 DeviceList *gDeviceList = NULL;
33 static int32 sParentCookie = 0;
34 static mutex sDriverLock;
35 static usb_support_descriptor *sSupportDescriptors;
36 
37 
38 // #pragma mark - notify hooks
39 
40 
41 status_t
42 usb_hid_device_added(usb_device device, void **cookie)
43 {
44 	TRACE("device_added()\n");
45 	const usb_device_descriptor *deviceDescriptor
46 		= gUSBModule->get_device_descriptor(device);
47 
48 	TRACE("vendor id: 0x%04x; product id: 0x%04x\n",
49 		deviceDescriptor->vendor_id, deviceDescriptor->product_id);
50 
51 	// wacom devices are handled by the dedicated wacom driver
52 	if (deviceDescriptor->vendor_id == USB_VENDOR_WACOM)
53 		return B_ERROR;
54 
55 	const usb_configuration_info *config
56 		= gUSBModule->get_nth_configuration(device, USB_DEFAULT_CONFIGURATION);
57 	if (config == NULL) {
58 		TRACE_ALWAYS("cannot get default configuration\n");
59 		return B_ERROR;
60 	}
61 
62 	// ensure default configuration is set
63 	status_t result = gUSBModule->set_configuration(device, config);
64 	if (result != B_OK) {
65 		TRACE_ALWAYS("set_configuration() failed 0x%08lx\n", result);
66 		return result;
67 	}
68 
69 	// refresh config
70 	config = gUSBModule->get_configuration(device);
71 	if (config == NULL) {
72 		TRACE_ALWAYS("cannot get current configuration\n");
73 		return B_ERROR;
74 	}
75 
76 	bool devicesFound = false;
77 	int32 parentCookie = atomic_add(&sParentCookie, 1);
78 	for (size_t i = 0; i < config->interface_count; i++) {
79 		const usb_interface_info *interface = config->interface[i].active;
80 		uint8 interfaceClass = interface->descr->interface_class;
81 		TRACE("interface %lu: class: %u; subclass: %u; protocol: %u\n",
82 			i, interfaceClass, interface->descr->interface_subclass,
83 			interface->descr->interface_protocol);
84 
85 		// check for quirky devices first
86 		int32 quirkyIndex = -1;
87 		for (int32 j = 0; j < gQuirkyDeviceCount; j++) {
88 			usb_hid_quirky_device &quirky = gQuirkyDevices[j];
89 			if ((quirky.vendor_id != 0
90 					&& deviceDescriptor->vendor_id != quirky.vendor_id)
91 				|| (quirky.product_id != 0
92 					&& deviceDescriptor->product_id != quirky.product_id)
93 				|| (quirky.device_class != 0
94 					&& interfaceClass != quirky.device_class)
95 				|| (quirky.device_subclass != 0
96 					&& interface->descr->interface_subclass
97 						!= quirky.device_subclass)
98 				|| (quirky.device_protocol != 0
99 					&& interface->descr->interface_protocol
100 						!= quirky.device_protocol)) {
101 				continue;
102 			}
103 
104 			quirkyIndex = j;
105 			break;
106 		}
107 
108 		if (quirkyIndex >= 0 || interfaceClass == USB_INTERFACE_CLASS_HID) {
109 			mutex_lock(&sDriverLock);
110 			HIDDevice *hidDevice
111 				= new(std::nothrow) HIDDevice(device, config, i, quirkyIndex);
112 
113 			if (hidDevice != NULL && hidDevice->InitCheck() == B_OK) {
114 				hidDevice->SetParentCookie(parentCookie);
115 
116 				for (uint32 i = 0;; i++) {
117 					ProtocolHandler *handler = hidDevice->ProtocolHandlerAt(i);
118 					if (handler == NULL)
119 						break;
120 
121 					// As devices can be un- and replugged at will, we cannot
122 					// simply rely on a device count. If there is just one
123 					// keyboard, this does not mean that it uses the 0 name.
124 					// There might have been two keyboards and the one using 0
125 					// might have been unplugged. So we just generate names
126 					// until we find one that is not currently in use.
127 					int32 index = 0;
128 					char pathBuffer[128];
129 					const char *basePath = handler->BasePath();
130 					while (true) {
131 						sprintf(pathBuffer, "%s%ld", basePath, index++);
132 						if (gDeviceList->FindDevice(pathBuffer) == NULL) {
133 							// this name is still free, use it
134 							handler->SetPublishPath(strdup(pathBuffer));
135 							break;
136 						}
137 					}
138 
139 					gDeviceList->AddDevice(handler->PublishPath(), handler);
140 					devicesFound = true;
141 				}
142 			} else
143 				delete hidDevice;
144 
145 			mutex_unlock(&sDriverLock);
146 		}
147 	}
148 
149 	if (!devicesFound)
150 		return B_ERROR;
151 
152 	*cookie = (void *)parentCookie;
153 	return B_OK;
154 }
155 
156 
157 status_t
158 usb_hid_device_removed(void *cookie)
159 {
160 	mutex_lock(&sDriverLock);
161 	int32 parentCookie = (int32)cookie;
162 	TRACE("device_removed(%ld)\n", parentCookie);
163 
164 	for (int32 i = 0; i < gDeviceList->CountDevices(); i++) {
165 		ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->DeviceAt(i);
166 		if (!handler)
167 			continue;
168 
169 		HIDDevice *device = handler->Device();
170 		if (device->ParentCookie() != parentCookie)
171 			continue;
172 
173 		// this handler's device belongs to the one removed
174 		if (device->IsOpen()) {
175 			// the device and it's handlers will be deleted in the free hook
176 			device->Removed();
177 			break;
178 		}
179 
180 		// remove all the handlers
181 		for (uint32 i = 0;; i++) {
182 			handler = device->ProtocolHandlerAt(i);
183 			if (handler == NULL)
184 				break;
185 
186 			gDeviceList->RemoveDevice(NULL, handler);
187 		}
188 
189 		delete device;
190 		break;
191 	}
192 
193 	mutex_unlock(&sDriverLock);
194 	return B_OK;
195 }
196 
197 
198 // #pragma mark - driver hooks
199 
200 
201 static status_t
202 usb_hid_open(const char *name, uint32 flags, void **_cookie)
203 {
204 	TRACE("open(%s, %lu, %p)\n", name, flags, _cookie);
205 
206 	device_cookie *cookie = new(std::nothrow) device_cookie();
207 	if (cookie == NULL)
208 		return B_NO_MEMORY;
209 
210 	MutexLocker locker(sDriverLock);
211 
212 	ProtocolHandler *handler = (ProtocolHandler *)gDeviceList->FindDevice(name);
213 	TRACE("  name %s: handler %p\n", name, handler);
214 
215 	cookie->handler = handler;
216 	cookie->cookie = 0;
217 
218 	status_t result = handler == NULL ? B_ENTRY_NOT_FOUND : B_OK;
219 	if (result == B_OK)
220 		result = handler->Open(flags, &cookie->cookie);
221 
222 	if (result != B_OK) {
223 		delete cookie;
224 		return result;
225 	}
226 
227 	*_cookie = cookie;
228 
229 	return B_OK;
230 }
231 
232 
233 static status_t
234 usb_hid_read(void *_cookie, off_t position, void *buffer, size_t *numBytes)
235 {
236 	device_cookie *cookie = (device_cookie *)_cookie;
237 
238 	TRACE("read(%p, %llu, %p, %p (%lu)\n", cookie, position, buffer, numBytes,
239 		numBytes != NULL ? *numBytes : 0);
240 	return cookie->handler->Read(&cookie->cookie, position, buffer, numBytes);
241 }
242 
243 
244 static status_t
245 usb_hid_write(void *_cookie, off_t position, const void *buffer,
246 	size_t *numBytes)
247 {
248 	device_cookie *cookie = (device_cookie *)_cookie;
249 
250 	TRACE("write(%p, %llu, %p, %p (%lu)\n", cookie, position, buffer, numBytes,
251 		numBytes != NULL ? *numBytes : 0);
252 	return cookie->handler->Write(&cookie->cookie, position, buffer, numBytes);
253 }
254 
255 
256 static status_t
257 usb_hid_control(void *_cookie, uint32 op, void *buffer, size_t length)
258 {
259 	device_cookie *cookie = (device_cookie *)_cookie;
260 
261 	TRACE("control(%p, %lu, %p, %lu)\n", cookie, op, buffer, length);
262 	return cookie->handler->Control(&cookie->cookie, op, buffer, length);
263 }
264 
265 
266 static status_t
267 usb_hid_close(void *_cookie)
268 {
269 	device_cookie *cookie = (device_cookie *)_cookie;
270 
271 	TRACE("close(%p)\n", cookie);
272 	return cookie->handler->Close(&cookie->cookie);
273 }
274 
275 
276 static status_t
277 usb_hid_free(void *_cookie)
278 {
279 	device_cookie *cookie = (device_cookie *)_cookie;
280 	TRACE("free(%p)\n", cookie);
281 
282 	mutex_lock(&sDriverLock);
283 
284 	HIDDevice *device = cookie->handler->Device();
285 	if (device->IsOpen()) {
286 		// another handler of this device is still open so we can't free it
287 	} else if (device->IsRemoved()) {
288 		// the parent device is removed already and none of its handlers are
289 		// open anymore so we can free it here
290 		for (uint32 i = 0;; i++) {
291 			ProtocolHandler *handler = device->ProtocolHandlerAt(i);
292 			if (handler == NULL)
293 				break;
294 
295 			gDeviceList->RemoveDevice(NULL, handler);
296 		}
297 
298 		delete device;
299 	}
300 
301 	mutex_unlock(&sDriverLock);
302 
303 	delete cookie;
304 	return B_OK;
305 }
306 
307 
308 //	#pragma mark - driver API
309 
310 
311 status_t
312 init_hardware()
313 {
314 	TRACE("init_hardware() " __DATE__ " " __TIME__ "\n");
315 	return B_OK;
316 }
317 
318 
319 status_t
320 init_driver()
321 {
322 	TRACE("init_driver() " __DATE__ " " __TIME__ "\n");
323 	if (get_module(B_USB_MODULE_NAME, (module_info **)&gUSBModule) != B_OK)
324 		return B_ERROR;
325 
326 	gDeviceList = new(std::nothrow) DeviceList();
327 	if (gDeviceList == NULL) {
328 		put_module(B_USB_MODULE_NAME);
329 		return B_NO_MEMORY;
330 	}
331 
332 	mutex_init(&sDriverLock, "usb hid driver lock");
333 
334 	static usb_notify_hooks notifyHooks = {
335 		&usb_hid_device_added,
336 		&usb_hid_device_removed
337 	};
338 
339 	static usb_support_descriptor genericHIDSupportDescriptor = {
340 		USB_INTERFACE_CLASS_HID, 0, 0, 0, 0
341 	};
342 
343 	int32 supportDescriptorCount = 1 + gQuirkyDeviceCount;
344 	sSupportDescriptors
345 		= new(std::nothrow) usb_support_descriptor[supportDescriptorCount];
346 	if (sSupportDescriptors != NULL) {
347 		sSupportDescriptors[0] = genericHIDSupportDescriptor;
348 		for (int32 i = 0; i < gQuirkyDeviceCount; i++) {
349 			usb_support_descriptor &descriptor = sSupportDescriptors[i + 1];
350 			descriptor.dev_class = gQuirkyDevices[i].device_class;
351 			descriptor.dev_subclass = gQuirkyDevices[i].device_subclass;
352 			descriptor.dev_protocol = gQuirkyDevices[i].device_protocol;
353 			descriptor.vendor = gQuirkyDevices[i].vendor_id;
354 			descriptor.product = gQuirkyDevices[i].product_id;
355 		}
356 
357 		gUSBModule->register_driver(DRIVER_NAME, sSupportDescriptors,
358 			supportDescriptorCount, NULL);
359 	} else {
360 		// no memory for quirky devices, at least support proper HID
361 		gUSBModule->register_driver(DRIVER_NAME, &genericHIDSupportDescriptor,
362 			1, NULL);
363 	}
364 
365 	gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
366 	TRACE("init_driver() OK\n");
367 	return B_OK;
368 }
369 
370 
371 void
372 uninit_driver()
373 {
374 	TRACE("uninit_driver()\n");
375 	gUSBModule->uninstall_notify(DRIVER_NAME);
376 	put_module(B_USB_MODULE_NAME);
377 	delete[] sSupportDescriptors;
378 	sSupportDescriptors = NULL;
379 	delete gDeviceList;
380 	gDeviceList = NULL;
381 	mutex_destroy(&sDriverLock);
382 }
383 
384 
385 const char **
386 publish_devices()
387 {
388 	TRACE("publish_devices()\n");
389 	const char **publishList = gDeviceList->PublishDevices();
390 
391 	int32 index = 0;
392 	while (publishList[index] != NULL) {
393 		TRACE("publishing %s\n", publishList[index]);
394 		index++;
395 	}
396 
397 	return publishList;
398 }
399 
400 
401 device_hooks *
402 find_device(const char *name)
403 {
404 	static device_hooks hooks = {
405 		usb_hid_open,
406 		usb_hid_close,
407 		usb_hid_free,
408 		usb_hid_control,
409 		usb_hid_read,
410 		usb_hid_write,
411 		NULL,				/* select */
412 		NULL				/* deselect */
413 	};
414 
415 	TRACE("find_device(%s)\n", name);
416 	if (gDeviceList->FindDevice(name) == NULL) {
417 		TRACE_ALWAYS("didn't find device %s\n", name);
418 		return NULL;
419 	}
420 
421 	return &hooks;
422 }
423