I fully agree with sundialsvcs, except to point out that ioctls are not the preferred interface. Kernel modules adding new ioctls will be less likely to be accepted upstream (and therefore into distributions); you'll have to be prepared to explain exactly why you think ioctls are the best interface for this.
Personally, I'd recommend using plain character devices. For example, you might have one device file for raw data, and another for control messages. If the control messages are plain text, you can then control your device from simple shell scripts. (Not to mention that your kernel code will be very simple, and fully contained in your module.)
The only issue is synchronizing state changes to your device driver. You may have one CPU core running in the kernel accessing the driver state for raw data transfer, while another code runs in the kernel modifying the driver state due to a control message; both at the exact same time. This should be easy to avoid by protecting the state using a lock.
As to the actual driver, see
Linux Device Drivers, Third Edition. If your device wants to export "registers" to user space, you can simply create a structure that mirrors the contents of these registers. (You should allocate it dynamically when your device is bound.)
To let userspace read the device similar to
/proc/meminfo , add a read method to the control device driver. It must construct the "file" contents as a string, based on the values in the internal structure.
To let userspace modify the device state, add a write method to the control device driver. It could parse text control settings (like
baudrate=38400), and modify the values in the state structure accordingly.
For good examples how these character-device based interfaces work, look at the kernel interfaces in
/sys/. They work pretty much like I just described above, except that /sys/ device nodes are usually limited to a single value (instead of full device state), so that they're easier to extend later on. From userspaces point of view, this interface is much easier to use than one that requires ioctls(), because you just treat the devices as normal files.
If you can describe your device a bit more detail, I think I could describe this method much better. I am almost certain this is easier to maintain in the long term (compared to a driver using ioctl()s), and I believe it would be much easier to get included upstream, should you desire that now or later on.