2
votes

I have a hardware device that controls LEDs on a panel, and it has a serial port for a PC to control the LEDs.

I would like to be able to control the LEDs from a userspace application using the Linux LED class API, i.e. via /sys/class/leds/whatever/brightness. So I'd like to make a Linux kernel driver for this device.

However, from what I've read, it seems unusual for a Linux kernel driver to open a serial device. E.g. StackOverflow question Accessing a serial port from a linux kernel module. I've read about filp_open() which can be used by kernel drivers to open device files, but its use seems to be discouraged.

On the other hand, it seems impossible to implement this in userspace because I'm not aware of a way to create a Linux LED class device from userspace.

What would be a good way to provide a Linux LED class API interface to a serial port controlled LED device?

  • Disregard the cautions against accessing a serial port from a Linux driver using filp_open()?
  • Is there some userspace way to create a Linux LED class device, so I could implement this in userspace?
  • Give up on the idea of using the Linux LEDs class API, and use an alternative API for the userspace application to control the LEDs?
  • Other?
2
There's one instance of a mainline (albeit staging) driver that uses a UART driver in the kernel, serial2002_open(), which is part of the Comedi project. But I'm not convinced that's the optimal solution for controlling LEDs.sawdust

2 Answers

3
votes

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.

-1
votes

3 Ways:

1 - You must to understand the data send to CPU Board for modify as you want data for display your message on led board.

2 - You must to have a linux API, but most of time the CPU is made in china, the chinese don't like linux.

3 - You write your own API for control LED Board with arduino or raspberry to control each pins of your LED Board.

Good luck !