+1, i like the Linux Device Drivers book _much_ better than the Linux Kernel Module Programming Guide, which is currently recommended in the top comment of this thread.
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.)
Something a little more recent but still dated unfortunately. https://lwn.net/Kernel/LDD3/ I guess there is not much of an audience for books these days.
It's been about 10 years since I've done any Linux kernel development, but often you can get the rest from the documentation folder in the kernel tree, plus the source code of a similar module also in tree.
This feels a bit too simplistic to actually be helpful to someone. If you want to learn Golang for example (from 0 previous experience), don't jump into reading Docker or Kubernetes, start with the guide on the website that explains how it works, look over the reference manual, write some smaller examples to solve some of your own minor pet peeves then once you have a little knowledge about the language, start looking for popular and big codebases, maybe implement some part of them yourself.
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 userspace USB drivers, you want to look at libusb. I don't know of a straightforward tutorial, but the API matches up really closely to the operations you'd expect to be able to do against a USB peripheral.
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.
It's tough though, because any book you'd read will not be up-to-date, things are constantly changing/improving inside the kernel, etc. For some things you'll just not find any documentation whatsoever.
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.
> If you want to learn Golang for example (from 0 previous experience), don't jump into reading Docker or Kubernetes...
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.
Thats true enough too, of course. But too often people want to be spoon-fed, and so you want to point them at decent resources which they can self-study, and then be on hand to answer specific questions.
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.
I recently wrote a user space driver for my Clevo laptop's backlit keyboard. I'm currently trying to convert it into a Linux kernel driver. I'll describe my approach.
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:
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:
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:
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: