* Ignore B_ENTRY_REMOVED node monitor messages.
* When the device watcher/control thread encounteres an error when read()ing or ioctl()ing the device, don't just quit the thread and leave a stale device add-on hanging there, but instead trigger _RemoveDevice() to exit this cleanly. This also takes care of calling _RemoveDevice() only from one thread. However, it adds a race condition should a mouse or keyboard be unplugged and plugged at the same time. I need to think about how to fix that cleanly, although the situation may be theoretical only... This fix seems to fix another problem with hot-plugging USB mice, before this change, the first mouse entry in /dev/input/mouse/usb/ was never gone and I got two entries after unplugging and replugging. * When using BObjectList configured to own the entries - don't delete the entries! Also don't call RemoveItem() before still using the item. Took me all day to find this one, because the code looked so... correct. :-} * In _AddDevice() call _RemoveDevice() just for the sake of it. It is really important that no device with the same name is published twice. The PS/2 driver behaves strange in that it publishes device more than once, if I understand correctly, until it decides that there is no device. * Only StartMonitoringDevice() /after/ having performed the initial device scan! Or else we may get ourselves confused. I don't know if this was an actual problem, but the code was like that before and it seems saner to me. Seeing there is no locking in the device add-on itself, we may already enter the code from the node monitor thread. This should fix #2894. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28321 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -379,8 +379,8 @@ KeyboardInputDevice::KeyboardInputDevice()
|
|||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
StartMonitoringDevice(kKeyboardDevicesDirectory);
|
|
||||||
_RecursiveScan(kKeyboardDevicesDirectory);
|
_RecursiveScan(kKeyboardDevicesDirectory);
|
||||||
|
StartMonitoringDevice(kKeyboardDevicesDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -525,14 +525,32 @@ KeyboardInputDevice::_HandleMonitor(BMessage* message)
|
|||||||
const char* path;
|
const char* path;
|
||||||
int32 opcode;
|
int32 opcode;
|
||||||
if (message->FindInt32("opcode", &opcode) != B_OK
|
if (message->FindInt32("opcode", &opcode) != B_OK
|
||||||
|| opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED
|
|| (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
|
||||||
|| message->FindString("path", &path) != B_OK)
|
|| message->FindString("path", &path) != B_OK)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (opcode == B_ENTRY_CREATED)
|
if (opcode == B_ENTRY_CREATED)
|
||||||
return _AddDevice(path);
|
return _AddDevice(path);
|
||||||
|
|
||||||
|
#if 0
|
||||||
return _RemoveDevice(path);
|
return _RemoveDevice(path);
|
||||||
|
#else
|
||||||
|
// Don't handle B_ENTRY_REMOVED, let the control thread take care of it.
|
||||||
|
return B_OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
keyboard_device*
|
||||||
|
KeyboardInputDevice::_FindDevice(const char* path) const
|
||||||
|
{
|
||||||
|
for (int i = fDevices.CountItems() - 1; i >= 0; i--) {
|
||||||
|
keyboard_device* device = fDevices.ItemAt(i);
|
||||||
|
if (strcmp(device->path, path) == 0)
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -540,6 +558,9 @@ status_t
|
|||||||
KeyboardInputDevice::_AddDevice(const char* path)
|
KeyboardInputDevice::_AddDevice(const char* path)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
_RemoveDevice(path);
|
||||||
|
|
||||||
keyboard_device* device = new(std::nothrow) keyboard_device(path);
|
keyboard_device* device = new(std::nothrow) keyboard_device(path);
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@@ -560,22 +581,20 @@ status_t
|
|||||||
KeyboardInputDevice::_RemoveDevice(const char* path)
|
KeyboardInputDevice::_RemoveDevice(const char* path)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
keyboard_device* device;
|
|
||||||
for (int i = 0; (device = fDevices.ItemAt(i)) != NULL; i++) {
|
|
||||||
if (!strcmp(device->path, path)) {
|
|
||||||
fDevices.RemoveItemAt(i);
|
|
||||||
|
|
||||||
input_device_ref* devices[2];
|
keyboard_device* device = _FindDevice(path);
|
||||||
devices[0] = &device->device_ref;
|
if (device == NULL)
|
||||||
devices[1] = NULL;
|
return B_ENTRY_NOT_FOUND;
|
||||||
UnregisterDevices(devices);
|
|
||||||
|
|
||||||
delete device;
|
input_device_ref* devices[2];
|
||||||
return B_OK;
|
devices[0] = &device->device_ref;
|
||||||
}
|
devices[1] = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
UnregisterDevices(devices);
|
||||||
|
|
||||||
|
fDevices.RemoveItem(device);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -598,8 +617,12 @@ KeyboardInputDevice::_DeviceWatcher(void* arg)
|
|||||||
LOG("%s\n", __PRETTY_FUNCTION__);
|
LOG("%s\n", __PRETTY_FUNCTION__);
|
||||||
|
|
||||||
while (device->active) {
|
while (device->active) {
|
||||||
if (ioctl(device->fd, KB_READ, &buffer) != B_OK)
|
if (ioctl(device->fd, KB_READ, &buffer) != B_OK) {
|
||||||
|
device->device_watcher = -1;
|
||||||
|
device->owner->_RemoveDevice(device->path);
|
||||||
|
// TOAST!
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 keycode = 0;
|
uint32 keycode = 0;
|
||||||
bool isKeyDown = false;
|
bool isKeyDown = false;
|
||||||
@@ -697,7 +720,7 @@ KeyboardInputDevice::_DeviceWatcher(void* arg)
|
|||||||
msg->AddInt32("modifiers", device->modifiers);
|
msg->AddInt32("modifiers", device->modifiers);
|
||||||
msg->AddData("states", B_UINT8_TYPE, states, 16);
|
msg->AddData("states", B_UINT8_TYPE, states, 16);
|
||||||
|
|
||||||
if (owner->EnqueueMessage(msg)!=B_OK)
|
if (owner->EnqueueMessage(msg) != B_OK)
|
||||||
delete msg;
|
delete msg;
|
||||||
|
|
||||||
if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
|
if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
|
||||||
@@ -717,8 +740,8 @@ KeyboardInputDevice::_DeviceWatcher(void* arg)
|
|||||||
|
|
||||||
BMessage* msg = new BMessage;
|
BMessage* msg = new BMessage;
|
||||||
if (msg == NULL) {
|
if (msg == NULL) {
|
||||||
free(string);
|
delete[] string;
|
||||||
free(rawString);
|
delete[] rawString;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,10 +60,15 @@ public:
|
|||||||
virtual status_t SystemShuttingDown();
|
virtual status_t SystemShuttingDown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend struct keyboard_device;
|
||||||
|
// TODO: needed by the control thread to remove a dead device
|
||||||
|
// find a better way...
|
||||||
|
|
||||||
status_t _HandleMonitor(BMessage* message);
|
status_t _HandleMonitor(BMessage* message);
|
||||||
status_t _InitFromSettings(void* cookie, uint32 opcode = 0);
|
status_t _InitFromSettings(void* cookie, uint32 opcode = 0);
|
||||||
void _RecursiveScan(const char* directory);
|
void _RecursiveScan(const char* directory);
|
||||||
|
|
||||||
|
keyboard_device* _FindDevice(const char* path) const;
|
||||||
status_t _AddDevice(const char* path);
|
status_t _AddDevice(const char* path);
|
||||||
status_t _RemoveDevice(const char* path);
|
status_t _RemoveDevice(const char* path);
|
||||||
|
|
||||||
|
|||||||
@@ -38,16 +38,20 @@
|
|||||||
# define LOG_ERR(text...) debug_printf(text)
|
# define LOG_ERR(text...) debug_printf(text)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//#define LOG_DEVICES(text...) debug_printf(text)
|
||||||
|
#define LOG_DEVICES(text...) LOG(text)
|
||||||
|
|
||||||
#define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
|
#define CALLED() LOG("%s\n", __PRETTY_FUNCTION__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
|
const static uint32 kMouseThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
|
||||||
const static char* kMouseDevicesDirectory = "/dev/input/mouse";
|
const static char* kMouseDevicesDirectory = "/dev/input/mouse";
|
||||||
|
|
||||||
|
|
||||||
class MouseDevice {
|
class MouseDevice {
|
||||||
public:
|
public:
|
||||||
MouseDevice(BInputServerDevice& target, const char* path);
|
MouseDevice(MouseInputDevice& target, const char* path);
|
||||||
~MouseDevice();
|
~MouseDevice();
|
||||||
|
|
||||||
status_t Start();
|
status_t Start();
|
||||||
@@ -71,16 +75,16 @@ class MouseDevice {
|
|||||||
char* _BuildShortName() const;
|
char* _BuildShortName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BInputServerDevice& fTarget;
|
MouseInputDevice& fTarget;
|
||||||
BString fPath;
|
BString fPath;
|
||||||
int fDevice;
|
int fDevice;
|
||||||
|
|
||||||
input_device_ref fDeviceRef;
|
input_device_ref fDeviceRef;
|
||||||
mouse_settings fSettings;
|
mouse_settings fSettings;
|
||||||
bool fDeviceRemapsButtons;
|
bool fDeviceRemapsButtons;
|
||||||
|
|
||||||
thread_id fThread;
|
thread_id fThread;
|
||||||
volatile bool fActive;
|
volatile bool fActive;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -94,15 +98,14 @@ instantiate_input_device()
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
MouseDevice::MouseDevice(BInputServerDevice& target, const char* driverPath)
|
MouseDevice::MouseDevice(MouseInputDevice& target, const char* driverPath)
|
||||||
:
|
:
|
||||||
fTarget(target),
|
fTarget(target),
|
||||||
|
fPath(driverPath),
|
||||||
fDevice(-1),
|
fDevice(-1),
|
||||||
fThread(-1),
|
fThread(-1),
|
||||||
fActive(false)
|
fActive(false)
|
||||||
{
|
{
|
||||||
fPath = driverPath;
|
|
||||||
|
|
||||||
fDeviceRef.name = _BuildShortName();
|
fDeviceRef.name = _BuildShortName();
|
||||||
fDeviceRef.type = B_POINTING_DEVICE;
|
fDeviceRef.type = B_POINTING_DEVICE;
|
||||||
fDeviceRef.cookie = this;
|
fDeviceRef.cookie = this;
|
||||||
@@ -230,8 +233,12 @@ MouseDevice::_Run()
|
|||||||
mouse_movement movements;
|
mouse_movement movements;
|
||||||
memset(&movements, 0, sizeof(movements));
|
memset(&movements, 0, sizeof(movements));
|
||||||
|
|
||||||
if (ioctl(fDevice, MS_READ, &movements) != B_OK)
|
if (ioctl(fDevice, MS_READ, &movements) != B_OK) {
|
||||||
|
fThread = -1;
|
||||||
|
fTarget._RemoveDevice(fPath.String());
|
||||||
|
// TOAST!
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 buttons = lastButtons ^ movements.buttons;
|
uint32 buttons = lastButtons ^ movements.buttons;
|
||||||
|
|
||||||
@@ -244,8 +251,6 @@ MouseDevice::_Run()
|
|||||||
movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
|
movements.clicks, movements.wheel_xdelta, movements.wheel_ydelta);
|
||||||
LOG("%s: x: %ld, y: %ld\n", fDeviceRef.name, deltaX, deltaY);
|
LOG("%s: x: %ld, y: %ld\n", fDeviceRef.name, deltaX, deltaY);
|
||||||
|
|
||||||
BMessage* message = NULL;
|
|
||||||
|
|
||||||
// Send single messages for each event
|
// Send single messages for each event
|
||||||
|
|
||||||
if (buttons != 0) {
|
if (buttons != 0) {
|
||||||
@@ -273,7 +278,7 @@ MouseDevice::_Run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
|
if ((movements.wheel_ydelta != 0) || (movements.wheel_xdelta != 0)) {
|
||||||
message = new BMessage(B_MOUSE_WHEEL_CHANGED);
|
BMessage* message = new BMessage(B_MOUSE_WHEEL_CHANGED);
|
||||||
if (message == NULL)
|
if (message == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -405,8 +410,8 @@ MouseInputDevice::MouseInputDevice()
|
|||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
StartMonitoringDevice(kMouseDevicesDirectory);
|
|
||||||
_RecursiveScan(kMouseDevicesDirectory);
|
_RecursiveScan(kMouseDevicesDirectory);
|
||||||
|
StartMonitoringDevice(kMouseDevicesDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -464,7 +469,6 @@ MouseInputDevice::Control(const char* name, void* cookie,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: Test this. USB doesn't work on my machine
|
|
||||||
status_t
|
status_t
|
||||||
MouseInputDevice::_HandleMonitor(BMessage* message)
|
MouseInputDevice::_HandleMonitor(BMessage* message)
|
||||||
{
|
{
|
||||||
@@ -473,14 +477,19 @@ MouseInputDevice::_HandleMonitor(BMessage* message)
|
|||||||
const char* path;
|
const char* path;
|
||||||
int32 opcode;
|
int32 opcode;
|
||||||
if (message->FindInt32("opcode", &opcode) != B_OK
|
if (message->FindInt32("opcode", &opcode) != B_OK
|
||||||
|| opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED
|
|| (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
|
||||||
|| message->FindString("path", &path) != B_OK)
|
|| message->FindString("path", &path) != B_OK)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (opcode == B_ENTRY_CREATED)
|
if (opcode == B_ENTRY_CREATED)
|
||||||
return _AddDevice(path);
|
return _AddDevice(path);
|
||||||
|
|
||||||
|
#if 0
|
||||||
return _RemoveDevice(path);
|
return _RemoveDevice(path);
|
||||||
|
#else
|
||||||
|
// Don't handle B_ENTRY_REMOVED, let the control thread take care of it.
|
||||||
|
return B_OK;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -489,9 +498,9 @@ MouseInputDevice::_FindDevice(const char* path)
|
|||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
for (int32 i = fDevices.CountItems(); i-- > 0;) {
|
for (int32 i = fDevices.CountItems() - 1; i >= 0; i--) {
|
||||||
MouseDevice* device = fDevices.ItemAt(i);
|
MouseDevice* device = fDevices.ItemAt(i);
|
||||||
if (!strcmp(device->Path(), path))
|
if (strcmp(device->Path(), path) == 0)
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,9 +513,11 @@ MouseInputDevice::_AddDevice(const char* path)
|
|||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
_RemoveDevice(path);
|
||||||
|
|
||||||
MouseDevice* device = new(std::nothrow) MouseDevice(*this, path);
|
MouseDevice* device = new(std::nothrow) MouseDevice(*this, path);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
LOG("No memory\n");
|
LOG("MouseInputDevice::_AddDevice() - No memory\n");
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,6 +530,9 @@ MouseInputDevice::_AddDevice(const char* path)
|
|||||||
devices[0] = device->DeviceRef();
|
devices[0] = device->DeviceRef();
|
||||||
devices[1] = NULL;
|
devices[1] = NULL;
|
||||||
|
|
||||||
|
LOG_DEVICES("MouseInputDevice::_AddDevice(%s), name: %s\n", path,
|
||||||
|
devices[0]->name);
|
||||||
|
|
||||||
return RegisterDevices(devices);
|
return RegisterDevices(devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,15 +546,17 @@ MouseInputDevice::_RemoveDevice(const char* path)
|
|||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
fDevices.RemoveItem(device);
|
|
||||||
|
|
||||||
input_device_ref* devices[2];
|
input_device_ref* devices[2];
|
||||||
devices[0] = device->DeviceRef();
|
devices[0] = device->DeviceRef();
|
||||||
devices[1] = NULL;
|
devices[1] = NULL;
|
||||||
|
|
||||||
|
LOG_DEVICES("MouseInputDevice::_RemoveDevice(%s), name: %s\n", path,
|
||||||
|
devices[0]->name);
|
||||||
|
|
||||||
UnregisterDevices(devices);
|
UnregisterDevices(devices);
|
||||||
|
|
||||||
delete device;
|
fDevices.RemoveItem(device);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public:
|
|||||||
uint32 command, BMessage* message);
|
uint32 command, BMessage* message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class MouseDevice;
|
||||||
|
// TODO: needed by the control thread to remove a dead device
|
||||||
|
// find a better way...
|
||||||
|
|
||||||
status_t _HandleMonitor(BMessage* message);
|
status_t _HandleMonitor(BMessage* message);
|
||||||
void _RecursiveScan(const char* directory);
|
void _RecursiveScan(const char* directory);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user