I also recommend "Linux Device Drivers" from O'Reilly. http://lwn.net/Kernel/LDD3/
I also recommend "Linux Device Drivers" from O'Reilly. http://lwn.net/Kernel/LDD3/
That book is a little out of date nowdays.
They're working on LDD4: http://www.amazon.com/Linux-Device-Drivers-Jessica-McKellar/...
but oddly, it's based on kernel version 3.2, which by the time the book will be released is also going to be out of date.
Another trick I've used is making as much of my core logic as possible happen in functions that are called from the kernel hooks, rather than in the kernel hooks. Then you can test a ton of it in userland to handle basic logic and flow control bugs, finally porting the code to the module. To help with this, it sometimes is actually faster to copy some of the kernel routines you use to a different .c file and change things like kprintf and kmalloc for the userland versions. It isn't going to be a perfect port, but it helps get some of the complex stuff out of the way where you have your familiar userland tools.
All that said - I've only dabbled in the kernel a little, there are probably better ways that someone can chime in on.
It's just like the article said--just a big, annoying to debug C program. If you understand pointers, you can learn how to program the Linux kernel. Programming in the Linux kernel has been a really fun learning experience for me. It's nice, if intimidating, how you can just do everything--there are no hard abstraction boundaries, you can read all the source and call into any part of the kernel without going through hoops.
I've developed the Linux kernel with two machines, a development machine and a headless machine that I'm ssh'ing into (actually, a bunch of those--makes testing go faster). VMs aren't really an option for device drivers, but if you run your code on your development machine, you waste a lot of time.
Save and sync often, and have only the bare-minimum of processes running.