On Fri, Dec 13, 2019 at 10:34:59PM +0100, Patrick Wildt wrote:
> Hi,
>
> I have a ThingM blink(1) USB RGB device that shows up as uhid(4).
> The tooling is "interesting", especially with all those libusb and
> HID libraries doing the abstraction. This introduces ublink(4), a
> dedicated kernel driver for that device. There are two LEDs on the
> device, which can be modified seperately. The firmware is impress-
> ive and provides features like playing sequences and adjusting how
> long it should take to fade from one colour to another. Obviously
> this also increases the complexity of the tools involved to toggle
> those RGB LEDs. Thus, the driver is kept simple (for now).
>
> In addition to providing a way to set RGB LEDs, we can also use it
> as a watchdog. If we don't "tickle" it in a specific timeframe it
> will play a (unless otherwise programmed) random sequence, which for
> instance can be used to see that the machine has paniced. This has
> been quite useful while debugging the USB stack, because once the
> magic sequence started you know that you're in deep trouble. All
> other features are unimplemented. Gamma correction would be nice
> to have.
>
> Since there is no abstraction layer for LEDs yet, this also intro-
> duces led(4), which attaches to ublink(4), and provides /dev/ledX.
>
> uhidev1 at uhub0 port 3 configuration 1 interface 0 "ThingM blink(1) mk2" rev
> 2.00/0.02 addr 2
> uhidev1: iclass 3/0, 1 report id
> ublink0 at uhidev1 reportid 1
> led0 at ublink0: 2 LEDs
>
> led(4) can be improved even further. We can attach the ThinkPad
> LEDs to it to control it. There are also plenty of mouses that
> have controllable RGBs. We could add "human readable descrip-
> tions", for instance "upper side LED" or "docking station LED",
> so that users can find out more easily which LED they have to
> toggle. A fading or blinking mechanism, including hardware off-
> loading, can probably be added as well.
>
> To be able to control those devices, there's ledctl(1), a simple
> program that can turn on/off /dev/ledX devices and also set RGB
> colours.
>
> I only did the MAKEDEV stuff for amd64, and also there are no
> manpages yet. Also I haven't run it through make build yet,
> sorry. And I don't often do userland tools, so feel free to
> let me know how to improve it.
>
> Thanks,
> Patrick
Updated diff, changes:
* All the manpages!
* /dev/led{0,1,2,...} are now by default 600.
* Doesn't panic when you remove the stick, I think I
might have already had that fixed in the first diff.
* Some small improvements here and there, nothing special.
Thanks to jan for ledctl(1) manpage and review. And thanks to
cheloha@!
Patrick
diff --git a/etc/MAKEDEV.common b/etc/MAKEDEV.common
index c187df748d6..dc67b54ec5a 100644
--- a/etc/MAKEDEV.common
+++ b/etc/MAKEDEV.common
@@ -521,6 +521,8 @@ __devitem(ipmi, ipmi*, IPMI BMC access)dnl
_mkdev(ipmi, ipmi*, {-M ipmi$U c major_ipmi_c $U 600-})dnl
__devitem(gpio, gpio*, General Purpose Input/Output)dnl
_mcdev(gpio, gpio*, gpio, {-major_gpio_c-}, 600)dnl
+__devitem(led, led*, Generic LED devices)dnl
+_mcdev({-led-}, led*, {-led-}, {-major_led_c-}, 600)dnl
__devitem(vmm, vmm, Virtual Machine Monitor)dnl
_mkdev(vmm, vmm, {-M vmm c major_vmm_c 0 600-})dnl
__devitem(pvbus, pvbus*, paravirtual device tree root)dnl
diff --git a/etc/etc.amd64/MAKEDEV b/etc/etc.amd64/MAKEDEV
index 543b0ec731b..50f7ac53acb 100644
--- a/etc/etc.amd64/MAKEDEV
+++ b/etc/etc.amd64/MAKEDEV
@@ -78,6 +78,7 @@
# gpio* General Purpose Input/Output
# hotplug devices hot plugging
# ipmi* IPMI BMC access
+# led* Generic LED devices
# nvram NVRAM access
# kcov Kernel code coverage tracing
# pci* PCI bus devices
@@ -329,6 +330,10 @@ nvram)
M nvram c 85 0 440 kmem
;;
+led*)
+ M led$U c 55 $U 600
+ ;;
+
ipmi*)
M ipmi$U c 96 $U 600
;;
diff --git a/etc/etc.amd64/MAKEDEV.md b/etc/etc.amd64/MAKEDEV.md
index f46b52bd7d6..66e85a16da8 100644
--- a/etc/etc.amd64/MAKEDEV.md
+++ b/etc/etc.amd64/MAKEDEV.md
@@ -76,6 +76,7 @@ _DEV(gpio, 88)
_DEV(hotplug, 82)
_DEV(ipmi, 96)
dnl _DEV(joy, 26)
+_DEV(led, 55)
_DEV(nvram, 85)
_DEV(kcov, 19)
_DEV(pci, 72)
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 307bd44b66b..45ab7539c60 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -41,8 +41,8 @@ MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \
ip.4 ip6.4 ipcomp.4 ipgphy.4 ipmi.4 ips.4 ipsec.4 ipw.4 \
isa.4 isagpio.4 isapnp.4 islrtc.4 it.4 itherm.4 iwi.4 iwn.4 iwm.4 \
ix.4 ixgb.4 ixl.4 jmb.4 jme.4 jmphy.4 \
- kate.4 kcov.4 km.4 ksmn.4 ksyms.4 kubsan.4 kue.4 lc.4 lge.4 lii.4 \
- lisa.4 lm.4 lmenv.4 lmn.4 lmtemp.4 lo.4 lpt.4 lxtphy.4 luphy.4 \
+ kate.4 kcov.4 km.4 ksmn.4 ksyms.4 kubsan.4 kue.4 lc.4 led.4 lge.4 \
+ lii.4 lisa.4 lm.4 lmenv.4 lmn.4 lmtemp.4 lo.4 lpt.4 lxtphy.4 luphy.4 \
maestro.4 mainbus.4 malo.4 maxds.4 maxrtc.4 maxtmp.4 mbg.4 \
mcprtc.4 mcx.4 midi.4 mii.4 mfi.4 \
mfii.4 mlphy.4 moscom.4 mos.4 mpe.4 mpath.4 mpi.4 mpii.4 \
@@ -75,8 +75,8 @@ MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \
tcic.4 tcp.4 termios.4 tht.4 ti.4 tipmic.4 tl.4 \
tlphy.4 thmc.4 tpm.4 tpmr.4 tqphy.4 trm.4 trunk.4 tsl.4 tty.4 \
tun.4 tap.4 twe.4 \
- txp.4 txphy.4 uaudio.4 uark.4 uath.4 ubcmtp.4 uberry.4 ubsa.4 \
- ubsec.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 ukspan.4 uslhcom.4 \
+ txp.4 txphy.4 uaudio.4 uark.4 uath.4 ubcmtp.4 uberry.4 ublink.4 \
+ ubsa.4 ubsec.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 ukspan.4 uslhcom.4 \
udav.4 udcf.4 udl.4 udp.4 udsbr.4 \
uftdi.4 ugen.4 ugl.4 ugold.4 uguru.4 uhci.4 uhid.4 uhidev.4 uipaq.4 \
uk.4 ukbd.4 \
diff --git a/share/man/man4/led.4 b/share/man/man4/led.4
new file mode 100644
index 00000000000..fb06edee73a
--- /dev/null
+++ b/share/man/man4/led.4
@@ -0,0 +1,78 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2019 Patrick Wildt <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt LED 4
+.Os
+.Sh NAME
+.Nm led
+.Nd Generic LED device
+.Sh SYNOPSIS
+.Cd "led* at ublink?"
+.Sh DESCRIPTION
+The
+.Nm
+device attaches to the LED controller and provices a uniform
+programming interface to its LEDs.
+.Pp
+Each LED controller with an attached
+.Nm
+device has an associated device file under the
+.Pa /dev
+directory, e.g.\&
+.Pa /dev/led0 .
+Access from userland is performed through
+.Xr ioctl 2
+calls on these devices.
+.Sh IOCTL INTERFACE
+The following structures and constants are defined in the
+.In sys/gpio.h
+header file:
+.Bl -tag -width XXXX
+.It Dv LED_GET_NUM Fa "unsigned int"
+Returns the number of LEDs on this LED controller.
+.It Dv LED_SET Fa "struct led_set"
+Sets a single LED's state using the
+.Fa led_set
+structur:
+.Bd -literal
+struct led_set {
+ unsigned int led; /* total number of LEDs available */
+ uint32_t rgb; /* colour value to set */
+};
+.Ed
+.El
+.Sh FILES
+.Bl -tag -width "/dev/ledu" -compact
+.It /dev/led Ns Ar u
+LED device unit
+.Ar u
+file.
+.El
+.Sh SEE ALSO
+.Xr ledctl 1 ,
+.Xr ioctl 2
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Ox 6.7 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Patrick Wildt Aq Mt [email protected] .
diff --git a/share/man/man4/ublink.4 b/share/man/man4/ublink.4
new file mode 100644
index 00000000000..3cbc33856d9
--- /dev/null
+++ b/share/man/man4/ublink.4
@@ -0,0 +1,50 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2019 Patrick Wildt <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt UBLINK 4
+.Os
+.Sh NAME
+.Nm ublink
+.Nd ThingM blink(1) USB RGB LED notification light
+.Sh SYNOPSIS
+.Cd "ublink* at uhidev?"
+.Cd "led* at ublink?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the ThingM blink(1) notification light.
+It provides access to its two LEDs using the
+.Xr led 4
+device.
+.Pp
+Additionally it sets up a default watchdog.
+If the host does not respond in a given time, the LEDs will start
+playing a pre-programmed sequence.
+.Sh SEE ALSO
+.Xr led 4 ,
+.Xr uhidev 4
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Ox 6.7 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Patrick Wildt Aq Mt [email protected] .
diff --git a/share/man/man4/uhidev.4 b/share/man/man4/uhidev.4
index 7dafba8fa22..4e93bf6e624 100644
--- a/share/man/man4/uhidev.4
+++ b/share/man/man4/uhidev.4
@@ -37,6 +37,7 @@
.Sh SYNOPSIS
.Cd "uhidev* at uhub?"
.Cd "ubcmtp* at uhidev?"
+.Cd "ublink* at uhidev?"
.Cd "ucycom* at uhidev?"
.Cd "ugold* at uhidev?"
.Cd "uhid* at uhidev?"
@@ -69,6 +70,7 @@ only dispatches data to them based on the report id.
.Sh SEE ALSO
.Xr intro 4 ,
.Xr ubcmtp 4 ,
+.Xr ublink 4 ,
.Xr ucycom 4 ,
.Xr ugold 4 ,
.Xr uhid 4 ,
diff --git a/share/man/man8/man8.amd64/MAKEDEV.8
b/share/man/man8/man8.amd64/MAKEDEV.8
index 02d448eed25..2836f490cf5 100644
--- a/share/man/man8/man8.amd64/MAKEDEV.8
+++ b/share/man/man8/man8.amd64/MAKEDEV.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: MAKEDEV.8,v 1.86 2019/12/17 13:18:05 reyk Exp $
+.\" $OpenBSD$
.\"
.\" THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
.\" generated from:
@@ -23,7 +23,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: December 17 2019 $
+.Dd $Mdocdate: June 6 2017 $
.Dt MAKEDEV 8 amd64
.Os
.Sh NAME
@@ -230,6 +230,9 @@ devices hot plugging, see
.It Ar ipmi*
IPMI BMC access, see
.Xr ipmi 4 .
+.It Ar led*
+Generic LED devices, see
+.Xr led 4 .
.It Ar nvram
NVRAM access, see
.Xr nvram 4 .
diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c
index 6330f6e442d..84b9d2c7ab3 100644
--- a/sys/arch/amd64/amd64/conf.c
+++ b/sys/arch/amd64/amd64/conf.c
@@ -164,6 +164,7 @@ cdev_decl(nvram);
cdev_decl(drm);
#include "viocon.h"
cdev_decl(viocon);
+#include "led.h"
#include "wsdisplay.h"
#include "wskbd.h"
@@ -248,7 +249,7 @@ struct cdevsw cdevsw[] =
cdev_midi_init(NMIDI,midi), /* 52: MIDI I/O */
cdev_notdef(), /* 53 was: sequencer I/O */
cdev_notdef(), /* 54 was: RAIDframe disk driver */
- cdev_notdef(), /* 55: */
+ cdev_led_init(NLED,led), /* 55: led(4) */
/* The following slots are reserved for isdn4bsd. */
cdev_notdef(), /* 56: i4b main device */
cdev_notdef(), /* 57: i4b control device */
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 17e88a9eb51..aae4a516aad 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -280,6 +280,8 @@ ucom* at ucycom?
uslhcom* at uhidev? # Silicon Labs CP2110 USB HID UART
ucom* at uslhcom?
uhid* at uhidev? # USB generic HID support
+ublink* at uhidev? # ThingM blink(1)
+led* at ublink?
fido* at uhidev? # FIDO/U2F security key support
upd* at uhidev? # USB Power Devices sensors
aue* at uhub? # ADMtek AN986 Pegasus Ethernet
diff --git a/sys/conf/files b/sys/conf/files
index 0cef7842919..ab0db72178a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -56,6 +56,11 @@ define i2c_bitbang
# 1-Wire bus bit-banging
define onewire_bitbang
+define led {}
+device led
+file dev/ic/led.c led needs-flag
+attach led at led
+
# net device attributes - we have generic code for ether(net)
define crypto
define ether
diff --git a/sys/dev/ic/led.c b/sys/dev/ic/led.c
new file mode 100644
index 00000000000..3bc8c214394
--- /dev/null
+++ b/sys/dev/ic/led.c
@@ -0,0 +1,139 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+
+#include <dev/ic/led.h>
+
+#ifdef LED_DEBUG
+#define DPRINTF(x) do { if (leddebug) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (leddebug>(n)) printf x; } while (0)
+int leddebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+struct led_softc {
+ struct device sc_dev;
+ unsigned int sc_nled;
+
+ void *sc_cookie;
+ struct led_ctl *sc_ctl;
+};
+
+#define LEDUNIT(dev) (minor(dev))
+
+int led_match(struct device *, void *, void *);
+void led_attach(struct device *, struct device *, void *);
+int led_detach(struct device *, int);
+
+struct cfdriver led_cd = {
+ NULL, "led", DV_DULL
+};
+
+struct cfattach led_ca = {
+ sizeof(struct led_softc), led_match, led_attach, led_detach,
+};
+
+int
+led_match(struct device *parent, void *match, void *aux)
+{
+ return 1;
+}
+
+void
+led_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct led_softc *sc = (struct led_softc *)self;
+ struct led_attach_args *laa = (struct led_attach_args *)aux;
+
+ sc->sc_cookie = laa->cookie;
+ sc->sc_ctl = laa->ctl;
+ sc->sc_nled = laa->nled;
+
+ printf(": %u LEDs\n", sc->sc_nled);
+}
+
+int
+led_detach(struct device *self, int flags)
+{
+ int maj, mn;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == ledopen)
+ break;
+
+ /* Nuke the vnodes for any open instances (calls close). */
+ mn = self->dv_unit;
+ vdevgone(maj, mn, mn, VCHR);
+
+ return 0;
+}
+
+int
+ledopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct led_softc *sc;
+
+ if (LEDUNIT(dev) >= led_cd.cd_ndevs)
+ return ENXIO;
+ sc = led_cd.cd_devs[LEDUNIT(dev)];
+ if (sc == NULL)
+ return ENXIO;
+
+ return 0;
+}
+
+int
+ledclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ return 0;
+}
+
+int
+ledioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
+{
+ struct led_softc *sc;
+ struct led_set *set;
+
+ if (LEDUNIT(dev) >= led_cd.cd_ndevs)
+ return ENXIO;
+ sc = led_cd.cd_devs[LEDUNIT(dev)];
+ if (sc == NULL)
+ return ENXIO;
+
+ switch (cmd) {
+ case LED_GET_NUM:
+ *(unsigned int *)addr = sc->sc_nled;
+ break;
+ case LED_SET:
+ set = (struct led_set *)addr;
+ if (set->led >= sc->sc_nled)
+ return ENXIO;
+ sc->sc_ctl->set_led(sc->sc_cookie, set->led, set->rgb);
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
diff --git a/sys/dev/ic/led.h b/sys/dev/ic/led.h
new file mode 100644
index 00000000000..d738692e35f
--- /dev/null
+++ b/sys/dev/ic/led.h
@@ -0,0 +1,36 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/ioctl.h>
+
+struct led_ctl {
+ void (*set_led)(void *, unsigned int led, uint32_t);
+};
+
+struct led_attach_args {
+ void *cookie;
+ struct led_ctl *ctl;
+ unsigned int nled;
+};
+
+struct led_set {
+ unsigned int led;
+ uint32_t rgb;
+};
+
+#define LED_GET_NUM _IOR ('L', 0, unsigned int)
+#define LED_SET _IOW ('L', 1, struct led_set)
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index 0f697127e92..c3b7ac5a73a 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -473,3 +473,8 @@ file dev/usb/uwacom.c uwacom
attach bwfm at uhub with bwfm_usb: firmload
file dev/usb/if_bwfm_usb.c bwfm_usb
+
+# ThingM blink(1)
+device ublink: led
+attach ublink at uhidbus
+file dev/usb/ublink.c ublink
diff --git a/sys/dev/usb/ublink.c b/sys/dev/usb/ublink.c
new file mode 100644
index 00000000000..4129694a5fd
--- /dev/null
+++ b/sys/dev/usb/ublink.c
@@ -0,0 +1,169 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+
+#include <dev/ic/led.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/uhidev.h>
+
+#define BLINK_FADE_MS 300
+#define BLINK_WATCHDOG_MS 15000
+#define BLINK_TIMEOUT_MS 10000
+
+#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
+
+#ifdef UBLINK_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+struct ublink_softc {
+ struct uhidev sc_hdev;
+ struct usbd_device *sc_udev;
+
+ struct timeout sc_wdog_to;
+};
+
+int ublink_match(struct device *, void *, void *);
+void ublink_attach(struct device *, struct device *, void *);
+int ublink_detach(struct device *, int);
+
+void ublink_watchdog(void *);
+
+void ublink_set_led(void *, unsigned int, uint32_t);
+
+struct led_ctl ublink_ctl = {
+ ublink_set_led
+};
+
+struct cfdriver ublink_cd = {
+ NULL, "ublink", DV_DULL
+};
+
+struct cfattach ublink_ca = {
+ sizeof(struct ublink_softc), ublink_match, ublink_attach, ublink_detach
+};
+
+struct usb_devno ublink_devs[] = {
+ { USB_VENDOR_THINGM, USB_PRODUCT_THINGM_BLINK1 },
+};
+
+int
+ublink_match(struct device *parent, void *match, void *aux)
+{
+ struct uhidev_attach_arg *uha = aux;
+
+ if (uha->reportid == UHIDEV_CLAIM_ALLREPORTID)
+ return UMATCH_NONE;
+
+ if (usb_lookup(ublink_devs, uha->uaa->vendor,
+ uha->uaa->product) == NULL)
+ return UMATCH_NONE;
+
+ return UMATCH_VENDOR_PRODUCT;
+}
+
+void
+ublink_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ublink_softc *sc = (struct ublink_softc *)self;
+ struct uhidev_attach_arg *uha = aux;
+ struct led_attach_args la;
+
+ sc->sc_udev = uha->parent->sc_udev;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_report_id = uha->reportid;
+
+ printf("\n");
+
+ /* Turn on watchdog and repeatedly re-arm. */
+ timeout_set(&sc->sc_wdog_to, ublink_watchdog, sc);
+ timeout_add_msec(&sc->sc_wdog_to, BLINK_TIMEOUT_MS);
+
+ /* Attach led(4). */
+ la.cookie = self;
+ la.ctl = &ublink_ctl;
+ la.nled = 3;
+ config_found(self, &la, NULL);
+}
+
+int
+ublink_detach(struct device *self, int flags)
+{
+ struct ublink_softc *sc = (struct ublink_softc *)self;
+
+ timeout_del(&sc->sc_wdog_to);
+ return config_detach_children(self, flags);
+}
+
+void
+ublink_watchdog(void *self)
+{
+ struct ublink_softc *sc = self;
+ uint8_t buf[7];
+
+ if (usbd_is_dying(sc->sc_udev))
+ return;
+
+ /* "serverdown" */
+ buf[0] = 'D';
+ buf[1] = 1;
+ buf[2] = ((BLINK_WATCHDOG_MS / 10) >> 8);
+ buf[3] = ((BLINK_WATCHDOG_MS / 10) % 0xff);
+ buf[4] = 1;
+ buf[5] = 0;
+ buf[6] = 15;
+
+ uhidev_set_report_async(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT,
+ sc->sc_hdev.sc_report_id, buf, sizeof(buf));
+ timeout_add_msec(&sc->sc_wdog_to, BLINK_TIMEOUT_MS);
+}
+
+void
+ublink_set_led(void *self, unsigned int led, uint32_t rgb)
+{
+ struct ublink_softc *sc = self;
+ uint8_t buf[7];
+
+ if (usbd_is_dying(sc->sc_udev))
+ return;
+
+ if (led > 2)
+ return;
+
+ /* fade to RGB */
+ buf[0] = 'c';
+ buf[1] = (rgb >> 16) & 0xff;
+ buf[2] = (rgb >> 8) & 0xff;
+ buf[3] = rgb & 0xff;
+ buf[4] = ((BLINK_FADE_MS / 10) >> 8);
+ buf[5] = (BLINK_FADE_MS / 10) % 0xff;
+ buf[6] = led;
+
+ uhidev_set_report_async(sc->sc_hdev.sc_parent, UHID_FEATURE_REPORT,
+ sc->sc_hdev.sc_report_id, buf, sizeof(buf));
+}
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index c506a7bcc28..afd673b6b7e 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -630,6 +630,7 @@ vendor TRIPPLITE 0x2478 Tripp-Lite
vendor ARUBA 0x2626 Aruba
vendor XIAOMI 0x2717 Xiaomi
vendor NHJ 0x2770 NHJ
+vendor THINGM 0x27b8 ThingM
vendor ASUSTEK 0x2821 ASUSTeK Computer
vendor PLANEX 0x2c02 Planex Communications
vendor LINKINSTRUMENTS 0x3195 Link Instruments
@@ -4249,6 +4250,9 @@ product TI NEXII 0x5409 Nex II Digital
product TI MSP430_JTAG 0xf430 MSP-FET430UIF JTAG
product TI MSP430 0xf432 MSP-FET430UIF
+/* ThingM products */
+product THINGM BLINK1 0x01ed blink(1)
+
/* Thrustmaster products */
product THRUST FUSION_PAD 0xa0a3 Fusion Digital Gamepad
diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h
index e520ee87431..b74272773b0 100644
--- a/sys/dev/usb/usbdevs.h
+++ b/sys/dev/usb/usbdevs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs.h,v 1.714 2019/12/07 08:47:20 kevlo Exp $ */
+/* $OpenBSD$ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -637,6 +637,7 @@
#define USB_VENDOR_ARUBA 0x2626 /* Aruba */
#define USB_VENDOR_XIAOMI 0x2717 /* Xiaomi */
#define USB_VENDOR_NHJ 0x2770 /* NHJ */
+#define USB_VENDOR_THINGM 0x27b8 /* ThingM */
#define USB_VENDOR_ASUSTEK 0x2821 /* ASUSTeK Computer */
#define USB_VENDOR_PLANEX 0x2c02 /* Planex
Communications */
#define USB_VENDOR_LINKINSTRUMENTS 0x3195 /* Link
Instruments */
@@ -4256,6 +4257,9 @@
#define USB_PRODUCT_TI_MSP430_JTAG 0xf430 /*
MSP-FET430UIF JTAG */
#define USB_PRODUCT_TI_MSP430 0xf432 /* MSP-FET430UIF */
+/* ThingM products */
+#define USB_PRODUCT_THINGM_BLINK1 0x01ed /* blink(1) */
+
/* Thrustmaster products */
#define USB_PRODUCT_THRUST_FUSION_PAD 0xa0a3 /* Fusion
Digital Gamepad */
diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h
index 21b61b04d5a..b2a46a8ef79 100644
--- a/sys/dev/usb/usbdevs_data.h
+++ b/sys/dev/usb/usbdevs_data.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdevs_data.h,v 1.708 2019/12/07 08:47:20 kevlo Exp $
*/
+/* $OpenBSD$ */
/*
* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
@@ -10901,6 +10901,10 @@ const struct usb_known_product usb_known_products[] = {
USB_VENDOR_TI, USB_PRODUCT_TI_MSP430,
"MSP-FET430UIF",
},
+ {
+ USB_VENDOR_THINGM, USB_PRODUCT_THINGM_BLINK1,
+ "blink(1)",
+ },
{
USB_VENDOR_THRUST, USB_PRODUCT_THRUST_FUSION_PAD,
"Fusion Digital Gamepad",
@@ -14041,6 +14045,10 @@ const struct usb_known_vendor usb_known_vendors[] = {
USB_VENDOR_NHJ,
"NHJ",
},
+ {
+ USB_VENDOR_THINGM,
+ "ThingM",
+ },
{
USB_VENDOR_ASUSTEK,
"ASUSTeK Computer",
diff --git a/sys/sys/conf.h b/sys/sys/conf.h
index b43c8374fa5..bf5cac8a98e 100644
--- a/sys/sys/conf.h
+++ b/sys/sys/conf.h
@@ -439,6 +439,13 @@ extern struct cdevsw cdevsw[];
(dev_type_stop((*))) enodev, 0, selfalse, \
(dev_type_mmap((*))) enodev }
+/* open, close, ioctl */
+#define cdev_led_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
+ (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, selfalse, \
+ (dev_type_mmap((*))) enodev }
+
/* open, close, ioctl */
#define cdev_bio_init(c,n) { \
dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \
@@ -586,6 +593,8 @@ cdev_decl(diskmap);
cdev_decl(bpf);
+cdev_decl(led);
+
cdev_decl(pf);
cdev_decl(tun);
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 35a3c00d69f..79b180eefcc 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -11,8 +11,8 @@ SUBDIR= apply arch at aucat audioctl awk banner \
find fgen finger fmt fold from fstat ftp gencat getcap \
getconf getent getopt gprof grep head hexdump htpasswd id indent \
infocmp ipcrm ipcs \
- join jot kdump keynote ktrace lam last lastcomm ldap leave less lex \
- libtool lndir \
+ join jot kdump keynote ktrace lam last lastcomm ldap leave ledctl \
+ less lex libtool lndir \
locale locate lock logger login logname look lorder \
m4 mail make mandoc mesg mg \
midicat mixerctl mkdep mklocale mktemp nc netstat \
diff --git a/usr.bin/ledctl/Makefile b/usr.bin/ledctl/Makefile
new file mode 100644
index 00000000000..35338c8219c
--- /dev/null
+++ b/usr.bin/ledctl/Makefile
@@ -0,0 +1,6 @@
+# $OpenBSD$
+
+PROG= ledctl
+SRCS= ledctl.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/ledctl/ledctl.1 b/usr.bin/ledctl/ledctl.1
new file mode 100644
index 00000000000..300968310a4
--- /dev/null
+++ b/usr.bin/ledctl/ledctl.1
@@ -0,0 +1,93 @@
+.\" $OpenBSD$
+.\"
+.\" Copyright (c) 2019 Jan Klemkow <[email protected]>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt LEDCTL 1
+.Os
+.Sh NAME
+.Nm ledctl
+.Nd sets the colors of LEDs
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar device
+.Op Fl n Ar led
+.Op Ar on|off|rgb
+.Sh DESCRIPTION
+The
+.Nm
+utility turns LEDs
+.Ar on ,
+.Ar off
+or sets their color.
+The color value
+.Ar rgb
+has to be in hex format.
+The parameters
+.Ar on
+and
+.Ar off
+are shortcuts for the color values 0xffffff and 0x000000.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f Ar device
+.Nm
+uses
+the device file
+.Ar device .
+Default is
+.Pa /dev/led0 .
+.It Fl n Ar led
+A
+.Xr led 4
+device may consists of multiple LEDs.
+Sets
+.Ar led
+to the index of the right LED.
+Default is 0.
+.El
+.Sh FILES
+.Pa /dev/led0
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Sets the first LED of
+.Pa /dev/led0
+to red:
+.Bd -literal -offset indent
+$ ledctl 0xff0000
+.Ed
+.Pp
+Sets the second LED of
+.Pa /dev/led0
+to green:
+.Bd -literal -offset indent
+$ ledctl -n 1 0x00ff00
+.Ed
+.Pp
+Sets the first LED of
+.Pa /dev/led2
+to blue:
+.Bd -literal -offset indent
+$ ledctl -f /dev/led2 0x0000ff
+.Ed
+.\".Sh SEE ALSO
+.\".Xr led 4
+.Sh AUTHORS
+The
+.Nm
+program was written by
+.An Patrick Wildt Aq Mt [email protected] .
diff --git a/usr.bin/ledctl/ledctl.c b/usr.bin/ledctl/ledctl.c
new file mode 100644
index 00000000000..e3275c42db0
--- /dev/null
+++ b/usr.bin/ledctl/ledctl.c
@@ -0,0 +1,101 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2019 Patrick Wildt <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <dev/ic/led.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-f device] [-n led] [on|off|rgb]\n",
+ getprogname());
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *dev, *errstr;
+ unsigned int led, nled;
+ struct led_set set;
+ int ch, fd;
+ long rgb;
+ char *ep;
+
+ led = 0;
+ dev = "/dev/led0";
+ while ((ch = getopt(argc, argv, "f:n:")) != -1) {
+ switch (ch) {
+ case 'f':
+ dev = optarg;
+ break;
+ case 'n':
+ led = strtonum(optarg, 0, 64, &errstr);
+ if (errstr != NULL)
+ errx(1, "led is %s: %s", errstr, optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (dev == NULL || argc != 1)
+ usage();
+
+ fd = open(dev, O_RDWR);
+ if (fd == -1)
+ err(1, "%s", dev);
+
+ if (ioctl(fd, LED_GET_NUM, &nled) == -1)
+ err(1, "ioctl LED_GET_NUM");
+
+ if (led >= nled)
+ errx(1, "bogus led: %u (max %u)", led, nled);
+
+ memset(&set, 0, sizeof(set));
+ set.led = led;
+ if (strcmp(argv[0], "on") == 0) {
+ set.rgb = 0xffffff;
+ } else if (strcmp(argv[0], "off") == 0) {
+ set.rgb = 0x000000;
+ } else {
+ errno = 0;
+ rgb = strtol(argv[0], &ep, 16);
+ if (*argv[0] == '\0' || *ep != '\0')
+ errx(1, "bogus color: %s", argv[0]);
+ if (errno == ERANGE && (rgb == LONG_MAX || rgb == LONG_MIN))
+ errx(1, "bogus color: %s", argv[0]);
+ set.rgb = rgb;
+ }
+
+ if (ioctl(fd, LED_SET, &set) == -1)
+ err(1, "ioctl LED_SET");
+
+ return 0;
+}