Linux Device Drivers

Linux Device Drivers


Linux
Modules
Character drivers
IO & Memory
Linux Kernel
Process Management
Process Address space

Linux Scheduler
Memory Management
Interrupts
Signals
System Calls
Kernel Synchronization
Linux Inter Process Communications




Serial Ports
Parallel Ports
Introduction to Hardware
Linux Timers
DMA in Linux
Linux Threads
Linux Thread Synchronization

Linux Multi Threading
Debugging in Linux
GDB GNU Debugger
KDB Kernel Debugger
KGDB Kernel GNU Debugger
Example Ethernet Driver




Character Device Drivers

Character Device Drivers

 

DRIVER REGISTRATION:

 

int register_chrdev (unsigned int major, const char *name,

struct file_operations &fops);

int unregister_chrdev(unsigned int major, const char* name);

 

Important File : /proc/devices

 

Major & Minor Numbers:

 

     Char devices are accessed through names in the file system called special devices or device files or nodes.

     Conventionally located in /dev directory.

     Identified by 'c' in the first column of ls -l

     Two comma separated numbers in file size field denote major and minor.

     major number identifies the driver associated with the device.

     minor number is only used by the driver to differentiate several devices controlled / managed /driven by it.

 

mknod

 

mknod creates device nodes in file system tree.

 

     Syntax: mknod PATH/DEVICE TYPE MAJOR MINOR

     Major numbers can be allocated dynamically or statically.

 

File_operations_structure

 

     Capabilities of a device (supported by a driver) are made known by filling a "file-operations" struct and passing it to "register_chrdev"

     This is an array of function pointers.

     Kernel uses this "struct" to access driver's functions.

 

'struct file-operations' members are :

 

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 (*ioctl) ( struct inode*, struct file*, unsigned int, unsigned long);

-to handle device specific commands .

 

int (*open) (struct inode *, struct file *);

 

int (*release) (struct inode *, struct file *);

-after fork or dup, release will be invoked after all copies of fd are closed.

struct module *owner ;

 

-Use tagged structure initialization

eg:

struct file_operations my_fops = {

llseek: my_llseek,

read: my_read,

write: my_write,

ioctl: my_control,

open: my_open,

release: my_close,

owner: THIS_MODULE,

};

 

The File Structure

 

C Library FILE appears in user space programs.

Struct file is a kernel file structure that never appears in user space.

Every open file in the system has an associated "struct file" in kernel space, created by the kernel on "open" and is passed to any function or method that operates on the file.

 

Most important fields are:

mode_t f_mode;

loof_t f_pos;

unsigned int f_flags;

struct file_operations *f_op;

void *private_data;

struct dentry *f_dentry;

 

 

The inode structure

 

inode structure is used by the kernel to represent files. Two fields of this structure are:

dev_t i_rdev;

struct cdev *i_cdev; // represents char devices.

 

Two macros to obtain the major and minor number from an inode

unsigned int iminor(struct inode *inode);

unsigned int imajor(struct inode *inode);

 

HOW TO GET DEVICE NUMBER

The combined device number resides in the field i_rdev of the inode structure.

 

MAJOR(kdev_t dev); Extract the major number from a kdev_t structure.

MINOR(kdev_t dev); Extract the minor number

MKDEV(int ma, int mi); create a kdev_t type from major & minor number

 

 

Data exchange between Application & DRIVER

 

     Application runs in user space where as driver in kernel space.

     User-space addresses cannot be used directly in kernel space.

     when the kernel accesses a user space pointer , the associated page may not be present in memory (swapped out).

 

To deal with like conditions , following functions are provided:

 

unsigned long copy_from_user( void *to, const void *from, unsigned long count);

unsigned long copy_to_user( void *to, const void *from, unsigned long count);

#include <asm/uaccess.h>

 

access_ok

Address verification (without transferring data) is implemented by the function access_ok, which is declared in <asm/uaccess.h>

 

int access_ok(int type, const void *addr, unsigned long size);

 

type- VERIFY_READ or VERIFY_WRITE depending on the action to be performed.

addr- User address space

size- Byte count

 

access_ok returns a boolean value: 1 for success (access is OK) and 0 for failure (access is not OK). If it returns false, the driver should usually return EFAULT to the caller.

 

Data transfer functions

A set of functions that are optimized for the most used data sizes (one, two , four and eight bytes).

 

put_user(dataum, ptr);

__put_user(dataum, ptr);

 

These macros write the datum to user space, relatively fast, single values are being transferred.

 

get_user(local, ptr);

__get_user(local,ptr);

 

These macros are used to retrieve a single datum from user space.

 

Returns 0 on success and EFAULT on error

 

The arguments to read

 

 

Kernel Space (nonswappable)

User Space (swappable)

 

The Release Method

 

The release method should perform the following tasks:

 

     Deallocate anything that open allocated in filp->private_data

     Shut down the device on last close

     Decrement the usage count

 

The Read Method

 

     If the value equals the count argument passed to the read systemcall, the requested number of bytes has been transferred.

     If the value is positive, but smaller than count, only part of thedata has been transferred.

     If the value is 0 end of file is reached

     A negative value means there was error. These errors look like-EINTR (interrupted system call) or -EFAULT (bad address)

 

The Write Method

 

     If the value equals the count argument passed to the write system call, the requested number of bytes has been transferred.

     If the value is positive, but smaller than count, only part of the data has been transferred.

     If the value is 0, nothing was written.

     A negative value means there was error. These errors are defined in <linux/errno.h>.

 

Ioctl method

 

     Perform various types of hardware control via device driver (ioctl method)

     Device specific entry point for the driver to handle the commands

     Allows to access features unique to hardware:

configuring the device or Enter / Exit operating modes

     ioctl system call : ioctl (int fd, int cmd, char *argp)

 

Driver method :

int (*ioctl) (struct inode *inode, struct file *filep,

unsigned int cmd, unsigned long arg );

 

Choose the ioctl command a unique number

Check in include/asm/ioctl.h & Documentation/ioctl-number.txt