Hardware Linux

Working on LDD3’s tiny tty example

A while back I started tipping my toes into Linux Kernel module development. Mainly, to understand a driver for a data capture card I got to work with (or for, I believe).

Well, there is a go-to reference: the book Linux Device Drivers, 3rd Edition by Corbet, Rubini and Kroah-Hartman (from now on LDD3).

It’s great, it explains a lot and contains lots of hands-on example code, too. But, unfortunately it refers to the 2.6 Linux kernel. We’re at 6.8 at the time of writing this. So it’s a bit outdated.

No worries though, FOSS is a beautiful beast, and people have taken the example modules and updated them. Around version 5.15 that is. And things have changed again – at least for tty it seems.

There is a pull request to make it 6.x compatible, but … it’s almost a year old by now, and it seems incomplete. Yet, it was a really great thing to come across at the start of this journey, because it restored my sanity.

So, here’s my go at the tiny tty example driver and I hope I can finish it up into something that works with a 6.x Linux kernel.

Things have changed

Using static major/minor numbers is discouraged, or at least, made easier to avoid in more recent kernel versions (feels like since 4.x or so). So, some functions used in LDD3’s examples simply don’t exist anymore.

alloc_tty_driver is now superseeded by tty_alloc_driver (okay, that re-naming is kind of evil). And while the former only bothered about the number of supported ports, the latter wants flags, too. So, it looks like the returned struct of type tty_driver already contains a lot of entries when tty_alloc_driver is done with it.

I’ve refrained from using the TTY_DRIVER_NO_DEVFS flag, because I think dynamic stuff is always nice, so TTY_DRIVER_DYNAMIC_DEV it is.

tty_driver->owner is not supposed to be set anymore, according to this old’ish LKLM post. Same goes for ->major (see tty_alloc_driver).

The module is not put down anymore by put_tty_driver but by tty_driver_kref_put which seemingly also handles references in proc (I’ve run into issues that the proc entry was not removed after rmmoding the module and hence, on the next try insmod was complaining).

I mention this, because LDD3’s static void __exit tiny_exit(void) spends two thirds of its code to close ports and kfree associated memory. This code is still present in the pull request with the updated example from 2023.

Still, I have to investigate if tty_driver_kref_put also removes timers.

Things have gotten easier

Compared to the example for a 2.6 kernel in LDD3, the current version (at least for module __init and __exit) is way easier and frankly cleaner, i.e. easier to read.

Still, or maybe exactly because of that, I think it’s time for a fourth edition of Linux Device Drivers.

I try to go through with the rest of the module and understand and ideally fix it. Then I’ll upload it too, for later generations at kernel 8.x to despair of it. Link soon.