Device Driver Basics

Where
Device drivers live inside the operating system.  They are not indepedent programs.  They do not run all the time.


What

They are instead just a set of  functions that are part of a larger program, and when that larger program needs them, they are called.   If the functions crash, the whole program crashes.  If the functions loop forever, the OS locks up.  Sometimes it just locks the device, other times it locks the whole OS.


How do they get into the OS?

There are two ways.  They can either be compiled into the OS, which means they are already available, or they can be loaded as modules, which means they only use RAM when needed.
If they are modules, there is a small bit of extra code needed.


How Many

These functions can be called multiple times at the same time.  It should be possible to call the function twice at the same time and everything is OK.  You can do this by having each instance have it's own variable (use variables from the stack) or by using locking.


Can I print from a device driver?

There is a 'printk' function.  It's mostly like 'printf', and makes it easy to print.  However, the messages don't go to the screen.  They go to /var/log/messages if the system is set up normally.


Can I Write Device Drivers Over the Network?

Generally, not.  If you make an error, and need to reboot the computer, then you must be in the lab.  However, if you are mistake-free, it is theoretically possible.


What Language Do I Write In?

The Linux kernel is written in C, and all the header files are written in C.  It's therefore easiest to write in C.


What's this Top/Bottom Half thing?

Device drivers typically have a top and bottom half.  The top half gets data and commands from the kernel, and places them into a data structure shared with the bottom half.  The bottom half gets called when there is an interrupt, and places answers in the common data structure.  This common data structure is protected from simultainious access via locking.


How Do Device Drivers Get Called

An application makes a system call
The operating system decides it needs to use the device
The operating system calls the top half of the device driver
---OR---
An interrupt goes off
The operating system decides that the interrupt was associated with your device
It calls the bottom half of the device driver.
Note that every system call does NOT automatically translate into a device call.  Maybe the OS has the answer cached.  Maybe the call had an error that could be detected before the device driver.  Maybe something else.

What functions must I implement?

These
struct file_operations {
       struct module *owner;
       loff_t (*llseek) (struct file *, loff_t, int);
       ssize_t (*read) (struct file *, char *, size_t, loff_t *);
       ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
       int (*readdir) (struct file *, void *, filldir_t);
       unsigned int (*poll) (struct file *, struct poll_table_struct *);
       int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
       int (*mmap) (struct file *, struct vm_area_struct *);
       int (*open) (struct inode *, struct file *);
       int (*flush) (struct file *);
       int (*release) (struct inode *, struct file *);
       int (*fsync) (struct file *, struct dentry *, int datasync);
       int (*fasync) (int, struct file *, int);
       int (*lock) (struct file *, int, struct file_lock *);
       ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
      ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
};