diff --git a/lib/logitech/unifying_receiver/base.py b/lib/logitech/unifying_receiver/base.py
index 1c64df8b..ecc9861e 100644
--- a/lib/logitech/unifying_receiver/base.py
+++ b/lib/logitech/unifying_receiver/base.py
@@ -67,9 +67,10 @@ class DeviceUnreachable(_KwException):
#
# vendor_id, product_id, usb interface number, hid driver
-DEVICE_UNIFYING_RECEIVER = (0x046d, 0xc52b, 2, 'logitech-djreceiver')
-DEVICE_UNIFYING_RECEIVER_2 = (0x046d, 0xc532, 2, 'logitech-djreceiver')
-DEVICE_NANO_RECEIVER = (0x046d, 0xc526, 1, 'hid-generic')
+DEVICE_UNIFYING_RECEIVER = (0x046d, 0xc52b, 2, 'logitech-djreceiver')
+DEVICE_UNIFYING_RECEIVER_2 = (0x046d, 0xc532, 2, 'logitech-djreceiver')
+DEVICE_NANO_RECEIVER = (0x046d, 0xc52f, 1, 'hid-generic')
+DEVICE_VXNANO_RECEIVER = (0x046d, 0xc526, 1, 'hid-generic')
def receivers():
@@ -78,8 +79,10 @@ def receivers():
yield d
for d in _hid.enumerate(*DEVICE_UNIFYING_RECEIVER_2):
yield d
- #for d in _hid.enumerate(*DEVICE_NANO_RECEIVER):
- # yield d
+ for d in _hid.enumerate(*DEVICE_NANO_RECEIVER):
+ yield d
+ for d in _hid.enumerate(*DEVICE_VXNANO_RECEIVER):
+ yield d
def notify_on_receivers(callback):
@@ -87,7 +90,8 @@ def notify_on_receivers(callback):
_hid.monitor_async(callback,
DEVICE_UNIFYING_RECEIVER,
DEVICE_UNIFYING_RECEIVER_2,
- # DEVICE_NANO_RECEIVER,
+ DEVICE_NANO_RECEIVER,
+ DEVICE_VXNANO_RECEIVER,
)
diff --git a/lib/logitech/unifying_receiver/descriptors.py b/lib/logitech/unifying_receiver/descriptors.py
index 2a78d13e..dec0b065 100644
--- a/lib/logitech/unifying_receiver/descriptors.py
+++ b/lib/logitech/unifying_receiver/descriptors.py
@@ -51,11 +51,11 @@ def check_features(device, already_known):
#
_DeviceDescriptor = namedtuple('_DeviceDescriptor',
- ['name', 'kind', 'codename', 'registers', 'settings'])
+ ['name', 'kind', 'product_id', 'codename', 'registers', 'settings'])
DEVICES = {}
-def _D(name, codename=None, kind=None, registers=None, settings=None):
+def _D(name, codename=None, kind=None, product_id=None, registers=None, settings=None):
if kind is None:
kind = (_hidpp10.DEVICE_KIND.mouse if 'Mouse' in name
else _hidpp10.DEVICE_KIND.keyboard if 'Keyboard' in name
@@ -68,7 +68,9 @@ def _D(name, codename=None, kind=None, registers=None, settings=None):
codename = name.split(' ')[-1]
assert codename is not None
- DEVICES[codename] = _DeviceDescriptor(name, kind, codename, registers, settings)
+ DEVICES[codename] = _DeviceDescriptor(name, kind, product_id, codename, registers, settings)
+ if product_id:
+ DEVICES[product_id] = DEVICES[codename]
#
#
@@ -133,6 +135,13 @@ _D('Wireless Illuminated Keyboard K800',
# Mice
+# _D('VX Nano Cordless Laser Mouse', product_id='c526', codename='VXNano',
+# registers={'battery_charge': 0x0D},
+# settings=[
+# _register_smooth_scroll(0x01, true_value=0x40, mask=0x40),
+# ],
+# )
+
_D('Wireless Mouse M315')
_D('Wireless Mouse M325')
_D('Wireless Mouse M505')
@@ -154,7 +163,7 @@ _D('Marathon Mouse M705',
)
_D('Zone Touch Mouse T400')
_D('Touch Mouse T620')
-_D('Logitech Cube', kind='mouse')
+_D('Logitech Cube', kind=_hidpp10.DEVICE_KIND.mouse)
_D('Anywhere Mouse MX', codename='Anywhere MX',
# registers={'battery_charge': 0x0D},
# settings=[
diff --git a/lib/logitech/unifying_receiver/hidpp10.py b/lib/logitech/unifying_receiver/hidpp10.py
index 6b5dba91..5dc99c62 100644
--- a/lib/logitech/unifying_receiver/hidpp10.py
+++ b/lib/logitech/unifying_receiver/hidpp10.py
@@ -153,7 +153,7 @@ def get_serial(device):
def get_firmware(device):
- firmware = []
+ firmware = [None, None]
reply = device.request(0x81F1, 0x01)
if reply:
@@ -163,23 +163,17 @@ def get_firmware(device):
if reply:
fw_version += '.B' + _strhex(reply[1:3])
fw = _FirmwareInfo(FIRMWARE_KIND.Firmware, '', fw_version, None)
- firmware.append(fw)
-
- if device.kind is None and device.max_devices == 1:
- # Nano receiver
- return firmware
- if device.kind is not None and not device._unifying:
- # Nano device
- return firmware
+ firmware[0] = fw
reply = device.request(0x81F1, 0x04)
if reply:
bl_version = _strhex(reply[1:3])
bl_version = '%s.%s' % (bl_version[0:2], bl_version[2:4])
bl = _FirmwareInfo(FIRMWARE_KIND.Bootloader, '', bl_version, None)
- firmware.append(bl)
+ firmware[1] = bl
- return tuple(firmware)
+ if any(firmware):
+ return tuple(f for f in firmware if f)
def get_notification_flags(device):
diff --git a/lib/logitech/unifying_receiver/receiver.py b/lib/logitech/unifying_receiver/receiver.py
index b0e0ffa3..f2fbb23c 100644
--- a/lib/logitech/unifying_receiver/receiver.py
+++ b/lib/logitech/unifying_receiver/receiver.py
@@ -32,19 +32,40 @@ class PairedDevice(object):
assert number > 0 and number <= receiver.max_devices
self.number = number
- self._unifying = receiver.max_devices > 1
- self._protocol = None if self._unifying else 1.0
- self._wpid = None
- self._power_switch = None
- self._polling_rate = None if self._unifying else 0
+ self.wpid = None
+ self.polling_rate = 0
+
+ self._kind = None
self._codename = None
self._name = None
- self._kind = None
- self._serial = None if self._unifying else receiver.serial
+
+ self._protocol = None if self.receiver.unifying_supported else 1.0
+ self._power_switch = None if self.receiver.unifying_supported else '(unknown)'
+ self._serial = None if self.receiver.unifying_supported else self.receiver.serial
+
+ if self.receiver.unifying_supported:
+ pair_info = self.receiver.request(0x83B5, 0x20 + self.number - 1)
+ if pair_info:
+ self.wpid = _strhex(pair_info[3:5])
+ kind = ord(pair_info[7:8]) & 0x0F
+ self._kind = _hidpp10.DEVICE_KIND[kind]
+ self.polling_rate = ord(pair_info[2:3])
+ # else:
+ # # guesswork...
+ # descriptor = _descriptors.DEVICES.get(self.receiver.product_id)
+ # if descriptor:
+ # self._kind = descriptor.kind
+ # self._codename = descriptor.codename
+ # self._name = descriptor.name
+
+ # device_info = self.receiver.request(0x83B5, 0x04)
+ # if device_info:
+ # self.wpid = _strhex(device_info[3:5])
+
self._firmware = None
self._keys = None
- self.features = _hidpp20.FeaturesArray(self) if self._unifying else None
+ self.features = _hidpp20.FeaturesArray(self) if self.receiver.unifying_supported else None
self._registers = None
self._settings = None
@@ -55,66 +76,36 @@ class PairedDevice(object):
# _log.debug("device %d protocol %s", self.number, self._protocol)
return self._protocol or 0
- @property
- def wpid(self):
- if self._wpid is None:
- if self._unifying:
- pair_info = self.receiver.request(0x83B5, 0x20 + self.number - 1)
- if pair_info:
- self._wpid = _strhex(pair_info[3:5])
- if self._kind is None:
- kind = ord(pair_info[7:8]) & 0x0F
- self._kind = _hidpp10.DEVICE_KIND[kind]
- if self._polling_rate is None:
- self._polling_rate = ord(pair_info[2:3])
- else:
- # guesswork...
- device_info = self.receiver.request(0x83B5, 0x04)
- self.wpid = _strhex(device_info[3:5])
- return self._wpid
-
- @property
- def polling_rate(self):
- if self._polling_rate is None:
- if self._unifying:
- self.wpid, 0
- else:
- self._polling_rate = 0
- return self._polling_rate
-
@property
def power_switch_location(self):
if self._power_switch is None:
- if self._unifying:
- ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
- if ps:
- ps = ord(ps[9:10]) & 0x0F
- self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
+ ps = self.receiver.request(0x83B5, 0x30 + self.number - 1)
+ if ps:
+ ps = ord(ps[9:10]) & 0x0F
+ self._power_switch = _hidpp10.POWER_SWITCH_LOCATION[ps]
return self._power_switch
@property
def codename(self):
if self._codename is None:
- if self._unifying:
- codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
- if codename:
- self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
- # _log.debug("device %d codename %s", self.number, self._codename)
+ codename = self.receiver.request(0x83B5, 0x40 + self.number - 1)
+ if codename:
+ self._codename = codename[2:].rstrip(b'\x00').decode('utf-8')
+ # _log.debug("device %d codename %s", self.number, self._codename)
return self._codename
@property
def name(self):
if self._name is None:
- if self._unifying:
- if self.codename in _descriptors.DEVICES:
- self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
- elif self.protocol >= 2.0:
- self._name = _hidpp20.get_name(self)
+ if self.codename in _descriptors.DEVICES:
+ self._name, self._kind = _descriptors.DEVICES[self._codename][:2]
+ elif self.protocol >= 2.0:
+ self._name = _hidpp20.get_name(self)
return self._name or self.codename or '?'
@property
def kind(self):
- if self._kind is None and self._unifying:
+ if self._kind is None and self.receiver.unifying_supported:
pair_info = self.receiver.request(0x83B5, 0x20 + self.number - 1)
if pair_info:
kind = ord(pair_info[7:8]) & 0x0F
@@ -146,7 +137,7 @@ class PairedDevice(object):
@property
def keys(self):
if self._keys is None:
- if self._unifying:
+ if self.protocol >= 2.0:
self._keys = _hidpp20.get_keys(self) or ()
return self._keys
@@ -201,7 +192,7 @@ class PairedDevice(object):
return _base.request(self.receiver.handle, self.number, request_id, *params)
def feature_request(self, feature, function=0x00, *params):
- if self._unifying:
+ if self.protocol >= 2.0:
return _hidpp20.feature_request(self, feature, function, *params)
def ping(self):
@@ -236,15 +227,18 @@ class Receiver(object):
number = 0xFF
kind = None
- def __init__(self, handle, path=None):
+ def __init__(self, handle, device_info):
assert handle
self.handle = handle
- assert path
- self.path = path
+ assert device_info
+ self.path = device_info.path
+ self.product_id = device_info.product_id
+ # read the serial immediately, so we can find out max_devices
+ # this will tell us if it's a Unifying or Nano receiver
serial_reply = self.request(0x83B5, 0x03)
assert serial_reply
- self._serial = _strhex(serial_reply[1:5])
+ self.serial = _strhex(serial_reply[1:5])
self.max_devices = ord(serial_reply[6:7])
if self.max_devices == 1:
@@ -255,6 +249,9 @@ class Receiver(object):
raise Exception("unknown receiver type")
self._str = '<%s(%s,%s%s)>' % (self.name.replace(' ', ''), self.path, '' if type(self.handle) == int else 'T', self.handle)
+ old_equad_reply = self.request(0x83B5, 0x04)
+ self.unifying_supported = old_equad_reply is None
+
self._firmware = None
self._devices = {}
@@ -266,13 +263,6 @@ class Receiver(object):
def __del__(self):
self.close()
- @property
- def serial(self):
- assert self._serial
- # if self._serial is None and self.handle:
- # self._serial = _hidpp10.get_serial(self)
- return self._serial
-
@property
def firmware(self):
if self._firmware is None and self.handle:
@@ -308,21 +298,13 @@ class Receiver(object):
def register_new_device(self, number):
if self._devices.get(number) is not None:
raise IndexError("%s: device number %d already registered" % (self, number))
+
dev = PairedDevice(self, number)
- # create a device object, but only use it if the receiver knows about it
-
- # Nano receiver
- if self.max_devices == 1 and number == 1:
- # the Nano receiver does not provide the wpid
- _log.info("%s: found Nano device %d (%s)", self, number, dev.serial)
- # dev._wpid = self.serial + ':1'
- self._devices[number] = dev
- return dev
-
if dev.wpid:
- _log.info("%s: found Unifying device %d (%s)", self, number, dev.wpid)
+ _log.info("%s: found device %d (%s)", self, number, dev.wpid)
self._devices[number] = dev
return dev
+
self._devices[number] = None
def set_lock(self, lock_closed=True, device=0, timeout=0):
@@ -403,18 +385,18 @@ class Receiver(object):
__bool__ = __nonzero__ = lambda self: self.handle is not None
@classmethod
- def open(self, path):
+ def open(self, device_info):
"""Opens a Logitech Receiver found attached to the machine, by Linux device path.
:returns: An open file handle for the found receiver, or ``None``.
"""
try:
- handle = _base.open_path(path)
+ handle = _base.open_path(device_info.path)
if handle:
- return Receiver(handle, path)
+ return Receiver(handle, device_info)
except OSError as e:
- _log.exception("open %s", path)
+ _log.exception("open %s", device_info)
if e.errno == _errno.EACCES:
raise
except:
- _log.exception("open %s", path)
+ _log.exception("open %s", device_info)
diff --git a/lib/logitech/unifying_receiver/status.py b/lib/logitech/unifying_receiver/status.py
index c2384ef9..87a221fc 100644
--- a/lib/logitech/unifying_receiver/status.py
+++ b/lib/logitech/unifying_receiver/status.py
@@ -273,6 +273,7 @@ class DeviceStatus(dict):
_log.warn("%s: unrecognized %s", self._device, n)
def _process_hidpp10_notification(self, n):
+ # unpair notification
if n.sub_id == 0x40:
if n.address == 0x02:
# device un-paired
@@ -283,44 +284,33 @@ class DeviceStatus(dict):
_log.warn("%s: disconnection with unknown type %02X: %s", self._device, n.address, n)
return True
+ # wireless link notification
if n.sub_id == 0x41:
- if n.address == 0x04: # unifying protocol
- # wpid = _strhex(n.data[4:5] + n.data[3:4])
- # assert wpid == device.wpid
-
+ protocol_name = ('unifying (eQuad DJ)' if n.address == 0x04
+ else 'eQuad' if n.address == 0x03
+ else None)
+ if protocol_name:
flags = ord(n.data[:1]) & 0xF0
link_encrypyed = bool(flags & 0x20)
link_established = not (flags & 0x40)
if _log.isEnabledFor(_DEBUG):
sw_present = bool(flags & 0x10)
has_payload = bool(flags & 0x80)
- _log.debug("%s: unifying connection notification: software=%s, encrypted=%s, link=%s, payload=%s",
- self._device, sw_present, link_encrypyed, link_established, has_payload)
- self[ENCRYPTED] = link_encrypyed
- self._changed(link_established)
-
- elif n.address == 0x03: # eQuad protocol
- # Nano devices might not have been initialized fully
- if self._device._kind is None:
- kind = ord(n.data[:1]) & 0x0F
- self._device._kind = _hidpp10.DEVICE_KIND[kind]
- if self._device._wpid is None:
- self._device._wpid = _strhex(n.data[2:3] + n.data[1:2])
-
- flags = ord(n.data[:1]) & 0xF0
- link_encrypyed = bool(flags & 0x20)
- link_established = not (flags & 0x40)
- if _log.isEnabledFor(_DEBUG):
- sw_present = bool(flags & 0x10)
- has_payload = bool(flags & 0x80)
- _log.debug("%s: eQuad connection notification: software=%s, encrypted=%s, link=%s, payload=%s",
- self._device, sw_present, link_encrypyed, link_established, has_payload)
+ _log.debug("%s: %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s",
+ self._device, protocol_name, sw_present, link_encrypyed, link_established, has_payload)
self[ENCRYPTED] = link_encrypyed
self._changed(link_established)
+ if protocol_name == 'eQuad':
+ # some Nano devices might not have been initialized fully
+ if self._device._kind is None:
+ kind = ord(n.data[:1]) & 0x0F
+ self._device._kind = _hidpp10.DEVICE_KIND[kind]
+ assert self._device.wpid == _strhex(n.data[2:3] + n.data[1:2])
else:
_log.warn("%s: connection notification with unknown protocol %02X: %s", self._device.number, n.address, n)
+ # if the device just came online, read the battery charge
if self._active: # and BATTERY_LEVEL not in self:
self.read_battery()
@@ -332,6 +322,7 @@ class DeviceStatus(dict):
# if n.address == 0x03, it's an actual input event
return True
+ # power notification
if n.sub_id == 0x4B:
if n.address == 0x01:
if _log.isEnabledFor(_DEBUG):
diff --git a/lib/solaar/cli.py b/lib/solaar/cli.py
index 161257cf..42ec8c97 100644
--- a/lib/solaar/cli.py
+++ b/lib/solaar/cli.py
@@ -36,7 +36,7 @@ def _receiver():
from logitech.unifying_receiver.base import receivers
for dev_info in receivers():
try:
- r = Receiver.open(dev_info.path)
+ r = Receiver.open(dev_info)
if r:
return r
except Exception as e:
@@ -99,7 +99,7 @@ def _print_receiver(receiver, verbose=False):
else:
print (" All notifications disabled")
- if paired_count > 0:
+ if receiver.unifying_supported:
activity = receiver.request(0x83B3)
if activity:
activity = [(d, ord(activity[d - 1:d])) for d in range(1, receiver.max_devices)]
diff --git a/lib/solaar/gtk.py b/lib/solaar/gtk.py
index 67f6d89a..6c85aa05 100644
--- a/lib/solaar/gtk.py
+++ b/lib/solaar/gtk.py
@@ -50,12 +50,12 @@ def _run(args):
listeners = {}
from solaar.listener import ReceiverListener
- def handle_receivers_events(action, device):
+ def handle_receivers_events(action, device_info):
assert action is not None
- assert device is not None
+ assert device_info is not None
# whatever the action, stop any previous receivers at this path
- l = listeners.pop(device.path, None)
+ l = listeners.pop(device_info.path, None)
if l is not None:
assert isinstance(l, ReceiverListener)
l.stop()
@@ -63,18 +63,17 @@ def _run(args):
if action == 'add':
# a new receiver device was detected
try:
- l = ReceiverListener.open(device.path, status_changed)
+ l = ReceiverListener.open(device_info, status_changed)
if l is not None:
- listeners[device.path] = l
+ listeners[device_info.path] = l
except OSError:
# permission error, blacklist this path for now
- listeners.pop(device.path, None)
+ listeners.pop(device_info.path, None)
GLib.idle_add(ui.error_dialog, 'Permissions error',
- 'Found a Logitech Unifying Receiver device,\n'
- 'but did not have permission to open it.\n'
+ 'Found a Logitech Receiver, but did not have permission to open it.\n'
'\n'
- 'If you\'ve just installed Solaar, try removing\n'
- 'the receiver and plugging it back in.')
+ 'If you\'ve just installed Solaar, try removing the receiver\n'
+ 'and plugging it back in.')
# elif action == 'remove':
# # we'll be receiving remove events for any hidraw devices,
diff --git a/lib/solaar/listener.py b/lib/solaar/listener.py
index 5f217713..d7b67d22 100644
--- a/lib/solaar/listener.py
+++ b/lib/solaar/listener.py
@@ -161,12 +161,12 @@ class ReceiverListener(_listener.EventsListener):
__unicode__ = __str__
@classmethod
- def open(self, path, status_changed_callback):
+ def open(self, device_info, status_changed_callback):
assert status_changed_callback
- receiver = Receiver.open(path)
+ receiver = Receiver.open(device_info)
if receiver:
rl = ReceiverListener(receiver, status_changed_callback)
rl.start()
return rl
else:
- _log.warn("failed to open %s", path)
+ _log.warn("failed to open %s", device_info)
diff --git a/lib/solaar/ui/main_window.py b/lib/solaar/ui/main_window.py
index b79a5a4b..b1d9571a 100644
--- a/lib/solaar/ui/main_window.py
+++ b/lib/solaar/ui/main_window.py
@@ -70,16 +70,17 @@ def _make_receiver_box(receiver):
device = f._device
if True: # f._info_label.get_visible() and '\n' not in f._info_label.get_text():
items = [('Path', device.path), ('Serial', device.serial)] + \
- [(fw.kind, fw.version) for fw in device.firmware]
+ list((fw.kind, fw.version) for fw in device.firmware) + \
+ [None]
notification_flags = _hidpp10.get_notification_flags(device)
if notification_flags:
notification_flags = _hidpp10.NOTIFICATION_FLAG.flag_names(notification_flags)
else:
notification_flags = ('(none)',)
- items.append(('Notifications', ('\n%16s' % ' ').join(notification_flags)))
+ items[-1] = ('Notifications', ('\n%16s' % ' ').join(notification_flags))
- f._info_label.set_markup('%s' % '\n'.join('%-14s: %s' % item for item in items))
+ f._info_label.set_markup('%s' % '\n'.join('%-14s: %s' % i for i in items if i))
f._info_label.set_sensitive(True)
def _toggle_info_label(action, f):
@@ -94,7 +95,7 @@ def _make_receiver_box(receiver):
toggle_info_action = _action.make_toggle('dialog-information', 'Details', _toggle_info_label, frame)
toolbar.insert(toggle_info_action.create_tool_item(), 0)
pair_action = _action.pair(frame)
- if receiver.max_devices == 1:
+ if not receiver.unifying_supported:
pair_action.set_sensitive(False)
pair_action.set_tooltip('Pairing not supported by this receiver')
toolbar.insert(pair_action.create_tool_item(), -1)
@@ -186,16 +187,14 @@ def _make_device_box(index):
device = f._device
assert device
- items = [None] * 8
hid = device.protocol
- items[0] = ('Protocol', 'HID++ %1.1f' % hid if hid else 'unknown')
- items[1] = ('Polling rate', '%d ms' % device.polling_rate) if device.polling_rate else None
- items[2] = ('Wireless PID', device.wpid)
- items[3] = ('Serial', device.serial)
- firmware = device.firmware
- if firmware:
- firmware = [(fw.kind, (fw.name + ' ' + fw.version).strip()) for fw in firmware]
- items[4:4+len(firmware)] = firmware
+ items = [
+ ('Protocol', 'HID++ %1.1f' % hid if hid else 'unknown'),
+ ('Polling rate', '%d ms' % device.polling_rate) if device.polling_rate else None,
+ ('Wireless PID', device.wpid),
+ ('Serial', device.serial) ] + \
+ list((fw.kind, (fw.name + ' ' + fw.version).strip()) for fw in device.firmware) + \
+ [None]
if device.status:
notification_flags = _hidpp10.get_notification_flags(device)
@@ -204,8 +203,6 @@ def _make_device_box(index):
else:
notification_flags = ('(none)',)
items[-1] = ('Notifications', ('\n%16s' % ' ').join(notification_flags))
- else:
- items[-1] = None
frame._info_label.set_markup('%s' % '\n'.join('%-14s: %s' % i for i in items if i))
frame._info_label.set_sensitive(True)
@@ -422,7 +419,7 @@ def _update_device_box(frame, dev):
for i in frame._toolbar.get_children():
i.set_active(False)
- if dev.receiver.max_devices == 1:
+ if not dev.receiver.unifying_supported:
unpair_button = frame.get_child().get_children()[-1]
unpair_button.set_sensitive(False)
unpair_button.set_tooltip_text('Unpairing not supported by this device')
diff --git a/rules.d/99-logitech-unifying-receiver.rules b/rules.d/99-logitech-unifying-receiver.rules
index d7b40bc1..d0fdbb4c 100644
--- a/rules.d/99-logitech-unifying-receiver.rules
+++ b/rules.d/99-logitech-unifying-receiver.rules
@@ -8,8 +8,13 @@
# HIDAPI/hidraw for Logitech Unifying Receiver
ACTION=="add", KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c52b", GROUP="plugdev", MODE="0660"
+ACTION=="add", KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c532", GROUP="plugdev", MODE="0660"
-# HIDAPI/hidraw for Logitech Nano Receiver
+# HIDAPI/hidraw for Logitech Nano Receiver, "Unifying ready"
+ACTION=="add", KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c52f", GROUP="plugdev", MODE="0660"
+
+# HIDAPI/hidraw for VX Nano receiver
+#ACTION=="add", KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c51a", GROUP="plugdev", MODE="0660"
#ACTION=="add", KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c526", GROUP="plugdev", MODE="0660"
# vim: ft=udevrules