Ubuntu is fine. Drivers are annoying on all distros (nvidia updates for me mainly, I don’t update hardware often).
I have daily driven various distros and tested a lot since the 90s and I pay close attention to time spent on customizing and fixes, and ubuntu just isn’t worse than other distros. I make setup scripts and have custom dockerfiles for webtops.
I want to like nixos or whatever fork will prevail, but it’s more work than people want to admit. I personally don’t want to have to pay that much attention to my operating system. It’s why i ditched gentoo almost 20 years ago. I don’t want to lurk forums for fixes and tweaks. I also make sure hardware I buy doesn’t have glaring compatibility issues.
If Ubuntu rubs you the wrong way but you are fine with most of it, just use debian.
In a driver, there’s a lot more than just C and hardware interaction. You also have to deal with:
Concurrency and Synchronization – Managing locks, spinlocks, atomic operations, and ensuring safe access to shared resources.
Memory Management – Allocating kernel memory safely, handling DMA buffers, and avoiding memory leaks or invalid accesses.
Interrupt Handling – Dealing with IRQs, deferring work using tasklets, workqueues, or bottom halves.
State Management – Handling suspend, resume, and power states efficiently.
Error Handling and Recovery – Ensuring robustness in the presence of hardware failures or unexpected states.
Device Trees and ACPI – Parsing platform configuration data.
Firmware Communication – Loading and interfacing with device firmware blobs.
Kernel APIs and Subsystems – Interacting with networking, block devices, input devices, and other kernel frameworks.
Performance Optimizations – Managing cache coherency, NUMA awareness, and latency-sensitive operations.
Security Considerations – Preventing privilege escalation, ensuring safe user-space interaction, and sandboxing where applicable.
Yes, interfacing with hardware often requires unsafe Rust or C, but a lot of driver logic isn’t directly interacting with raw hardware registers. Rust can help improve safety in many of these areas by reducing common C pitfalls like use-after-free, null dereferences, and buffer overflows.