How to structure device driver software?
That very, very much depends on the kernel for which you are writing your driver. I'm (a bit) familiar with Linux. There are structures defined into which your drver has to hook. Those structures define most of the structure you are looking for, the driver itself just hooks into the kernel's structures on startup, gets its marching orders through a structure to be filled with function pointers for the relevant operations on the hardware. See Corbet, Rubini, Kroah-Harman "Linux Device Drivers" (3rd edition, get it here). It is somewhat dated, but the fundamentals haven't changed that much. The Linux Drivers Project gathers people trying to write drivers.

For a graphics card, the picture is quite different, I believe you'll find the above split between the kernel and X.org.

(The above general picture, with the kernel defining the overall architecture and the driver filling in the details of what object-oriented programming fans would call an "object" in an operating system defined device type "class" is the only reasonable way of structuring a non-toy, non-one-machine-only operating system. Most of the time written in C, not C++ or ($deity forbid) Java, but OO all the same.)