Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using FTDI in NixOS / with read-only '/etc' #534

Open
zh4ngx opened this issue Jan 11, 2025 · 13 comments
Open

Using FTDI in NixOS / with read-only '/etc' #534

zh4ngx opened this issue Jan 11, 2025 · 13 comments

Comments

@zh4ngx
Copy link

zh4ngx commented Jan 11, 2025

I'm running NixOS and currently running into a FTDI issues.

I can't enable due to '/etc/' not being writable in Nix:

$ sudo apio drivers --ftdi-enable
Configure FTDI drivers for FPGA
cp: cannot create regular file '/etc/udev/rules.d/80-fpga-ftdi.rules': Read-only file system
sudo: service: command not found
FTDI drivers enabled
Unplug and reconnect your board

Just to confirm, can't list ftdi devices, although I'm not super clear what the error message means:

$ apio system --lsftdi
ftdi_usb_get_strings failed: -4 (libusb_open() failed)

Is there a way around having to modify /etc/udev/rules.d/ ? Or is the error indicative of something else?

@zh4ngx
Copy link
Author

zh4ngx commented Jan 11, 2025

For reference, here's apio in nixpkgs: https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/embedded/fpga/apio/default.nix

I don't see libftdi in there, but there is a nixpkg for that as well:
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/libftdi/default.nix

@zapta
Copy link
Collaborator

zapta commented Jan 11, 2025

Thanks @zh4ngx, can you post here what you get using apio system --info or apio system info. I am looking for the apio version and the platform id as apio sees it.

@zh4ngx
Copy link
Author

zh4ngx commented Jan 13, 2025

Sure thing:

$ apio system --info
Platform: linux_x86_64

$ apio --version
apio, version 0.9.5

@zapta
Copy link
Collaborator

zapta commented Jan 13, 2025

Ok, thanks. So you are using the release apio and your platform was identified as a standard linux.

Below is the code (in the apio dev branch, 0.9.6) which installs the ftdi drivers on linux.

secho("Configure FTDI drivers for FPGA")

Any suggestions on...

  1. How to determine that the platform requires the alternative nix installation?

  2. Once we detect that the alternative nix installation is required, what should be the installation steps?

Edit: one valid solution for question 2 is to print to the user instructions on how to install manually. This is how we handle windows:

Please follow these steps:

@zh4ngx
Copy link
Author

zh4ngx commented Jan 14, 2025

Thanks, that is super helpful. Is the following a good characterization of FTDI install?

  1. See if udev rules already set up - if yes, then done.
  2. Copy udev rules to privileged location.
  3. Reload rules
  4. Restart udev service

On point 3., there's an assumption that the system cmd exists, which is not the case for me and might not be on other systems as well.

A few approaches

  1. For the nixpkgs version of apio, I would suggest including the FTDI install as an option upon installation. I'll have to read up more and get back to you on how to best package this in nix. I found a few examples here and here but there may be less heavy-handed approaches.

  2. An alternate, (hopefully) cross-platform approach would be to use buildFHSEnv which builds an FHS sandbox and let's you use things like udev with less modification to existing code/workflows.

@zapta
Copy link
Collaborator

zapta commented Jan 14, 2025

Thanks @zh4ngx, the three steps that you describe seems to be correct. In case we will stay with the existing apio installation process and then use the apio drivers command to install the drivers...

  1. How can apio detect that it's on a nix based system like the one you use and not on a regular linux?

  2. What steps can be done by apio or by an admin manually to install the ftdi driver?

@zh4ngx
Copy link
Author

zh4ngx commented Jan 14, 2025

Ok, it sounds like option 2. I'm not super well-versed in buildFHSEnv so we'd have to ask the nixpkgs apio maintainer for help with this one. To answer your Qs:

  1. I think this would just be part of the nix install itself. apio will install in the nix store like so:
$ type apio
apio is /nix/store/8lnkrsdldnh8jgnda4j6vg6a2yzqqglp-apio-0.9.5/bin/apio
  1. buildFHSEnv should let us just run the install ftdi commands directly

Definitely worth giving this approach a try at is should be a smaller lift. If it doesn't work, we can always try option 1.

@zh4ngx
Copy link
Author

zh4ngx commented Jan 14, 2025

@Luflosi
Copy link

Luflosi commented Jan 15, 2025

Hello 👋 I'm the "maintainer".
"maintainer" in quotes because I haven't really used this package for a few years now, I have just been trying to keep the package updated in Nixpkgs.

On NixOS /etc/udev/rules.d is managed by Nix and is a symlink to a non-writable location, so it's not possible to just copy files there. I think the proper solution would be to write a small NixOS module. A user could then add programs.apio.enable = true to their configuration and the module would install the file in the correct location. I don't think anything special needs to be done in apio itself.

Unfortunately I won't have much time in the next two months, so I can't implement this right now.

I do have a small NixOS module that worked for me a long time ago:

{ config, lib, ... }:

let
  cfg = config.hardware.fomu;
in
{
  options.hardware.fomu = {
    enable = lib.mkOption {
      type = lib.types.bool;
      default = false;
      description = lib.mdDoc ''
        Enables Fomu udev rules and ensures 'fomu' group exists.
        This is a prerequisite to using Fomu devices without being root, since Fomu USB descriptors will be owned by the fomu group through udev.
      '';
    };
    users = lib.mkOption {
      type = with lib.types; listOf str;
      default = [];
      description = lib.mdDoc ''
        Usernames to be added to the "fomu" group, so that they
        can interact with the Fomu device.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    users.groups.fomu = {
      members = cfg.users;
    };

    services.udev.extraRules = ''
      SUBSYSTEM=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5bf0", MODE="0664", GROUP="fomu"
    '';
  };

  meta.maintainers = with lib.maintainers; [ Luflosi ];
}

This is specific to the fomu and doesn't work for any other board. You could use it as a starting point though.
Here is what would need to be done:

  • Rename hardware.fomu to something more appropriate, such as programs.apio
  • Add yourself as a maintainer
  • Remove the users option and the users.groups.fomu setting
  • Add apio to the list of environment.systemPackages, so it's "installed" globally (environment.systemPackages = with pkgs; [ apio ];)
  • Instead of services.udev.extraRules = «string», use services.udev.packages = with pkgs; [ apio ]; and make sure the apio package contains the udev rules at «apio»/etc/udev/rules.d or «apio»/lib/udev/rules.d
  • If I remember correctly, the uaccess tag didn't work correctly on NixOS. I think the reason for this is (was?) that some udev rule from systemd was missing. You would need to find out, which one it is and also add it to services.udev.packages

I encourage you to try to implement this and make a PR to Nixpkgs. Otherwise please open an issue instead (and ping me there).

If you just want a quick and hacky workaround for the moment, I think you can chown the correct file in /dev so that your user has the permission to communicate with the board. Maybe you can find the correct file by looking at dmesg -wH while you plug in the board or check if any new files appear in /dev when you plug it in. The file might be in a subdirectory of /dev though, which may make it more difficult to find the correct file.

@zapta
Copy link
Collaborator

zapta commented Jan 15, 2025

Thanks @Luflosi. This is very useful!

A side question, with the current apio installation (that is, not via a nix package), what is a stable and clean way for apio (and for any other program for that matter) to test if it runs under a nix managed linux?

@zh4ngx
Copy link
Author

zh4ngx commented Jan 16, 2025

Very much appreciate the detailed writeup as well @Luflosi

@zapta

In case this is informative/helpful, here is a paste from dmesg -wH:

[Jan16 15:53] usb 1-5: new high-speed USB device number 6 using xhci_hcd
[  +0.208159] usb 1-5: New USB device found, idVendor=0403, idProduct=6010, bcdDevice= 7.00
[  +0.000005] usb 1-5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  +0.000002] usb 1-5: Product: Alchitry Cu
[  +0.000002] usb 1-5: Manufacturer: Alchitry
[  +0.000002] usb 1-5: SerialNumber: ******
[  +0.039905] usbcore: registered new interface driver ftdi_sio
[  +0.000011] usbserial: USB Serial support registered for FTDI USB Serial Device
[  +0.000099] ftdi_sio 1-5:1.0: FTDI USB Serial Device converter detected
[  +0.000021] usb 1-5: Detected FT2232H
[  +0.004010] usb 1-5: FTDI USB Serial Device converter now attached to ttyUSB0
[  +0.000025] ftdi_sio 1-5:1.1: FTDI USB Serial Device converter detected
[  +0.000034] usb 1-5: Detected FT2232H
[  +0.004927] usb 1-5: FTDI USB Serial Device converter now attached to ttyUSB1

Does this tell us anything interesting/useful about existing FTDI drivers?

@zh4ngx
Copy link
Author

zh4ngx commented Jan 23, 2025

  • If I remember correctly, the uaccess tag didn't work correctly on NixOS. I think the reason for this is (was?) that some udev rule from systemd was missing. You would need to find out, which one it is and also add it to services.udev.packages

Regarding the uaccess tag, is it enough to name the file lexically before /usr/lib/udev/rules.d/73-seat-late.rules like here?

Or are you saying this file doesn't exist in NixOS at all?

@zh4ngx
Copy link
Author

zh4ngx commented Jan 30, 2025

Great news!

I was able to run apio upload after creating a local NixOS module (programs.apio) as suggested - enabled my device with an inline writeTextFile. Note that with 70-ftdi.rules using TAG+="uaccess" is sufficient. Excerpt below:

 services.udev.packages = lib.mkIf cfg.enableFtdiDrivers [
      (pkgs.writeTextFile {
        name = "ftdi-udev-rules";
        text = ''ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", TAG+="uaccess"'';
        destination = "/etc/udev/rules.d/70-ftdi.rules";
      })
    ];

For NixOS users, you can essentially skip the apio drivers step, as you configure this on install. Excerpt below from my configuration.nix.

  programs.apio = {
    enable = true;
    enableFtdiDrivers = true;
  };

It would be great to use/update the udev rules here as described below:

  • Instead of services.udev.extraRules = «string», use services.udev.packages = with pkgs; [ apio ]; and make sure the apio package contains the udev rules at «apio»/etc/udev/rules.d or «apio»/lib/udev/rules.d

@zapta Do we need to move + rename the rules in this repo or is there a better approach?

@Luflosi Is it correct to say udev rules (services.udev) are only available as a NixOS module, not a Home Manager module, and therefore is only configurable globally?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants