Home | Projects | Notes > Linux Device Drivers > Character Driver
A Linux character device is a special type of device file that allows sequential character-based input or output to be processed, such as terminals or serial ports.
A Linux character driver is a software component that enables communication and control of character-oriented devices by providing an interface for applications to read from and write to them character by character.
Character driver accesses data from the device sequentially (i.e., byte-by-byte like a stream of characters) not as a chunk.
Sophisticated buffering strategies are usually not involved in char drivers, because when you write 1 byte, it directly goes to the device without any intermediate buffering, delayed write-back or dirty buffer management.
Examples: Sensors, RTC, keyboard, serial port, parallel port, etc.
VFS file_operations
structure (Collection of various function pointers to the possible file operation methods for a regular file or a device file)
xxxxxxxxxx
421/* include/linux/fs.h */
2
3struct file_operations {
4 struct module *owner;
5 loff_t (*llseek) (struct file *, loff_t, int);
6 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
7 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
8 ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
9 ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
10 int (*iterate) (struct file *, struct dir_context *);
11 int (*iterate_shared) (struct file *, struct dir_context *);
12 unsigned int (*poll) (struct file *, struct poll_table_struct *);
13 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
14 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
15 int (*mmap) (struct file *, struct vm_area_struct *);
16 int (*open) (struct inode *, struct file *);
17 int (*flush) (struct file *, fl_owner_t id);
18 int (*release) (struct inode *, struct file *);
19 int (*fsync) (struct file *, loff_t, loff_t, int datasync);
20 int (*fasync) (int, struct file *, int);
21 int (*lock) (struct file *, int, struct file_lock *);
22 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
23 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
24 int (*check_flags)(int);
25 int (*setfl)(struct file *, unsigned long);
26 int (*flock) (struct file *, int, struct file_lock *);
27 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
28 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
29 int (*setlease)(struct file *, long, struct file_lock **, void **);
30 long (*fallocate)(struct file *file, int mode, loff_t offset,
31 loff_t len);
32 void (*show_fdinfo)(struct seq_file *m, struct file *f);
33
34 unsigned (*mmap_capabilities)(struct file *);
35
36 ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
37 loff_t, size_t, unsigned int);
38 int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
39 u64);
40 ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
41 u64);
42} __randomize_layout;
Create device file using udev
(init_special_inode()
gets called)
xxxxxxxxxx
201/* fs/inode.c */
2
3void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
4{
5 inode->i_mode = mode;
6 if (S_ISCHR(mode)) {
7 inode->i_fop = &def_chr_fops; /* dummy file operation; fs/char_dev.c */
8 inode->i_rdev = rdev; /* initialize i_rdev with newly created device's device # */
9 } else if (S_ISBLK(mode)) {
10 inode->i_fop = &def_blk_fops;
11 inode->i_rdev = rdev;
12 } else if (S_ISFIFO(mode))
13 inode->i_fop = &pipefifo_fops;
14 else if (S_ISSOCK(mode))
15 ; /* leave it no_open_fops */
16 else
17 printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
18 " inode %s:%lu\n", mode, inode->i_sb->s_id,
19 inode->i_ino);
20}
rdev
- Device number
mode
- Device type (e.g., char device, block device, etc.)
inode
object gets created in memory and inode->i_rdev
field is initialized with the device number
inode->i_fop
field is set to dummy default file operations (i.e., def_chr_fops
)
xxxxxxxxxx
111/* fs/char_dev.c */
2
3/*
4 * Dummy default file-operations: the only thing this does
5 * is contain the open that then fills in the correct operations
6 * depending on the special file...
7 */
8const struct file_operations def_chr_fops = {
9 .open = chrdev_open,
10 .llseek = noop_llseek,
11};
open()
System CallUser invokes open()
system call on the device file
file
object gets created (VFS opens a file by creating a new file object and linking it to the corresponding inode object.)
inode
's i_fop
gets copied to file object's f_op
(dummy default file operations of char device file def_chr_fops
)
Open function of dummy default file operations gets called (chrdev_open
)
inode->i_cdev
field is initialized to cdev
that you added during cdev_add
(lookup happens using inode->i_rdev
field)
inode->cdev->fops
(this is a actual file operations of the driver) gets copied to file->f_op
file->f_op->open
method gets called (actual open
method of the driver)
open()
System Call Behind the Scenes
inode
Object & file
Objectinode
Object
Unix makes a clear distinction between the contents of a file and the information about a file.
An inode
is a VFS data structure (struct inode
) that holds general information about a file.
Whereas VFS file
data structure (struct file
) tracks interaction on a file opened by the user process.
An inode
contains all the information needed by the filesystem to handle a file.
Each file has its own inode
object, which the filesystem uses to identify the file.
Each inode
object is associated with an inode
number, which uniquely identifies the file within the file system.
The inode
object is created and stored in memory when a new file (regular or device) gets created.
file
Object
Whenever a file is opened, a file object is created in the kernel space. There will be one file
object for every open regular/device file.
A file
object stores information about the interaction between an open file and a process.
This information exists ONLY in kernel memory while the file is open.
The contents of a file
object is NOT written back to disk unlike the case of an inode
.