udev: add function to get wpid from udev
base: make workaround flag name more generic descriptors: fix wpid's for 27Mhz devices device: Improve wpid and kind processing for 27Mhz devices notifications: Improve wpid generation for 27Mhz devices docs: fix wpid's for EX100
This commit is contained in:
parent
9de4d392d4
commit
7a82b93aaf
|
@ -211,8 +211,8 @@ setting is useful only to disable smooth scrolling.
|
||||||
| MK550 | | | | |
|
| MK550 | | | | |
|
||||||
| MK700 | 2008 | 1.0 | yes | FN swap, reprog keys |
|
| MK700 | 2008 | 1.0 | yes | FN swap, reprog keys |
|
||||||
| MK710 | | 1.0 | yes | FN swap, reprog keys |
|
| MK710 | | 1.0 | yes | FN swap, reprog keys |
|
||||||
| EX100 keyboard | 6500 | 1.0 | yes | |
|
| EX100 keyboard | 0065 | 1.0 | yes | |
|
||||||
| EX100 mouse | 3f00 | 1.0 | yes | |
|
| EX100 mouse | 003f | 1.0 | yes | |
|
||||||
|
|
||||||
* The EX100 is old, preunifying set, supporting only part of HID++ 1.0 features
|
* The EX100 is old, preunifying set, supporting only part of HID++ 1.0 features
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
||||||
from hidapi.udev import close # noqa: F401
|
from hidapi.udev import close # noqa: F401
|
||||||
from hidapi.udev import enumerate # noqa: F401
|
from hidapi.udev import enumerate # noqa: F401
|
||||||
from hidapi.udev import find_paired_node # noqa: F401
|
from hidapi.udev import find_paired_node # noqa: F401
|
||||||
|
from hidapi.udev import find_paired_node_wpid # noqa: F401
|
||||||
from hidapi.udev import get_manufacturer # noqa: F401
|
from hidapi.udev import get_manufacturer # noqa: F401
|
||||||
from hidapi.udev import get_product # noqa: F401
|
from hidapi.udev import get_product # noqa: F401
|
||||||
from hidapi.udev import get_serial # noqa: F401
|
from hidapi.udev import get_serial # noqa: F401
|
||||||
|
|
|
@ -176,6 +176,27 @@ def find_paired_node(receiver_path, index, timeout):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_paired_node_wpid(receiver_path, index):
|
||||||
|
"""Find the node of a device paired with a receiver, get wpid from udev"""
|
||||||
|
context = _Context()
|
||||||
|
receiver_phys = _Devices.from_device_file(context, receiver_path).find_parent('hid').get('HID_PHYS')
|
||||||
|
|
||||||
|
if not receiver_phys:
|
||||||
|
return None
|
||||||
|
|
||||||
|
phys = f'{receiver_phys}:{index}'
|
||||||
|
for dev in context.list_devices(subsystem='hidraw'):
|
||||||
|
dev_phys = dev.find_parent('hid').get('HID_PHYS')
|
||||||
|
if dev_phys and dev_phys == phys:
|
||||||
|
# get hid id like 0003:0000046D:00000065
|
||||||
|
hid_id = dev.find_parent('hid').get('HID_ID')
|
||||||
|
# get wpid - last 4 symbols
|
||||||
|
udev_wpid = hid_id[-4:]
|
||||||
|
return udev_wpid
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def monitor_glib(callback, *device_filters):
|
def monitor_glib(callback, *device_filters):
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
||||||
## should this last be changed so that may_unpair is used for all receivers? writing to _R.receiver_pairing doesn't seem right
|
## should this last be changed so that may_unpair is used for all receivers? writing to _R.receiver_pairing doesn't seem right
|
||||||
# re_pairs determines whether a receiver pairs by replacing existing pairings, default to False
|
# re_pairs determines whether a receiver pairs by replacing existing pairings, default to False
|
||||||
## currently only one receiver is so marked - should there be more?
|
## currently only one receiver is so marked - should there be more?
|
||||||
# ex100_wpid_fix enable workarounds for EX100 and possible other old 27Mhz receivers
|
# ex100_27mhz_wpid_fix enable workarounds for EX100 and possible other old 27Mhz receivers
|
||||||
|
|
||||||
_DRIVER = ('hid-generic', 'generic-usb', 'logitech-djreceiver')
|
_DRIVER = ('hid-generic', 'generic-usb', 'logitech-djreceiver')
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ _ex100_receiver = lambda product_id: {
|
||||||
'max_devices': 4,
|
'max_devices': 4,
|
||||||
'may_unpair': False,
|
'may_unpair': False,
|
||||||
're_pairs': True,
|
're_pairs': True,
|
||||||
'ex100_wpid_fix': True
|
'ex100_27mhz_wpid_fix': True
|
||||||
}
|
}
|
||||||
|
|
||||||
_wired_device = lambda product_id: {'vendor_id': 0x046d, 'product_id': product_id, 'usb_interface': 2}
|
_wired_device = lambda product_id: {'vendor_id': 0x046d, 'product_id': product_id, 'usb_interface': 2}
|
||||||
|
|
|
@ -169,7 +169,7 @@ _D(
|
||||||
_D(
|
_D(
|
||||||
'Wireless Keyboard MK300',
|
'Wireless Keyboard MK300',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='8521',
|
wpid='0068',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -292,14 +292,14 @@ _D(
|
||||||
'Wireless Keyboard S510',
|
'Wireless Keyboard S510',
|
||||||
codename='S510',
|
codename='S510',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='3622',
|
wpid='0056',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
)
|
)
|
||||||
_D(
|
_D(
|
||||||
'Wireless Keyboard EX100',
|
'Wireless Keyboard EX100',
|
||||||
codename='EX100',
|
codename='EX100',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='6500',
|
wpid='0065',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -523,21 +523,21 @@ _D(
|
||||||
'LX5 Cordless Mouse',
|
'LX5 Cordless Mouse',
|
||||||
codename='LX5',
|
codename='LX5',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='5612',
|
wpid='0036',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
)
|
)
|
||||||
_D(
|
_D(
|
||||||
'Wireless Mouse M30',
|
'Wireless Mouse M30',
|
||||||
codename='M30',
|
codename='M30',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='6822',
|
wpid='0085',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
)
|
)
|
||||||
_D(
|
_D(
|
||||||
'Wireless Mouse EX100',
|
'Wireless Mouse EX100',
|
||||||
codename='EX100m',
|
codename='EX100m',
|
||||||
protocol=1.0,
|
protocol=1.0,
|
||||||
wpid='3F00',
|
wpid='003F',
|
||||||
registers=(_R.battery_status, ),
|
registers=(_R.battery_status, ),
|
||||||
# settings=[ _RS.smooth_scroll(), ], # command accepted, but no change in whell action
|
# settings=[ _RS.smooth_scroll(), ], # command accepted, but no change in whell action
|
||||||
)
|
)
|
||||||
|
|
|
@ -81,9 +81,13 @@ class Device(object):
|
||||||
self.wpid = _strhex(link_notification.data[2:3] + link_notification.data[1:2])
|
self.wpid = _strhex(link_notification.data[2:3] + link_notification.data[1:2])
|
||||||
# assert link_notification.address == (0x04 if unifying else 0x03)
|
# assert link_notification.address == (0x04 if unifying else 0x03)
|
||||||
kind = ord(link_notification.data[0:1]) & 0x0F
|
kind = ord(link_notification.data[0:1]) & 0x0F
|
||||||
|
# get 27Mhz wpid and set kind based on index
|
||||||
|
if receiver.ex100_27mhz_wpid_fix: # 27 Mhz receiver
|
||||||
|
self.wpid = '00' + _strhex(link_notification.data[2:3])
|
||||||
|
kind = self.get_kind_from_index(number, receiver)
|
||||||
self._kind = _hidpp10.DEVICE_KIND[kind]
|
self._kind = _hidpp10.DEVICE_KIND[kind]
|
||||||
else:
|
else:
|
||||||
# force a reading of the wpid
|
# Not a notification, force a reading of the wpid
|
||||||
pair_info = self.receiver.read_register(_R.receiver_info, 0x20 + number - 1)
|
pair_info = self.receiver.read_register(_R.receiver_info, 0x20 + number - 1)
|
||||||
if pair_info:
|
if pair_info:
|
||||||
# may be either a Unifying receiver, or an Unifying-ready
|
# may be either a Unifying receiver, or an Unifying-ready
|
||||||
|
@ -91,20 +95,14 @@ class Device(object):
|
||||||
self.wpid = _strhex(pair_info[3:5])
|
self.wpid = _strhex(pair_info[3:5])
|
||||||
kind = ord(pair_info[7:8]) & 0x0F
|
kind = ord(pair_info[7:8]) & 0x0F
|
||||||
self._kind = _hidpp10.DEVICE_KIND[kind]
|
self._kind = _hidpp10.DEVICE_KIND[kind]
|
||||||
elif receiver.ex100_wpid_fix:
|
elif receiver.ex100_27mhz_wpid_fix:
|
||||||
# ex100 receiver, fill fake device_info with known wpid's
|
# 27Mhz receiver, fill extracting WPID from udev path
|
||||||
# accordingly to drivers/hid/hid-logitech-dj.c
|
self.wpid = _hid.find_paired_node_wpid(receiver.path, number)
|
||||||
# index 1 or 2 always mouse, index 3 always the keyboard,
|
if not self.wpid:
|
||||||
# index 4 is used for an optional separate numpad
|
_log.error('Unable to get wpid from udev for device %d of %s', number, receiver)
|
||||||
if number == 1: # mouse
|
raise _base.NoSuchDevice(number=number, receiver=receiver, error='Not present 27Mhz device')
|
||||||
self.wpid = '3F00'
|
kind = self.get_kind_from_index(number, receiver)
|
||||||
self._kind = _hidpp10.DEVICE_KIND[2]
|
self._kind = _hidpp10.DEVICE_KIND[kind]
|
||||||
elif number == 3: # keyboard
|
|
||||||
self.wpid = '6500'
|
|
||||||
self._kind = _hidpp10.DEVICE_KIND[1]
|
|
||||||
else: # unknown device number on EX100
|
|
||||||
_log.error('failed to set fake EX100 wpid for device %d of %s', number, receiver)
|
|
||||||
raise _base.NoSuchDevice(number=number, receiver=receiver, error='Unknown EX100 device')
|
|
||||||
else:
|
else:
|
||||||
# unifying protocol not supported, must be a Nano receiver
|
# unifying protocol not supported, must be a Nano receiver
|
||||||
device_info = self.receiver.read_register(_R.receiver_info, 0x04)
|
device_info = self.receiver.read_register(_R.receiver_info, 0x04)
|
||||||
|
@ -289,6 +287,25 @@ class Device(object):
|
||||||
self._feature_settings_checked = _check_feature_settings(self, self._settings)
|
self._feature_settings_checked = _check_feature_settings(self, self._settings)
|
||||||
return self._settings
|
return self._settings
|
||||||
|
|
||||||
|
def get_kind_from_index(self, index, receiver):
|
||||||
|
"""Get device kind from 27Mhz device index"""
|
||||||
|
# accordingly to drivers/hid/hid-logitech-dj.c
|
||||||
|
# index 1 or 2 always mouse, index 3 always the keyboard,
|
||||||
|
# index 4 is used for an optional separate numpad
|
||||||
|
|
||||||
|
if index == 1: # mouse
|
||||||
|
kind = 2
|
||||||
|
elif index == 2: # mouse
|
||||||
|
kind = 2
|
||||||
|
elif index == 3: # keyboard
|
||||||
|
kind = 1
|
||||||
|
elif index == 4: # numpad
|
||||||
|
kind = 3
|
||||||
|
else: # unknown device number on 27Mhz receiver
|
||||||
|
_log.error('failed to calculate device kind for device %d of %s', index, receiver)
|
||||||
|
raise _base.NoSuchDevice(number=index, receiver=receiver, error='Unknown 27Mhz device number')
|
||||||
|
return kind
|
||||||
|
|
||||||
def enable_notifications(self, enable=True):
|
def enable_notifications(self, enable=True):
|
||||||
"""Enable or disable device (dis)connection notifications on this
|
"""Enable or disable device (dis)connection notifications on this
|
||||||
receiver."""
|
receiver."""
|
||||||
|
|
|
@ -203,6 +203,9 @@ def _process_hidpp10_notification(device, status, n):
|
||||||
)
|
)
|
||||||
if protocol_name:
|
if protocol_name:
|
||||||
wpid = _strhex(n.data[2:3] + n.data[1:2])
|
wpid = _strhex(n.data[2:3] + n.data[1:2])
|
||||||
|
# workaround for short EX100 and other 27 MHz wpids
|
||||||
|
if protocol_name == '27 MHz':
|
||||||
|
wpid = '00' + _strhex(n.data[2:3])
|
||||||
if wpid != device.wpid:
|
if wpid != device.wpid:
|
||||||
_log.warn('%s wpid mismatch, got %s', device, wpid)
|
_log.warn('%s wpid mismatch, got %s', device, wpid)
|
||||||
flags = ord(n.data[:1]) & 0xF0
|
flags = ord(n.data[:1]) & 0xF0
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Receiver(object):
|
||||||
self._str = '<%s(%s,%s%s)>' % (
|
self._str = '<%s(%s,%s%s)>' % (
|
||||||
self.name.replace(' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle
|
self.name.replace(' ', ''), self.path, '' if isinstance(self.handle, int) else 'T', self.handle
|
||||||
)
|
)
|
||||||
self.ex100_wpid_fix = product_info.get('ex100_wpid_fix', False)
|
self.ex100_27mhz_wpid_fix = product_info.get('ex100_27mhz_wpid_fix', False)
|
||||||
|
|
||||||
self._firmware = None
|
self._firmware = None
|
||||||
self._devices = {}
|
self._devices = {}
|
||||||
|
|
Loading…
Reference in New Issue