Custom tty line discipline driver
As far as I can tell, one way to do this in Linux would be to write a custom tty line discipline kernel driver that implements the Linux LED API and sends the commands to the serial port. Then the Linux LED code can be in a kernel driver, but it's not tied to a specific serial port.
Then, to link it to a particular serial port, a userspace program would open the serial port, and use an ioctl(serial_fd, TIOCSETD, ...)
call to attach the serial port to the custom line discipline driver. The line discipline driver does all the work from that point. The userspace program's only purpose is really to associate the custom line discipline driver with the right serial device.
Pseudo-driver using FUSE filesystem
One alternative would be to write a userspace program that is a "pseudo-driver", that connects to the serial device, and provides an LED API resembling the Linux kernel LED class API, but at a different location, using a FUSE filesystem.
For example, the program might be named foo-serial-leds
and it could provide a number of LEDs under /var/run/foo-serial-leds/
with an API resembling the Linux kernel LED class drivers.
Then another program could control the LEDs by writing to e.g. /var/run/foo-serial-leds/status/brightness
. That would be very similar to the program controlling a real Linux kernel LED class at /sys/class/leds/status/brightness
, except the location on the filesystem is different. That program would be portable to another platform, with different LED devices, as long as the program has a configurable filesystem path for the LEDs it wants to control.
Two disadvantages of this:
- The program that wants to control the LED must be flexible enough to access the LED file API in a different location than the normal
/sys/class/leds/
- These pseudo-driver LEDs can't use Linux kernel LED triggers
Custom driver to allow userspace creation of LED devices
Another option would be to write a Linux kernel driver that allows for userspace programs to create LED devices in the Linux kernel LED class. The driver could use configfs
to allow userspace programs to create the LED devices, which would then appear under /sys/class/leds/
. It would need to provide a way to notify the userspace program when the LED brightness is changed (maybe via sysfs_notify()
on a custom sysfs attribute, which the userspace program can poll()
).
With that driver in place, a userspace program could implement the LED API and write to the serial device to achieve the LED control. This program is kind of a userspace driver. I.e. it would use the Linux driver to create one or more LED-class LEDs, and open the serial port to talk to the LED hardware. When it is notified that something has written to the LED brightness, it would need to send the relevant command to the serial device.
Then other userspace programs that want to control LEDs would be able to write to the LED-class API in the usual location under /sys/class/leds/
.
Linux kernel 4.10 userspace LED class driver
Update November 2017: Linux kernel 4.10 adds a userspace LED class driver, uleds
. It implements something like what is described above. However, control is via a device /dev/uleds
, not via configfs.
An app should open the char device file /dev/uleds
once for each user LED it wants to create. It should write a struct to the file, which specifies the name of the LED. Then it should do reads from the open file handle, and will receive an int which specifies the brightness of the LED whenever that LED's brightness is changed by something else in the system. If multiple LEDs are to be created, the app should open the char device file multiple times, once for each LED.
When the app closes, and the open file handle(s) to /dev/uleds
is closed, then the user LED is automatically removed.