In classic Unix, the difference between character devices and block devices is that block devices support seek, which implies that they are addressable, in units of fixed sized disk blocks. Character devices do not support seek, they just deliver or accept a stream of characters.
In linux, a device driver is implemented as a struct, containing some flags and parameters plus a collection of function pointers, implementing the methods for read()/write()/etc. Block (disk) drivers will also implement seek(), and maybe even mmap().
Normally, device drivers do not interfere with the actual content being transferred, they only move bytes or blocks to/from the device, using the (hardware) protocol that the device needs (such as manipulating the internal control registers, inspecting status registers, ...)