The software described in this documentation is either in Extended Support or Sustaining Support. See https://www.oracle.com/us/support/library/enterprise-linux-support-policies-069172.pdf for more information.
Oracle recommends that you upgrade the software described by this documentation as soon as possible.
Character device drivers support devices that handle variable rather than fixed amounts of data, and which do not access physically addressable storage media or support file system access. Keyboards, mice, and video cards are examples of devices that might use character devices, although USB keyboards and mice require the use of USB device drivers.
The implementation of most character device drivers is very similar on both Linux and UNIX operating systems, with most differences arising from the structures that are used to define a driver's file operations.
The file_operations
structure for a character
device, defined in <linux/fs.h>
, contains a
set of method pointers that specify how the system interacts with
the device via the device files under /dev
when
using system calls such as open()
,
read()
, write()
, and
ioctl()
.
struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); };
A simple character device driver might only need to implement a subset of the functions defined for this structure, for example:
struct file_operationsdriver_fileops
= { .owner = THIS_MODULE, .llseek =driver_llseek
, .read =driver_read
, .write =driver_write
, .ioctl =driver_ioctl
, .open =driver_open
, .release =driver_release
, };
As well as the methods, it is usual to define
module_init()
initialization and
module_exit()
cleanup routines for the driver
that are called when a driver is loaded and unloaded. These
routines should call register_chrdev()
and
unregister_chrdev()
to register and unregister
the device major number for the driver.
Most character device drivers declare an interrupt handler to
accept incoming data asynchronously from the device. When
initializing the driver, use request_irq()
to
install the interrupt handler, remembering to specify shared
interrupts by setting the SA_SHIRQ
bit in the
flags
argument as well as a unique
dev_id
argument that the handler can
use to identify interrupts that it should process. Cleanup should
call free_irq()
to unregister the handler.
Alternatively, a driver can use polling to check for incoming
data, although this is uncommon.
The file
structure for a character device,
defined in <linux/fs.h>
, specifies the
kernel-space data structure that the kernel creates when the
device is opened.
The most important members of the file
structure are:
-
f_flags
File control flags that indicate how device operations should behave, for example, non-blocking reads.
-
f_mode
The mode, which indicates whether the file is readable and writable.
-
f_op
The operation associated with a file, usually depending on the minor device number.
-
f_pos
The current offset in the file for reading or writing.
-
private_data
Allows data about the device to be retained between system calls until the device is released.
To obtain the major and minor numbers from a device's inode, use
the following macros that are also defined in
<linux/fs.h>
:
unsigned iminor(struct inode *inode); unsigned imajor( struct inode *inode);