The only book on the subject is the LDDD3 (Linux device driver developemeny third edition), it gives you the broad idea of how things work however it is hopelessly out of date in many areas DMA buffers in particular so take it with a cargo hold of salt
I have tried to go the “proper” way by doing the driver and all, but it is just a waste of time as you have to either freeze your kernel to a hopelessly outdated version, mainline your driver (which let’s face it will never happen) or keep tracking changes for the entire life of the project, as internal kernel API/ABI is not stable and subjected to routine unannounced breaking changes (see what happened to ZFS), my suggestion is unless you really need to access shared kernel resources (scheduling for example) jus use a UIO driver, and manage everything with a C/Cpp daemon running in the background