While it's still based on the 2.6 kernel, it's probably good enough for the basics. Not sure there is a more modern source.
(Robert Love's Linux Kernel Programming was also a nice introduction to how the Kernel works, though it might be outdated in some areas now as well)
LDD3 goes way more in-depth and teaches you about the specifics of many different classes of device drivers, their interfaces and data structures, as well as where to find the appropriate in-tree documentation.
(both LDD3 and LKMPG are written for the 2.6 kernel. it's a shame there are no newer resources of the same caliber.)
It's part of tldp (also google searchable)
I wonder how someone from the outside is supposed to know that's the magic string to google.
The first result for the utterly mundane, plain English "how to program linux drivers" brings me to this tutorial: https://www.apriorit.com/dev-blog/195-simple-driver-for-linu...
Linked from that tutorial is a hypertext version of the content in that PDF: http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html
That's a beautiful way to put it. You've distilled into one sentence a skill that I've been asked about many, many times (as the token IT guy).
I tried "how to write device drivers under Linux" (in quotes) which showed one result and I ended up at this exact post.
Hi me!
The same way people learn to do many other similar things.
Now I don't know how to write userspace USB drivers, but there has to be something between 0 knowledge and just "trying and immitating"[SIC] kernel source code. At least I'd be happy for more pointers on similar resources as the submitted link, but more beginner oriented.
For learning more about how USB itself works, I highly recommend Jan Axelson's USB Complete[1]. I used an older version of this book to build a from-scratch USB device (on an STM32F0 but not using the built-in USB example code) and libusb-based usermode driver for it.
And what to learn depends on what driver you want to write, so you best start by looking into the code in the relevant subsystem, and read it, understand it, and use it, and learn what you need on the go, based on the needs you discover you have for your driver. Then you may realize what you need to learn, and if you can't grok it from the code, go for the books/presentations/linux kernel docs.
So diving into kernel code is a way to discover what you'll need to learn to write your particular kernel driver. Kernel's api surface is huge, and you'll never learn/need anything, and it's best to only learn what you'll be using soon. And this is one way to discover what that might be for your driver.
For kernel wide resources that the kernel offers (like threads, workqueues, locking primitives, of interfaces, kobj/device interfaces, sysfs attributes, timers, etc.) you can learn them from books, but it's also just as effective to learn them by example simply by going to https://elixir.bootlin.com/linux/latest/source and searching for all references of given function, and learn by example/implementation.
USB userspace drivers are not kernel drivers, so there the situation is different. Interface for writing them is part of kernel-userspace ABI, so you'll be able to use them even with half a decade old guides on the internet.
I aggree that to learn C, you'd probably not start with reading Linux kernel code.
That's not the correct analogy, though. Learning to write a kernel driver would be more analogous to learning how to extend Kubernetes.
So if that was the goal, and it would be known that Kubernetes internals and its interfaces to extensions are constantly evolving/changing, that there'd more value in diving into Kubernetes code, instead of reading up on possibly outdated howto guides or whatever.
There are books such as "Linux Device Drivers", which are great resources, and there is a lot of existing code out there to read too.
The person who asks "How do I do x?" without having appeared to carry out the minimum of self-searching themselves is often impossible to help in any detail anyway.
First of all, I had to realize that the keyboard was in fact controlled via USB. It seems obvious but other Clevo laptops did it via ACPI:
https://github.com/tuxedocomputers/tuxedo-keyboard/blob/mast...
https://bitbucket.org/tuxedocomputers/clevo-xsm-wmi/src/mast...
I assumed my laptop worked the same way and wasted a lot of time dumping my laptop's ACPI tables and trying to figure them out. I even installed some Windows tools to decompile the WMI buffers. Didn't find anything. I was about to give up when someone on IRC set me on the right path and I was able to make progress. Even though I saw my keyboard on lsusb output, I never thought to look for a USB protocol. Learned this one the hard way.
Before I started, I emailed Clevo and asked for technical documentation on the keyboard. Their marketing department replied: "Ubuntu was not supported". I emailed Tuxedo Computers (mentioned above) and they were much more helpful: their developers shared a fan control application they wrote with me! It was great but the keyboard drivers were missing.
So I decided to reverse engineer it.
While not as complex as the VGA-to-USB device, the process of reverse engineering the keyboard was similar:
1. Boot Windows 10 with the proprietary driver
2. Start Wireshark
3. Capture USB traffic
4. Use the manufacturer's keyboard control program
5. Correlate the data sent to the keyboard with what I did
6. Document the structure of the messages
For example, to set the color of a specific RGB LED on my keyboard, the following bytes must be sent to the device through a USB control transfer: 0xcc01kkrrggbb7f
01 = some kind of operation code
kk = target LED
rr = red
gg = green
bb = blue
cc, 7f always surround all bytes (part of USB protocol?)
I used hidapi-libusb to create a small program that sends those bytes to the keyboard:https://github.com/matheusmoreira/ite-829x/blob/master/ite-8...
This user space driver gave me access to most of my keyboard's functionality on Linux. I used to have to boot into Windows in order to configure the keyboard lights -- not anymore!
The keyboard also generates some custom key codes that are used by the proprietary Windows driver to implement some Fn hotkeys. I know this because the kernel logs these unknown key events. To implement this, I'll have to make a real kernel module that maps them into something user space can make use of.
To this end, I've been studying the Linux kernel's documentation:
https://www.kernel.org/doc/html/latest/driver-api/usb/
https://www.kernel.org/doc/html/latest/driver-api/usb/writin...
https://elixir.bootlin.com/linux/latest/source/include/linux...
The input_mapping, input_mapped, event and raw_event hooks seem especially relevant to my case: the custom driver just needs to process the custom key codes and let the generic Linux keyboard driver handle the rest. Might as well add sysfs entries for the LEDs but I don't know how to do that yet.
I expect to end up with something like the open razer driver:
https://github.com/openrazer/openrazer/blob/master/driver/ra...
I used this site to gain a better understanding of USB itself: