One of the books about Linux kernel development that I like the most is Linux Device Drivers 3. In my opinion the best thing about the book is that all the example drivers covered in the book are implemented as memory devices. So one doesn’t need special hardware in order to use the example drivers.
With this approach one can understand the ABIs, interfaces and helpers that the kernel offers to driver authors while having drivers for (pseudo) devices to play with.
A different approach is used in the book Essential Linux Device Drivers where the authors explain how drivers for real devices works. I think both approaches and books are complementary.
The problem is that LDD3 book is now a few years old and most of the example drivers do not compile in recent kernels. Also, many new changes were introduced in the kernel since 2.6.10. So examples for many ABIs are not covered in the book, like netlink sockets, threaded interrupt handlers, debugfs, etc.
I started a project to keep the LDD3 examples up-to-date with recent kernels and have plans to include more examples that cover more recent kernel features like the listed before.
The project can be found here.