* [PATCH v14 0/2] Introduce Synology Microp driver
@ 2026-05-30 22:57 Markus Probst via B4 Relay
2026-05-30 22:57 ` [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices Markus Probst via B4 Relay
2026-05-30 22:57 ` [PATCH v14 2/2] platform: Add initial synology microp driver Markus Probst via B4 Relay
0 siblings, 2 replies; 5+ messages in thread
From: Markus Probst via B4 Relay @ 2026-05-30 22:57 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, Bryan O'Donoghue,
Lee Jones, Pavel Machek, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Greg Kroah-Hartman
Cc: platform-driver-x86, linux-leds, devicetree, linux-kernel,
rust-for-linux, Markus Probst, Krzysztof Kozlowski
Synology uses a microcontroller in their NAS devices connected to a
serial port to control certain LEDs, fan speeds, a beeper, to handle
proper shutdown and restart, buttons and fan failures.
This patch series depends on the rust led abstraction [1] and the rust
serdev abstraction [2].
This is only a initial version of the driver able to control LEDs.
The following rust abstractions would be required, to implement the
remaining features:
- hwmon (include/linux/hwmon.h)
- input (include/linux/input.h)
- sysoff handler (include/linux/reboot.h)
[1] https://lore.kernel.org/rust-for-linux/20260530-rust_leds-v17-0-c0698c4368e2@posteo.de/
[2] https://lore.kernel.org/rust-for-linux/20260530-rust_serdev-v8-0-2a95f1da22a7@posteo.de/
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
Changes in v14:
- adapt to led abstraction v18 and serdev abstraction v11
- Link to v13: https://patch.msgid.link/20260530-synology_microp_initial-v13-0-aa2bb9c56efc@posteo.de
Changes in v13:
- adapted to driver-lifetime v5 patch series.
- set blink = false as initial power led state, as set_blink hasn't been
called yet (even though the led is blinking at startup)
- Link to v12: https://patch.msgid.link/20260429-synology_microp_initial-v12-0-40a05033c620@posteo.de
Changes in v12:
- adapted to driver-lifetime patch series. The driver can't take
advantage of it, until class devices like led also make use of it.
- Link to v11: https://patch.msgid.link/20260427-synology_microp_initial-v11-0-9c1bd5a6f3ed@posteo.de
Changes in v11:
- rebased on top of 7.1-rc1
- add "synology" as devicename to led, like it is done in existing dts
files in the kernel
- fix color for led being orange instead of amber. I personally can't
clearly tell them apart, but apparently its amber.
- replaced MCU with EC in Kconfig help
- Link to v10: https://patch.msgid.link/20260424-synology_microp_initial-v10-0-e852d2f3eba1@posteo.de
Changes in v10:
- resolved issues reported by Sashiko Bot:
- removed unneeded include from device tree
- fix typo in of device table
- fix blink not set to false, if delay_off or delay_on is 0
- Link to v9: https://patch.msgid.link/20260423-synology_microp_initial-v9-0-4a8533f87e07@posteo.de
Changes in v9:
- separate fallback and front compatibles in dt schema
- remove front compatibles from of id table, if all functionality is
by covered by the fallback
- remove TODO file
- add platform-driver-x86@vger.kernel.org to Maintainers file entry
- use `Delta` type in `BLINK_DELAY` const
- Link to v8: https://patch.msgid.link/20260420-synology_microp_initial-v8-0-7946a9124491@posteo.de
Changes in v8:
- removed unnecessary Copy and Clone derive
- added `BLINK_DELAY` constant
- added compatible id fallbacks
- moved dt schema patch before the driver
- added ds411p
- Link to v7: https://lore.kernel.org/r/20260411-synology_microp_initial-v7-0-9a3a094e763a@posteo.de
Changes in v7:
- remove list of compatible ids from commit msg
- explain what makes the different models not compatible in the commit msg
- remove unnecessary examples
- Link to v6: https://lore.kernel.org/r/20260405-synology_microp_initial-v6-0-08fde474b6c9@posteo.de
Changes in v6:
- moved devicetree bindings patch at the end of the set
- remove several patches
- move of id table from model.rs to synology_microp.rs
- remove the model! macro
- use if blocks in devicetree schema to narrow down the
fan-failure-gpios property
- add multiple devicetree examples to test if blocks
- Link to v5: https://lore.kernel.org/r/20260329-synology_microp_initial-v5-0-27cb80bdf591@posteo.de
Changes in v5:
- add esata led support
- use different compatible for each model
- add visibility modifier to of_device_table macro
- fix match data missing when using PRP0001
- Link to v4: https://lore.kernel.org/r/20260320-synology_microp_initial-v4-0-0423ddb83ca4@posteo.de
Changes in v4:
- convert to monolithic driver and moved it into drivers/platform
- removed mfd rust abstraction
- moved dt-bindings to embedded-controller
- Link to v3: https://lore.kernel.org/r/20260313-synology_microp_initial-v3-0-ad6ac463a201@posteo.de
Changes in v3:
- remove `default n` from Kconfig entry, as n is the default already.
- select RUST_SERIAL_DEV_BUS_ABSTRACTIONS in Kconfig
- add mfd rust abstraction
- split core and led parts into their own driver. It should now be considered a
MFD device.
- split led part of dt binding into its own file
- Link to v2: https://lore.kernel.org/r/20260308-synology_microp_initial-v2-0-9389963f31c5@posteo.de
Changes in v2:
- fix missing tabs in MAINTAINERS file
- remove word binding from patch subject
- add missing signed-off-by
- add missing help entry in Kconfig
- add missing spdx license headers
- remove no-check{,-cpu}-fan properties from the dt-bindings and replace
them with the check_fan module parameter
- use patternProperties for leds in dt-bindings
- license dt-binding as GPL-2.0-only OR BSD-2-Clause
- move driver from staging tree into mfd tree and mark it as work in
progress inside Kconfig
- only register alert and usb led if fwnode is present
- Link to v1: https://lore.kernel.org/r/20260306-synology_microp_initial-v1-0-fcffede6448c@posteo.de
---
Markus Probst (2):
dt-bindings: embedded-controller: Add synology microp devices
platform: Add initial synology microp driver
.../synology,ds918p-microp.yaml | 100 +++++++
MAINTAINERS | 7 +
drivers/platform/Kconfig | 2 +
drivers/platform/Makefile | 1 +
drivers/platform/synology_microp/Kconfig | 13 +
drivers/platform/synology_microp/Makefile | 3 +
drivers/platform/synology_microp/command.rs | 54 ++++
drivers/platform/synology_microp/led.rs | 297 +++++++++++++++++++++
drivers/platform/synology_microp/model.rs | 49 ++++
.../platform/synology_microp/synology_microp.rs | 91 +++++++
10 files changed, 617 insertions(+)
---
base-commit: 9e171fc1d7d7ab847a750c03571c87ac3c17bd84
change-id: 20260306-synology_microp_initial-0f7dac7b7496
prerequisite-message-id: 20260505152400.3905096-1-dakr@kernel.org
prerequisite-patch-id: d2aebf69b153c039bbed1d0ed26906708fd22534
prerequisite-patch-id: 84b28da2f5de20fc1785095c647b2ffc35d969a5
prerequisite-patch-id: 67318671a5eed5fb4ad23a450f1cf0e442bf8ca2
prerequisite-message-id: 20260525202921.124698-1-dakr@kernel.org
prerequisite-patch-id: b84db329d4372a175cb8d49e4e88c3eecf7eb228
prerequisite-patch-id: 2c30303f409cc8288cc87e241920219f5ddd8390
prerequisite-patch-id: 4e4f0ad370d763ad00b0f75b91fa216f2cc95953
prerequisite-patch-id: 5bcd6b37f3498feebda275dfef78136eba34004e
prerequisite-patch-id: 872b0982f3e5e7d1698d9df3b325e4cd27b27789
prerequisite-patch-id: 3a3c7749e017d9335f58497404d1350e96caf471
prerequisite-patch-id: 3526c9154f581497a11465b936d83ef61a875454
prerequisite-patch-id: 65d8c757b52475c2acc7d22ddc92cd3f0152b55d
prerequisite-patch-id: 4bd31f1414d5248dc080884caadf5f21684a8427
prerequisite-patch-id: 7beadbb0da3e589ed86d12f512d1c83427dd82b4
prerequisite-patch-id: 12cd0f67ffd27347f90c065db491945908206b7f
prerequisite-patch-id: 4642e31f66331f6c3b579377111ea733dbb3a11c
prerequisite-patch-id: 52d67b40b4396c741e2222d6a5bc7927abcb77aa
prerequisite-patch-id: 74ca82ff26cf9c7a993757c87db8be62006e820f
prerequisite-patch-id: 466fb9fa7febbffd8ef51b311c7d9893c11fc0f0
prerequisite-patch-id: e515cd98b06e26721cbbe6a4fbacd251d0073b63
prerequisite-patch-id: 8dc8e75d9f6499a554ef7e474bbacdbf3660a9f2
prerequisite-patch-id: 5fdb9f71dca2f44dd293760a60db125b770f1f55
prerequisite-patch-id: c766a24c2d5064f5ec09daada0b8e8fba862d3aa
prerequisite-patch-id: b768f6456d35fa7a80c015e34bbdba6082dbd593
prerequisite-patch-id: 6a8b17234f12f7084e6e2ce843a7031b0a891ce4
prerequisite-patch-id: 98b2deb9e60c1f28f90c5ee34fd608aaa9fd9420
prerequisite-patch-id: 774b29be66e641ee50cedb4704cf49d8b9fabf50
prerequisite-patch-id: cf95dc936cfc4b3a7a363435a51a48d9009645b3
prerequisite-message-id: 20260530132736.3298549-1-dakr@kernel.org
prerequisite-patch-id: 310c6bee038ca3909a8e5e58ec12b74f7189b869
prerequisite-patch-id: 92812c3d42b29504838e6dc66c307ff5c035bb5e
prerequisite-change-id: 20251217-rust_serdev-ee5481e9085c:v11
prerequisite-patch-id: 45128665162dd9f51a0764deb3815a338948b291
prerequisite-patch-id: b84db329d4372a175cb8d49e4e88c3eecf7eb228
prerequisite-patch-id: 2c30303f409cc8288cc87e241920219f5ddd8390
prerequisite-patch-id: 4e4f0ad370d763ad00b0f75b91fa216f2cc95953
prerequisite-patch-id: 5bcd6b37f3498feebda275dfef78136eba34004e
prerequisite-patch-id: 872b0982f3e5e7d1698d9df3b325e4cd27b27789
prerequisite-patch-id: 3a3c7749e017d9335f58497404d1350e96caf471
prerequisite-patch-id: 3526c9154f581497a11465b936d83ef61a875454
prerequisite-patch-id: 65d8c757b52475c2acc7d22ddc92cd3f0152b55d
prerequisite-patch-id: 4bd31f1414d5248dc080884caadf5f21684a8427
prerequisite-patch-id: 7beadbb0da3e589ed86d12f512d1c83427dd82b4
prerequisite-patch-id: 12cd0f67ffd27347f90c065db491945908206b7f
prerequisite-patch-id: 4642e31f66331f6c3b579377111ea733dbb3a11c
prerequisite-patch-id: 52d67b40b4396c741e2222d6a5bc7927abcb77aa
prerequisite-patch-id: 74ca82ff26cf9c7a993757c87db8be62006e820f
prerequisite-patch-id: 466fb9fa7febbffd8ef51b311c7d9893c11fc0f0
prerequisite-patch-id: e515cd98b06e26721cbbe6a4fbacd251d0073b63
prerequisite-patch-id: 8dc8e75d9f6499a554ef7e474bbacdbf3660a9f2
prerequisite-patch-id: 5fdb9f71dca2f44dd293760a60db125b770f1f55
prerequisite-patch-id: c766a24c2d5064f5ec09daada0b8e8fba862d3aa
prerequisite-patch-id: b768f6456d35fa7a80c015e34bbdba6082dbd593
prerequisite-patch-id: 6a8b17234f12f7084e6e2ce843a7031b0a891ce4
prerequisite-patch-id: 98b2deb9e60c1f28f90c5ee34fd608aaa9fd9420
prerequisite-patch-id: 774b29be66e641ee50cedb4704cf49d8b9fabf50
prerequisite-patch-id: cf95dc936cfc4b3a7a363435a51a48d9009645b3
prerequisite-patch-id: 310c6bee038ca3909a8e5e58ec12b74f7189b869
prerequisite-patch-id: 92812c3d42b29504838e6dc66c307ff5c035bb5e
prerequisite-patch-id: 26cf819caf22fa5bb25b70a855d9f3d852ffea32
prerequisite-patch-id: 19eb53ce0c653c1406f8f192f6ad158fb4bd8d8f
prerequisite-patch-id: 55d6a70baf3be7f4da36b82cf02a5a7d59457520
prerequisite-change-id: 20251114-rust_leds-a959f7c2f7f9:v18
prerequisite-patch-id: 45128665162dd9f51a0764deb3815a338948b291
prerequisite-patch-id: b84db329d4372a175cb8d49e4e88c3eecf7eb228
prerequisite-patch-id: 2c30303f409cc8288cc87e241920219f5ddd8390
prerequisite-patch-id: 4e4f0ad370d763ad00b0f75b91fa216f2cc95953
prerequisite-patch-id: 5bcd6b37f3498feebda275dfef78136eba34004e
prerequisite-patch-id: 872b0982f3e5e7d1698d9df3b325e4cd27b27789
prerequisite-patch-id: 3a3c7749e017d9335f58497404d1350e96caf471
prerequisite-patch-id: 3526c9154f581497a11465b936d83ef61a875454
prerequisite-patch-id: 65d8c757b52475c2acc7d22ddc92cd3f0152b55d
prerequisite-patch-id: 4bd31f1414d5248dc080884caadf5f21684a8427
prerequisite-patch-id: 7beadbb0da3e589ed86d12f512d1c83427dd82b4
prerequisite-patch-id: 12cd0f67ffd27347f90c065db491945908206b7f
prerequisite-patch-id: 4642e31f66331f6c3b579377111ea733dbb3a11c
prerequisite-patch-id: 52d67b40b4396c741e2222d6a5bc7927abcb77aa
prerequisite-patch-id: 74ca82ff26cf9c7a993757c87db8be62006e820f
prerequisite-patch-id: 466fb9fa7febbffd8ef51b311c7d9893c11fc0f0
prerequisite-patch-id: e515cd98b06e26721cbbe6a4fbacd251d0073b63
prerequisite-patch-id: 8dc8e75d9f6499a554ef7e474bbacdbf3660a9f2
prerequisite-patch-id: 5fdb9f71dca2f44dd293760a60db125b770f1f55
prerequisite-patch-id: c766a24c2d5064f5ec09daada0b8e8fba862d3aa
prerequisite-patch-id: b768f6456d35fa7a80c015e34bbdba6082dbd593
prerequisite-patch-id: 6a8b17234f12f7084e6e2ce843a7031b0a891ce4
prerequisite-patch-id: 98b2deb9e60c1f28f90c5ee34fd608aaa9fd9420
prerequisite-patch-id: 774b29be66e641ee50cedb4704cf49d8b9fabf50
prerequisite-patch-id: cf95dc936cfc4b3a7a363435a51a48d9009645b3
prerequisite-patch-id: 4d3ac33ad5f5b6358ad5d72b57fb692a70ff03bf
prerequisite-patch-id: 50bfe4b15f07d3733d4fc4b4520ce74cbac2cf4f
prerequisite-patch-id: 19f2c7abf0b0ca888bff7097a2e039d3676eb1dc
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices
2026-05-30 22:57 [PATCH v14 0/2] Introduce Synology Microp driver Markus Probst via B4 Relay
@ 2026-05-30 22:57 ` Markus Probst via B4 Relay
2026-05-30 23:05 ` sashiko-bot
2026-05-30 22:57 ` [PATCH v14 2/2] platform: Add initial synology microp driver Markus Probst via B4 Relay
1 sibling, 1 reply; 5+ messages in thread
From: Markus Probst via B4 Relay @ 2026-05-30 22:57 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, Bryan O'Donoghue,
Lee Jones, Pavel Machek, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Greg Kroah-Hartman
Cc: platform-driver-x86, linux-leds, devicetree, linux-kernel,
rust-for-linux, Markus Probst, Krzysztof Kozlowski
From: Markus Probst <markus.probst@posteo.de>
Add the Synology Microp devicetree bindings. Those devices are
microcontrollers found on Synology NAS devices. They are connected to a
serial port on the host device.
Those devices are used to control certain LEDs, fan speeds, a beeper, to
handle buttons, fan failures and to properly shutdown and reboot the
device.
The device has a different feature set depending on the Synology NAS
model, like having different number of fans, buttons and leds. Depending
on the architecture of the model, they also need a different system
shutdown behaviour.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
.../synology,ds918p-microp.yaml | 100 +++++++++++++++++++++
1 file changed, 100 insertions(+)
diff --git a/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml b/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
new file mode 100644
index 000000000000..eb1c9d3fac07
--- /dev/null
+++ b/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/embedded-controller/synology,ds918p-microp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synology NAS on-board Microcontroller
+
+maintainers:
+ - Markus Probst <markus.probst@posteo.de>
+
+description: |
+ Synology Microp is a microcontroller found in Synology NAS devices.
+ It is connected to a serial port on the host device.
+
+ It is necessary to properly shutdown and reboot the NAS device and
+ provides additional functionality such as led control, fan speed control,
+ a beeper and buttons on the NAS device.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - synology,ds1221rpp-microp
+ - synology,rs822p-microp
+ - synology,rs422p-microp
+ - const: synology,rs1221p-microp
+
+ - items:
+ - const: synology,ds1825p-microp
+ - const: synology,ds1823xsp-microp
+
+ - items:
+ - enum:
+ - synology,ds725p-microp
+ - synology,ds225p-microp
+ - synology,ds723p-microp
+ - synology,ds710p-microp
+ - const: synology,ds214play-microp
+
+ - items:
+ - enum:
+ - synology,ds425p-microp
+ - synology,ds1525p-microp
+ - synology,ds925p-microp
+ - synology,ds923p-microp
+ - synology,ds1522p-microp
+ - synology,ds1010p-microp
+ - synology,ds411p-microp
+ - const: synology,ds918p-microp
+
+ - items:
+ - enum:
+ - synology,ds124-microp
+ - synology,ds223j-microp
+ - synology,ds223-microp
+ - const: synology,ds118-microp
+
+ - enum:
+ - synology,ds118-microp
+ - synology,ds1823xsp-microp
+ - synology,rs1221p-microp
+ - synology,ds918p-microp
+ - synology,ds214play-microp
+
+ fan-failure-gpios:
+ description: GPIOs needed to determine which fans stopped working on a fan failure event.
+ minItems: 2
+ maxItems: 3
+
+required:
+ - compatible
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - synology,ds918p-microp
+ - synology,rs422p-microp
+ then:
+ required:
+ - fan-failure-gpios
+ else:
+ properties:
+ fan-failure-gpios: false
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ embedded-controller {
+ compatible = "synology,ds923p-microp", "synology,ds918p-microp";
+
+ fan-failure-gpios = <&gpio 68 GPIO_ACTIVE_HIGH>, <&gpio 69 GPIO_ACTIVE_HIGH>;
+ };
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v14 2/2] platform: Add initial synology microp driver
2026-05-30 22:57 [PATCH v14 0/2] Introduce Synology Microp driver Markus Probst via B4 Relay
2026-05-30 22:57 ` [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices Markus Probst via B4 Relay
@ 2026-05-30 22:57 ` Markus Probst via B4 Relay
2026-05-30 23:16 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Markus Probst via B4 Relay @ 2026-05-30 22:57 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, Bryan O'Donoghue,
Lee Jones, Pavel Machek, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Greg Kroah-Hartman
Cc: platform-driver-x86, linux-leds, devicetree, linux-kernel,
rust-for-linux, Markus Probst
From: Markus Probst <markus.probst@posteo.de>
Add a initial synology microp driver, written in Rust.
The driver targets a microcontroller found in Synology NAS devices. It
currently only supports controlling of the power led, status led, alert
led and usb led. Other components such as fan control or handling
on-device buttons will be added once the required rust abstractions are
there.
This driver can be used both on arm and x86, thus it goes into the root
directory of drivers/platform.
Tested successfully on a Synology DS923+.
Signed-off-by: Markus Probst <markus.probst@posteo.de>
---
MAINTAINERS | 7 +
drivers/platform/Kconfig | 2 +
drivers/platform/Makefile | 1 +
drivers/platform/synology_microp/Kconfig | 13 +
drivers/platform/synology_microp/Makefile | 3 +
drivers/platform/synology_microp/command.rs | 54 ++++
drivers/platform/synology_microp/led.rs | 297 +++++++++++++++++++++
drivers/platform/synology_microp/model.rs | 49 ++++
.../platform/synology_microp/synology_microp.rs | 91 +++++++
9 files changed, 517 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 6e974a518a25..e032b4a1566c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25838,6 +25838,13 @@ F: drivers/dma-buf/sync_*
F: include/linux/sync_file.h
F: include/uapi/linux/sync_file.h
+SYNOLOGY MICROP DRIVER
+M: Markus Probst <markus.probst@posteo.de>
+L: platform-driver-x86@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
+F: drivers/platform/synology_microp/
+
SYNOPSYS ARC ARCHITECTURE
M: Vineet Gupta <vgupta@kernel.org>
L: linux-snps-arc@lists.infradead.org
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 312788f249c9..996050566a4a 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -22,3 +22,5 @@ source "drivers/platform/arm64/Kconfig"
source "drivers/platform/raspberrypi/Kconfig"
source "drivers/platform/wmi/Kconfig"
+
+source "drivers/platform/synology_microp/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index fa322e7f8716..2381872e9133 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
obj-$(CONFIG_BCM2835_VCHIQ) += raspberrypi/
obj-$(CONFIG_ACPI_WMI) += wmi/
+obj-$(CONFIG_SYNOLOGY_MICROP) += synology_microp/
diff --git a/drivers/platform/synology_microp/Kconfig b/drivers/platform/synology_microp/Kconfig
new file mode 100644
index 000000000000..8878cfb7bcdd
--- /dev/null
+++ b/drivers/platform/synology_microp/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config SYNOLOGY_MICROP
+ tristate "Synology Microp driver"
+ depends on LEDS_CLASS && LEDS_CLASS_MULTICOLOR
+ depends on RUST_SERIAL_DEV_BUS_ABSTRACTIONS
+ help
+ Enable support for the EC found in Synology NAS devices.
+
+ This is needed to properly shutdown and reboot the device, as well as
+ additional functionality like fan and LED control.
+
+ This driver is work in progress and may not be fully functional.
diff --git a/drivers/platform/synology_microp/Makefile b/drivers/platform/synology_microp/Makefile
new file mode 100644
index 000000000000..63585ccf76e4
--- /dev/null
+++ b/drivers/platform/synology_microp/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += synology_microp.o
diff --git a/drivers/platform/synology_microp/command.rs b/drivers/platform/synology_microp/command.rs
new file mode 100644
index 000000000000..58cb2f3cb3da
--- /dev/null
+++ b/drivers/platform/synology_microp/command.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::{
+ device::Bound,
+ error::Result,
+ serdev, //
+};
+
+use crate::led;
+
+#[expect(
+ clippy::enum_variant_names,
+ reason = "future variants will not end with Led"
+)]
+pub(crate) enum Command {
+ PowerLed(led::State),
+ StatusLed(led::StatusLedColor, led::State),
+ AlertLed(led::State),
+ UsbLed(led::State),
+ EsataLed(led::State),
+}
+
+impl Command {
+ pub(crate) fn write(self, dev: &serdev::Device<Bound>) -> Result {
+ dev.write_all(
+ match self {
+ Self::PowerLed(led::State::On) => &[0x34],
+ Self::PowerLed(led::State::Blink) => &[0x35],
+ Self::PowerLed(led::State::Off) => &[0x36],
+
+ Self::StatusLed(_, led::State::Off) => &[0x37],
+ Self::StatusLed(led::StatusLedColor::Green, led::State::On) => &[0x38],
+ Self::StatusLed(led::StatusLedColor::Green, led::State::Blink) => &[0x39],
+ Self::StatusLed(led::StatusLedColor::Amber, led::State::On) => &[0x3A],
+ Self::StatusLed(led::StatusLedColor::Amber, led::State::Blink) => &[0x3B],
+
+ Self::AlertLed(led::State::On) => &[0x4C, 0x41, 0x31],
+ Self::AlertLed(led::State::Blink) => &[0x4C, 0x41, 0x32],
+ Self::AlertLed(led::State::Off) => &[0x4C, 0x41, 0x33],
+
+ Self::UsbLed(led::State::On) => &[0x40],
+ Self::UsbLed(led::State::Blink) => &[0x41],
+ Self::UsbLed(led::State::Off) => &[0x42],
+
+ Self::EsataLed(led::State::On) => &[0x4C, 0x45, 0x31],
+ Self::EsataLed(led::State::Blink) => &[0x4C, 0x45, 0x32],
+ Self::EsataLed(led::State::Off) => &[0x4C, 0x45, 0x33],
+ },
+ serdev::Timeout::Max,
+ )?;
+ dev.wait_until_sent(serdev::Timeout::Max);
+ Ok(())
+ }
+}
diff --git a/drivers/platform/synology_microp/led.rs b/drivers/platform/synology_microp/led.rs
new file mode 100644
index 000000000000..4454f06bca4c
--- /dev/null
+++ b/drivers/platform/synology_microp/led.rs
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::{
+ device::Bound,
+ led::{
+ self,
+ LedOps,
+ MultiColorSubLed, //
+ },
+ new_mutex,
+ prelude::*,
+ serdev,
+ str::CString,
+ sync::Mutex,
+ time::Delta, //
+};
+use pin_init::pin_init_scope;
+
+use crate::{
+ command::Command,
+ model::Model, //
+};
+
+#[pin_data]
+pub(crate) struct Data<'bound> {
+ #[pin]
+ status: led::MultiColorDevice<'bound, StatusLedHandler>,
+ power_name: CString,
+ #[pin]
+ power: led::Device<'bound, LedHandler>,
+ alert: Option<Pin<KBox<led::Device<'bound, LedHandler>>>>,
+ usb_copy: Option<Pin<KBox<led::Device<'bound, LedHandler>>>>,
+ esata: Option<Pin<KBox<led::Device<'bound, LedHandler>>>>,
+}
+
+impl<'bound> Data<'bound> {
+ pub(super) fn register<'a>(
+ dev: &'bound serdev::Device<Bound>,
+ model: &'a Model,
+ ) -> impl PinInit<Self, Error> + 'a
+ where
+ 'bound: 'a,
+ {
+ pin_init_scope(move || {
+ Ok(try_pin_init!(Self {
+ status <- led::DeviceBuilder::new()
+ .color(led::Color::Multi)
+ .name(c"synology:multicolor:status")
+ .build_multicolor(
+ dev,
+ try_pin_init!(StatusLedHandler {
+ blink <- new_mutex!(false),
+ }),
+ StatusLedHandler::SUBLEDS,
+ ),
+ power_name: CString::try_from_fmt(fmt!(
+ "synology:{}:power",
+ model.led_power.as_c_str().to_str()?
+ ))?,
+ power <- led::DeviceBuilder::new()
+ .color(model.led_power)
+ .name(power_name)
+ .build(
+ dev,
+ try_pin_init!(LedHandler {
+ blink <- new_mutex!(false),
+ command: Command::PowerLed,
+ }),
+ ),
+ alert: {
+ if let Some(color) = model.led_alert {
+ let name = CString::try_from_fmt(fmt!(
+ "synology:{}:alarm",
+ color.as_c_str().to_str()?
+ ))?;
+ Some(KBox::pin_init(
+ led::DeviceBuilder::new().color(color).name(&name).build(
+ dev,
+ try_pin_init!(LedHandler {
+ blink <- new_mutex!(false),
+ command: Command::AlertLed,
+ }),
+ ),
+ GFP_KERNEL,
+ )?)
+ } else {
+ None
+ }
+ },
+ usb_copy: {
+ if model.led_usb_copy {
+ Some(KBox::pin_init(
+ led::DeviceBuilder::new()
+ .color(led::Color::Green)
+ .name(c"synology:green:usb")
+ .build(
+ dev,
+ try_pin_init!(LedHandler {
+ blink <- new_mutex!(false),
+ command: Command::UsbLed,
+ }),
+ ),
+ GFP_KERNEL,
+ )?)
+ } else {
+ None
+ }
+ },
+ esata: {
+ if model.led_esata {
+ Some(KBox::pin_init(
+ led::DeviceBuilder::new()
+ .color(led::Color::Green)
+ .name(c"synology:green:esata")
+ .build(
+ dev,
+ try_pin_init!(LedHandler {
+ blink <- new_mutex!(false),
+ command: Command::EsataLed,
+ }),
+ ),
+ GFP_KERNEL,
+ )?)
+ } else {
+ None
+ }
+ },
+ }))
+ })
+ }
+}
+
+#[derive(Copy, Clone)]
+pub(crate) enum StatusLedColor {
+ Green,
+ Amber,
+}
+
+#[derive(Copy, Clone)]
+pub(crate) enum State {
+ On,
+ Blink,
+ Off,
+}
+
+#[pin_data]
+struct LedHandler {
+ #[pin]
+ blink: Mutex<bool>,
+ command: fn(State) -> Command,
+}
+
+/// Blink delay measured using video recording on DS923+ for Power and Status Led.
+///
+/// We assume it is the same for all other leds and models.
+const BLINK_DELAY: Delta = Delta::from_millis(167);
+
+#[vtable]
+impl LedOps for LedHandler {
+ type Bus = serdev::Device<Bound>;
+ type Mode = led::Normal;
+ const BLOCKING: bool = true;
+ const MAX_BRIGHTNESS: u32 = 1;
+
+ fn brightness_set<'bound>(
+ &self,
+ dev: &'bound Self::Bus,
+ _classdev: &led::Device<'bound, Self>,
+ brightness: u32,
+ ) -> Result<()> {
+ let mut blink = self.blink.lock();
+ (self.command)(if brightness == 0 {
+ *blink = false;
+ State::Off
+ } else if *blink {
+ State::Blink
+ } else {
+ State::On
+ })
+ .write(dev)?;
+
+ Ok(())
+ }
+
+ fn blink_set<'bound>(
+ &self,
+ dev: &'bound Self::Bus,
+ _classdev: &led::Device<'bound, Self>,
+ delay_on: &mut usize,
+ delay_off: &mut usize,
+ ) -> Result<()> {
+ let mut blink = self.blink.lock();
+
+ (self.command)(if *delay_on == 0 && *delay_off != 0 {
+ *blink = false;
+
+ State::Off
+ } else if *delay_on != 0 && *delay_off == 0 {
+ *blink = false;
+
+ State::On
+ } else {
+ *blink = true;
+ *delay_on = BLINK_DELAY.as_millis() as usize;
+ *delay_off = BLINK_DELAY.as_millis() as usize;
+
+ State::Blink
+ })
+ .write(dev)
+ }
+}
+
+#[pin_data]
+struct StatusLedHandler {
+ #[pin]
+ blink: Mutex<bool>,
+}
+
+impl StatusLedHandler {
+ const SUBLEDS: &[MultiColorSubLed] = &[
+ MultiColorSubLed::new(led::Color::Green).initial_intensity(1),
+ MultiColorSubLed::new(led::Color::Amber),
+ ];
+}
+
+#[vtable]
+impl LedOps for StatusLedHandler {
+ type Bus = serdev::Device<Bound>;
+ type Mode = led::MultiColor;
+ const BLOCKING: bool = true;
+ const MAX_BRIGHTNESS: u32 = 1;
+
+ fn brightness_set<'bound>(
+ &self,
+ dev: &'bound Self::Bus,
+ classdev: &led::MultiColorDevice<'bound, Self>,
+ brightness: u32,
+ ) -> Result<()> {
+ let mut blink = self.blink.lock();
+ if brightness == 0 {
+ *blink = false;
+ }
+
+ let (color, subled_brightness) = if classdev.subleds()[1].intensity == 0 {
+ (StatusLedColor::Green, classdev.subleds()[0].brightness)
+ } else {
+ (StatusLedColor::Amber, classdev.subleds()[1].brightness)
+ };
+
+ Command::StatusLed(
+ color,
+ if subled_brightness == 0 {
+ State::Off
+ } else if *blink {
+ State::Blink
+ } else {
+ State::On
+ },
+ )
+ .write(dev)
+ }
+
+ fn blink_set<'bound>(
+ &self,
+ dev: &'bound Self::Bus,
+ classdev: &led::MultiColorDevice<'bound, Self>,
+ delay_on: &mut usize,
+ delay_off: &mut usize,
+ ) -> Result<()> {
+ let mut blink = self.blink.lock();
+ *blink = true;
+
+ let (color, subled_intensity) = if classdev.subleds()[1].intensity == 0 {
+ (StatusLedColor::Green, classdev.subleds()[0].intensity)
+ } else {
+ (StatusLedColor::Amber, classdev.subleds()[1].intensity)
+ };
+ Command::StatusLed(
+ color,
+ if *delay_on == 0 && *delay_off != 0 {
+ *blink = false;
+ State::Off
+ } else if subled_intensity == 0 {
+ State::Off
+ } else if *delay_on != 0 && *delay_off == 0 {
+ *blink = false;
+ State::On
+ } else {
+ *delay_on = BLINK_DELAY.as_millis() as usize;
+ *delay_off = BLINK_DELAY.as_millis() as usize;
+
+ State::Blink
+ },
+ )
+ .write(dev)
+ }
+}
diff --git a/drivers/platform/synology_microp/model.rs b/drivers/platform/synology_microp/model.rs
new file mode 100644
index 000000000000..715d8840f56b
--- /dev/null
+++ b/drivers/platform/synology_microp/model.rs
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use kernel::led::Color;
+
+pub(crate) struct Model {
+ pub(crate) led_power: Color,
+ pub(crate) led_alert: Option<Color>,
+ pub(crate) led_usb_copy: bool,
+ pub(crate) led_esata: bool,
+}
+
+impl Model {
+ pub(super) const fn new() -> Self {
+ Self {
+ led_power: Color::Blue,
+ led_alert: None,
+ led_usb_copy: false,
+ led_esata: false,
+ }
+ }
+
+ pub(super) const fn led_power(self, color: Color) -> Self {
+ Self {
+ led_power: color,
+ ..self
+ }
+ }
+
+ pub(super) const fn led_alert(self, color: Color) -> Self {
+ Self {
+ led_alert: Some(color),
+ ..self
+ }
+ }
+
+ pub(super) const fn led_esata(self) -> Self {
+ Self {
+ led_esata: true,
+ ..self
+ }
+ }
+
+ pub(super) const fn led_usb_copy(self) -> Self {
+ Self {
+ led_usb_copy: true,
+ ..self
+ }
+ }
+}
diff --git a/drivers/platform/synology_microp/synology_microp.rs b/drivers/platform/synology_microp/synology_microp.rs
new file mode 100644
index 000000000000..f7168309e611
--- /dev/null
+++ b/drivers/platform/synology_microp/synology_microp.rs
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Synology Microp driver
+
+use kernel::{
+ device,
+ led::Color,
+ of::{
+ DeviceId,
+ IdTable, //
+ },
+ of_device_table,
+ prelude::*,
+ serdev, //
+};
+use pin_init::pin_init_scope;
+
+use crate::model::Model;
+
+pub(crate) mod command;
+mod led;
+mod model;
+
+kernel::module_serdev_device_driver! {
+ type: SynologyMicropDriver<'static>,
+ name: "synology_microp",
+ authors: ["Markus Probst <markus.probst@posteo.de>"],
+ description: "Synology Microp driver",
+ license: "GPL v2",
+}
+
+#[rustfmt::skip]
+of_device_table!(
+ OF_TABLE,
+ MODULE_OF_TABLE,
+ Model,
+ [
+ // apollolake
+ (DeviceId::new(c"synology,ds918p-microp"), Model::new()),
+
+ // evansport
+ (DeviceId::new(c"synology,ds214play-microp"), Model::new()),
+
+ // geminilakenk
+ (DeviceId::new(c"synology,ds225p-microp"), Model::new().led_usb_copy()),
+
+ // pineview
+ (DeviceId::new(c"synology,ds710p-microp"), Model::new().led_esata()),
+ (DeviceId::new(c"synology,ds1010p-microp"), Model::new().led_alert(Color::Amber)),
+
+ // rtd1296
+ (DeviceId::new(c"synology,ds118-microp"), Model::new()),
+
+ // rtd1619b
+ (DeviceId::new(c"synology,ds223-microp"), Model::new().led_usb_copy()),
+
+ // v1000
+ (DeviceId::new(c"synology,ds1823xsp-microp"), Model::new()),
+ (DeviceId::new(c"synology,rs1221p-microp"), Model::new().led_power(Color::Green)),
+ ]
+);
+
+#[pin_data]
+struct SynologyMicropDriver<'bound> {
+ #[pin]
+ led: led::Data<'bound>,
+}
+
+#[vtable]
+impl serdev::Driver for SynologyMicropDriver<'_> {
+ type IdInfo = Model;
+ type Data<'bound> = SynologyMicropDriver<'bound>;
+ const OF_ID_TABLE: Option<IdTable<Self::IdInfo>> = Some(&OF_TABLE);
+
+ fn probe<'bound>(
+ dev: &'bound serdev::Device<device::Core<'_>>,
+ model: Option<&'bound Model>,
+ ) -> impl PinInit<Self::Data<'bound>, kernel::error::Error> + 'bound {
+ pin_init_scope(move || {
+ let model = model.ok_or(EINVAL)?;
+
+ dev.set_baudrate(9600).map_err(|_| EINVAL)?;
+ dev.set_flow_control(false);
+ dev.set_parity(serdev::Parity::None)?;
+
+ Ok(try_pin_init!(SynologyMicropDriver {
+ led <- led::Data::register(dev, model),
+ }))
+ })
+ }
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices
2026-05-30 22:57 ` [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices Markus Probst via B4 Relay
@ 2026-05-30 23:05 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-05-30 23:05 UTC (permalink / raw)
To: Markus Probst via B4 Relay; +Cc: robh, devicetree, conor+dt, ojeda
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The compatible string `synology,ds1221rpp-microp` is a typographical error for `synology,rs1221rpp-microp`.
--
commit 75e2ac8371810f3cce7ca7c6e847f04807d5bf10
Author: Markus Probst <markus.probst@posteo.de>
dt-bindings: embedded-controller: Add synology microp devices
This commit introduces device tree bindings for the Synology Microp
microcontrollers found on Synology NAS devices. These controllers manage
LEDs, fan speeds, power behavior, and other hardware features across various
NAS models.
> diff --git a/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml b/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
> new file mode 100644
> index 0000000000000..eb1c9d3fac074
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/embedded-controller/synology,ds918p-microp.yaml
[ ... ]
> +properties:
> + compatible:
> + oneOf:
> + - items:
> + - enum:
> + - synology,ds1221rpp-microp
[Severity: Medium]
This isn't a bug, but is this compatible string a typo for
synology,rs1221rpp-microp?
Synology uses "RS" (RackStation) for models with the "RP+" designation
(Redundant Power Plus). There is no DiskStation ("DS") model named DS1221RP+.
This string is also grouped with other RackStation models and correctly falls
back to synology,rs1221p-microp.
> + - synology,rs822p-microp
> + - synology,rs422p-microp
> + - const: synology,rs1221p-microp
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260531-synology_microp_initial-v14-0-1377d425b24b@posteo.de?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v14 2/2] platform: Add initial synology microp driver
2026-05-30 22:57 ` [PATCH v14 2/2] platform: Add initial synology microp driver Markus Probst via B4 Relay
@ 2026-05-30 23:16 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-05-30 23:16 UTC (permalink / raw)
To: Markus Probst via B4 Relay; +Cc: ojeda, robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Use-after-free of dynamically allocated LED device names.
- [High] Concurrent operations across different LEDs can interleave multi-byte commands over the shared serial bus.
- [Medium] Setting a non-zero brightness fails to clear the hardware blink state.
- [Medium] StatusLedHandler::blink_set fails to update its internal blink state when stopping a blink while subled intensity is 0.
- [Low] Dependency on a non-existent Kconfig symbol 'RUST_SERIAL_DEV_BUS_ABSTRACTIONS'.
--
commit 667b721a5d920b45bcf6f6fe67ef8c56b057c3be
Author: Markus Probst <markus.probst@posteo.de>
platform: Add initial synology microp driver
Add a initial synology microp driver, written in Rust.
The driver targets a microcontroller found in Synology NAS devices. It
currently only supports controlling of the power led, status led, alert
led and usb led.
> diff --git a/drivers/platform/synology_microp/Kconfig b/drivers/platform/synology_microp/Kconfig
> new file mode 100644
> index 0000000000000..8878cfb7bcddb
> --- /dev/null
> +++ b/drivers/platform/synology_microp/Kconfig
> @@ -0,0 +1,13 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +config SYNOLOGY_MICROP
> + tristate "Synology Microp driver"
> + depends on LEDS_CLASS && LEDS_CLASS_MULTICOLOR
> + depends on RUST_SERIAL_DEV_BUS_ABSTRACTIONS
[Severity: Low]
Does the dependency RUST_SERIAL_DEV_BUS_ABSTRACTIONS exist?
Searching the tree doesn't show this symbol, which might cause silent build
failures or make the driver unselectable.
[ ... ]
> diff --git a/drivers/platform/synology_microp/command.rs b/drivers/platform/synology_microp/command.rs
[ ... ]
> +impl Command {
> + pub(crate) fn write(self, dev: &serdev::Device<Bound>) -> Result {
> + dev.write_all(
> + match self {
[Severity: High]
Can concurrent LED operations interleave multi-byte commands over the shared
serial bus?
Since LedHandler and StatusLedHandler can be invoked concurrently via sysfs,
they lock their own local blink mutex but do not lock a shared driver-level
mutex before calling Command::write().
Since dev.write_all() and dev.wait_until_sent() are called concurrently
without mutual exclusion for multi-byte sequences (for example, the 3-byte
sequence for AlertLed), the bytes could interleave.
Could this send corrupted command streams to the hardware?
[ ... ]
> diff --git a/drivers/platform/synology_microp/led.rs b/drivers/platform/synology_microp/led.rs
[ ... ]
> +#[pin_data]
> +pub(crate) struct Data<'bound> {
> + #[pin]
> + status: led::MultiColorDevice<'bound, StatusLedHandler>,
> + power_name: CString,
> + #[pin]
> + power: led::Device<'bound, LedHandler>,
[Severity: Critical]
Does declaring power_name before power lead to a use-after-free during
device unbind?
Rust drops struct fields strictly in declaration order. If power_name is
dropped before power, the underlying C struct led_classdev (which only
stores the raw string pointer) might be left with a dangling pointer before
the LED device is finally unregistered.
[ ... ]
> + alert: {
> + if let Some(color) = model.led_alert {
> + let name = CString::try_from_fmt(fmt!(
> + "synology:{}:alarm",
> + color.as_c_str().to_str()?
> + ))?;
> + Some(KBox::pin_init(
> + led::DeviceBuilder::new().color(color).name(&name).build(
[Severity: Critical]
Is the name variable dropped at the end of this block, resulting in a
dangling pointer?
The C struct led_classdev does not copy the string assigned to its name
field, it merely stores the raw pointer.
Once this block ends, the local CString goes out of scope, which leaves a
dangling pointer in the LED device for its entire lifetime. This could cause
memory corruption when the device name is accessed via sysfs.
[ ... ]
> + fn brightness_set<'bound>(
> + &self,
> + dev: &'bound Self::Bus,
> + _classdev: &led::Device<'bound, Self>,
> + brightness: u32,
> + ) -> Result<()> {
> + let mut blink = self.blink.lock();
> + (self.command)(if brightness == 0 {
> + *blink = false;
> + State::Off
> + } else if *blink {
> + State::Blink
> + } else {
[Severity: Medium]
Should setting a non-zero brightness clear the active hardware blink state?
According to the LED subsystem semantics, setting a non-zero brightness
should clear any active hardware blinking and set the LED to solid on.
Here, if the internal blink state is true, the driver commands State::Blink
instead of solid on, and leaves the internal blink variable as true. This
prevents userspace from stopping a blink by simply setting the brightness.
[ ... ]
> + Command::StatusLed(
> + color,
> + if subled_brightness == 0 {
> + State::Off
> + } else if *blink {
> + State::Blink
> + } else {
[Severity: Medium]
Similarly, for the multicolor status LED, should a non-zero subled
brightness clear the active hardware blink state instead of continuing
to command State::Blink?
[ ... ]
> + fn blink_set<'bound>(
> + &self,
> + dev: &'bound Self::Bus,
> + classdev: &led::MultiColorDevice<'bound, Self>,
> + delay_on: &mut usize,
> + delay_off: &mut usize,
> + ) -> Result<()> {
> + let mut blink = self.blink.lock();
> + *blink = true;
> +
> + let (color, subled_intensity) = if classdev.subleds()[1].intensity == 0 {
> + (StatusLedColor::Green, classdev.subleds()[0].intensity)
> + } else {
> + (StatusLedColor::Amber, classdev.subleds()[1].intensity)
> + };
> + Command::StatusLed(
> + color,
> + if *delay_on == 0 && *delay_off != 0 {
> + *blink = false;
> + State::Off
> + } else if subled_intensity == 0 {
> + State::Off
> + } else if *delay_on != 0 && *delay_off == 0 {
[Severity: Medium]
If a user attempts to stop blinking but the subled intensity is 0, does the
internal blink state diverge from the requested state?
The blink state is unconditionally set to true at the beginning of the
function. If the subled_intensity == 0 branch is taken, it commands
State::Off but fails to set blink to false.
Later, if the subled intensity increases, brightness_set will see that blink
is still true and erroneously command the LED to blink instead of staying
solidly on.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260531-synology_microp_initial-v14-0-1377d425b24b@posteo.de?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-30 23:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-30 22:57 [PATCH v14 0/2] Introduce Synology Microp driver Markus Probst via B4 Relay
2026-05-30 22:57 ` [PATCH v14 1/2] dt-bindings: embedded-controller: Add synology microp devices Markus Probst via B4 Relay
2026-05-30 23:05 ` sashiko-bot
2026-05-30 22:57 ` [PATCH v14 2/2] platform: Add initial synology microp driver Markus Probst via B4 Relay
2026-05-30 23:16 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox