xref: /haiku/src/add-ons/input_server/devices/wacom/MasterServerDevice.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2005-2008 Stephan Aßmus <superstippi@gmx.de>. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  */
5 #include "MasterServerDevice.h"
6 
7 #include <fstream>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <Directory.h>
13 #include <Entry.h>
14 #include <InterfaceDefs.h>
15 #include <Message.h>
16 #include <NodeMonitor.h>
17 #include <OS.h>
18 #include <Path.h>
19 #include <Screen.h>
20 #include <View.h>
21 #include <File.h>
22 
23 #include "PointingDevice.h"
24 #include "PointingDeviceFactory.h"
25 
26 #define DEFAULT_CLICK_SPEED 250000
27 
28 static const char* kWatchFolder			= "input/wacom/usb";
29 static const char* kDeviceFolder		= "/dev/input/wacom/usb";
30 
31 //static const char* kPS2MouseThreadName	= "PS/2 Mouse";
32 
33 // instantiate_input_device
34 //
35 // this is where it all starts make sure this function is exported!
36 BInputServerDevice*
37 instantiate_input_device()
38 {
39 	return (new MasterServerDevice());
40 }
41 
42 // constructor
43 MasterServerDevice::MasterServerDevice()
44 	: BInputServerDevice(),
45 	  fDevices(1),
46 	  fActive(false),
47 	  fDblClickSpeed(DEFAULT_CLICK_SPEED),
48 	  fPS2DisablerThread(B_ERROR),
49 	  fDeviceLock("device list lock")
50 {
51 	get_mouse_speed(&fSpeed);
52 	get_mouse_acceleration(&fAcceleration);
53 	get_click_speed(&fDblClickSpeed);
54 	_CalculateAccelerationTable();
55 }
56 
57 // destructor
58 MasterServerDevice::~MasterServerDevice()
59 {
60 	// cleanup
61 	_StopAll();
62 	if (_LockDevices()) {
63 		while (PointingDevice* device = (PointingDevice*)fDevices.RemoveItem((int32)0))
64 			delete device;
65 		_UnlockDevices();
66 	}
67 }
68 
69 // InitCheck
70 status_t
71 MasterServerDevice::InitCheck()
72 {
73 	input_device_ref device = { (char *)"Wacom Tablets",
74 		B_POINTING_DEVICE, (void*)this };
75 	input_device_ref* deviceList[2] = { &device, NULL };
76 	RegisterDevices(deviceList);
77 
78 	return B_OK;
79 }
80 
81 // SystemShuttingDown
82 status_t
83 MasterServerDevice::SystemShuttingDown()
84 {
85 	// the devices should be stopped anyways,
86 	// but this is just defensive programming.
87 	// the pointing devices will have spawned polling threads,
88 	// we make sure that we block until every thread has bailed out.
89 
90 	_StopAll();
91 
92 	PRINT(("---------------------------------\n\n"));
93 
94 	return (BInputServerDevice::SystemShuttingDown());
95 }
96 
97 // Start
98 //
99 // start generating events
100 status_t
101 MasterServerDevice::Start(const char* device, void* cookie)
102 {
103 	if (_LockDevices()) {
104 		// do an initial scan of the devfs folder, after that, we should receive
105 		// node monitor messages for hotplugging support
106 		_SearchDevices();
107 
108 		fActive = true;
109 
110 		for (int32 i = 0; PointingDevice* device = (PointingDevice*)fDevices.ItemAt(i); i++) {
111 			device->Start();
112 		}
113 		_UnlockDevices();
114 	}
115 
116 	// TODO: make this configurable
117 //	_StartPS2DisablerThread();
118 
119 	return StartMonitoringDevice(kWatchFolder);
120 }
121 
122 // Stop
123 status_t
124 MasterServerDevice::Stop(const char* device, void* cookie)
125 {
126 	// stop generating events
127 	fActive = false;
128 
129 	_StopAll();
130 
131 //	_StopPS2DisablerThread();
132 
133 	return StopMonitoringDevice(kWatchFolder);
134 }
135 
136 // Control
137 status_t
138 MasterServerDevice::Control(const char* device, void* cookie, uint32 code, BMessage* message)
139 {
140 	// respond to changes in the system
141 	switch (code) {
142 		case B_MOUSE_SPEED_CHANGED:
143 			get_mouse_speed(&fSpeed);
144 			_CalculateAccelerationTable();
145 			break;
146 		case B_CLICK_SPEED_CHANGED:
147 			get_click_speed(&fDblClickSpeed);
148 			break;
149 		case B_MOUSE_ACCELERATION_CHANGED:
150 			get_mouse_acceleration(&fAcceleration);
151 			_CalculateAccelerationTable();
152 			break;
153 		case B_NODE_MONITOR:
154 			_HandleNodeMonitor(message);
155 			break;
156 		default:
157 			BInputServerDevice::Control(device, cookie, code, message);
158 			break;
159 	}
160 	return B_OK;
161 }
162 
163 // #pragma mark -
164 
165 // _SearchDevices
166 void
167 MasterServerDevice::_SearchDevices()
168 {
169 	if (_LockDevices()) {
170 		// construct a PointingDevice for every devfs entry we find
171 		BDirectory dir(kDeviceFolder);
172 		if (dir.InitCheck() >= B_OK) {
173 			// traverse the contents of the folder to see if the
174 			// entry of that device still exists
175 			entry_ref ref;
176 			while (dir.GetNextRef(&ref) >= B_OK) {
177 				PRINT(("examining devfs entry '%s'\n", ref.name));
178 				// don't add the control device
179 				if (strcmp(ref.name, "control") != 0) {
180 					BPath path(&ref);
181 					if (path.InitCheck() >= B_OK) {
182 						// add the device
183 						_AddDevice(path.Path());
184 					}
185 				}
186 			}
187 		} else
188 			PRINT(("folder '%s' not found\n", kDeviceFolder));
189 
190 		PRINT(("done examing devfs\n"));
191 		_UnlockDevices();
192 	}
193 }
194 
195 // _StopAll
196 void
197 MasterServerDevice::_StopAll()
198 {
199 	if (_LockDevices()) {
200 		for (int32 i = 0; PointingDevice* device
201 				= (PointingDevice*)fDevices.ItemAt(i); i++)
202 			device->Stop();
203 		_UnlockDevices();
204 	}
205 }
206 
207 // _AddDevice
208 void
209 MasterServerDevice::_AddDevice(const char* path)
210 {
211 	if (_LockDevices()) {
212 		// get the device from the factory
213 		PointingDevice* device = PointingDeviceFactory::DeviceFor(this, path);
214 		// add it to our list
215 		if (device && device->InitCheck() >= B_OK
216 			&& fDevices.AddItem((void*)device)) {
217 			PRINT(("pointing device added (%s)\n", path));
218 			// start device polling only if we're started
219 			if (fActive)
220 				device->Start();
221 		} else {
222 
223 			PRINT(("pointing device not added (%s)\n", path));
224 			if (device) {
225 				PRINT(("  vendor: %0*x, product: %0*x\n", 4, device->VendorID(),
226 					4, device->ProductID()));
227 			}
228 
229 			delete device;
230 		}
231 		_UnlockDevices();
232 	}
233 }
234 
235 // _HandleNodeMonitor
236 void
237 MasterServerDevice::_HandleNodeMonitor(BMessage* message)
238 {
239 	int32 opcode;
240 	if (message->FindInt32("opcode", &opcode) < B_OK)
241 		return;
242 
243 	switch (opcode) {
244 		case B_ENTRY_CREATED:
245 			// extract info to create an entry_ref structure
246 			const char* name;
247 			ino_t directory;
248 			dev_t device;
249 			if (message->FindString("name", &name) >= B_OK
250 				&& strcmp(name, "control") != 0
251 				&& message->FindInt64("directory", (int64*)&directory) >= B_OK
252 				&& message->FindInt32("device", (int32*)&device) >= B_OK) {
253 				// make a path from that info
254 				entry_ref ref(device, directory, name);
255 				BPath path(&ref);
256 				if (path.InitCheck() >= B_OK) {
257 					// add the device
258 					_AddDevice(path.Path());
259 				}
260 			}
261 			break;
262 		case B_ENTRY_REMOVED: {
263 			// I cannot figure out how to see if this is actually
264 			// the directory that we're node monitoring, and even if it is,
265 			// we would have to look at the directories contents to
266 			// see which PointingDevice we might want to remove
267 			BDirectory dir(kDeviceFolder);
268 			if (dir.InitCheck() >= B_OK) {
269 				// for each device in our list, see if the corresponding
270 				// entry in the device folder still exists
271 				for (int32 i = 0; PointingDevice* pointingDevice
272 						= (PointingDevice*)fDevices.ItemAt(i); i++) {
273 					// traverse the contents of the folder
274 					// if the entry for this device is there,
275 					// we can abort the search
276 					entry_ref ref;
277 					dir.Rewind();
278 					bool found = false;
279 					while (dir.GetNextRef(&ref) >= B_OK) {
280 						BPath path(&ref);
281 						if (strcmp(pointingDevice->DevicePath(),
282 								path.Path()) == 0) {
283 							found = true;
284 							break;
285 						}
286 					}
287 					// remove the device if the devfs entry was not found
288 					if (!found) {
289 
290 						PRINT(("removing device '%s'\n", pointingDevice->DevicePath()));
291 
292 						if (_LockDevices()) {
293 							if (fDevices.RemoveItem((void*)pointingDevice)) {
294 
295 								delete pointingDevice;
296 								i--;
297 							}
298 							_UnlockDevices();
299 						}
300 					}
301 				}
302 			}
303 			break;
304 		}
305 	}
306 }
307 
308 // _CalculateAccelerationTable
309 //
310 // calculates the acceleration table. This is recalculated anytime we find out that
311 // the current acceleration or speed has changed.
312 void
313 MasterServerDevice::_CalculateAccelerationTable()
314 {
315 	// This seems to work alright.
316 	for (int x = 1; x <= 128; x++){
317 		fAccelerationTable[x] = (x / (128 * (1 - (((float)fSpeed + 8192) / 262144))))
318 			* (x / (128 * (1 - (((float)fSpeed + 8192) / 262144))))
319 			+ ((((float)fAcceleration + 4000) / 262144)
320 			* (x / (128 * (1 - (((float)fSpeed + 8192) / 262144)))));
321 	}
322 
323 	// sets the bottom of the table to be the inverse of the first half.
324 	// position 0 -> 128 positive movement, 255->129 negative movement
325 	for (int x = 255; x > 128; x--){
326 		fAccelerationTable[x] = -(fAccelerationTable[(255 - x)]);
327 	}
328 
329 	// Location 0 will be 0.000, which is unacceptable, otherwise, single step moves are lost
330 	// To work around this, we'll make it 1/2 of the smallest increment.
331 	fAccelerationTable[0] = fAccelerationTable[1] / 2;
332 	fAccelerationTable[255] = -fAccelerationTable[0];
333 }
334 
335 // _ps2_disabler
336 //
337 // find the PS/2 device thread and suspend its execution
338 // TODO: make this configurable
339 // In case you're wondering... this behaviour is useful for notebook
340 // users who are annoyed by accidentally hitting their touchpad while
341 // typing. "Turning it off entirely" by suspending the PS/2 thread is
342 // just a compfort thing, but should of course be made configurable...
343 //int32
344 //MasterServerDevice::_ps2_disabler(void* cookie)
345 //{
346 //	MasterServerDevice* master = (MasterServerDevice*)cookie;
347 //
348 //	thread_id haltedThread = B_ERROR;
349 //
350 //	while (master->fActive) {
351 //		// search for at least one running device
352 //		bool suspendPS2 = false;
353 //		if (master->_LockDevices()) {
354 //			for (int32 i = 0; PointingDevice* device = (PointingDevice*)master->fDevices.ItemAt(i); i++) {
355 //				if (device->DisablePS2()) {
356 //					suspendPS2 = true;
357 //					break;
358 //				}
359 //			}
360 //			master->_UnlockDevices();
361 //		}
362 //
363 //		if (suspendPS2){
364 //			// find and suspend PS/2 thread (if not already done)
365 //			if (haltedThread < B_OK) {
366 //				haltedThread = find_thread(kPS2MouseThreadName);
367 //				if (haltedThread >= B_OK) {
368 //					suspend_thread(haltedThread);
369 //				}
370 //			}
371 //		} else {
372 //			// reenable PS/2 thread
373 //			if (haltedThread >= B_OK) {
374 //				resume_thread(haltedThread);
375 //				haltedThread = B_ERROR;
376 //			}
377 //		}
378 //
379 //		// sleep a little while
380 //		snooze(2000000);
381 //	}
382 //
383 //	// reenable PS/2 thread in any case before we die
384 //	if (haltedThread >= B_OK) {
385 //		resume_thread(haltedThread);
386 //	}
387 //
388 //	return B_OK;
389 //}
390 //
391 //// _StartPS2DisablerThread
392 //void
393 //MasterServerDevice::_StartPS2DisablerThread()
394 //{
395 //	if (fPS2DisablerThread < B_OK) {
396 //		fPS2DisablerThread = spawn_thread(_ps2_disabler, "PS/2 Mouse disabler", B_LOW_PRIORITY, this);
397 //		if (fPS2DisablerThread >= B_OK)
398 //			resume_thread(fPS2DisablerThread);
399 //	}
400 //}
401 //
402 //// _StopPS2DisablerThread
403 //void
404 //MasterServerDevice::_StopPS2DisablerThread()
405 //{
406 //	if (fPS2DisablerThread >= B_OK) {
407 //		status_t err;
408 //		wait_for_thread(fPS2DisablerThread, &err);
409 //	}
410 //	fPS2DisablerThread = B_ERROR;
411 //}
412 
413 // _LockDevices
414 bool
415 MasterServerDevice::_LockDevices()
416 {
417 	return fDeviceLock.Lock();
418 }
419 
420 // _UnlockDevices
421 void
422 MasterServerDevice::_UnlockDevices()
423 {
424 	fDeviceLock.Unlock();
425 }
426 
427