Linux Driver Design

Source: Internet
Author: User
Linux Driver Design-general Linux technology-Linux programming and kernel information. The following is a detailed description. To learn more, write the devfs driver in linux:
By analyzing the driver source code, we can find that the driver can be divided into three parts:
Core data structure; Initialization, registration, elimination, and release of core data and resources; underlying device operation functions;

A. Core Data Structure
Struct file_operations fops Device Driver Interface
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 *);
Ssize_t (* sendpage) (struct file *, struct page *, int, size_t, loff_t *, int );
Unsigned long (* get_unmapped_area) (struct file *, unsigned long, unsigned long );
};


Block_device_operations block Device Driver Interface
{Int (* open) (struct inode *, struct file *);
Int (* release) (struct inode *, struct file *);
Int (* ioctl) (struct inode *, struct file *, unsigned, unsigned long );
Int (* check_media_change) (kdev_t );
Int (* revalidate) (kdev_t );
Struct module * owner;
}; READ () of the block device (). WRITE () is not registered here, but is registered in the read/WRITE request queue of the device. The kernel will call General blk_read (), blk_write () here (). read/write queue
Send read/write requests.

Linux uses these data structures to register the entry handles of open (), release (), ioctl (), check_media_change (), rvalidate (), and other functions with the kernel.
The open (), release (), ioctl (), check_media_change (), revalidate () and other functions to be compiled will be initialized during the driver,
Provides the function entry to the kernel through a variable of this structure type.

Struct request_queue_t data structure of the device Request queue
Struct request_list {
Unsigned int count;
Unsigned int pending [2];
Struct list_head free;
};
Struct request {
Struct list_head queue;
Int elevator_sequence;
Kdev_t rq_dev;
Int cmd;/* READ or WRITE */
Int errors;
Unsigned long start_time;
Unsigned long sector;
Unsigned long nr_sectors;
Unsigned long hard_sector, hard_nr_sectors;
Unsigned int nr_segments;
Unsigned int nr_hw_segments;
Unsigned long current_nr_sectors, hard_cur_sectors;
Void * special;
Char * buffer;
Struct completion * waiting;
Struct buffer_head * bh;
Struct buffer_head * bhtail;
Request_queue_t * q;
};

Struct request_queue
{
/*
* The queue request freelist, one for reads and one for writes
*/
Struct request_list rq;

/*
* The total number of requests on each queue
*/
Int nr_requests;

/*
* Batching threshold for sleep/wakeup decisions
*/
Int batch_requests;

/*
* The total number of 512 byte blocks on each queue
*/
Atomic_t nr_sectors;

/*
* Batching threshold for sleep/wakeup decisions
*/
Int batch_sectors;

/*
* The max number of 512 byte blocks on each queue
*/
Int max_queue_sectors;

/*
* Together with queue_head for cacheline sharing
*/
Struct list_head queue_head;
Elevator_t elevator;

Request_fn_proc * request_fn;
Merge_request_fn * back_merge_fn;
Merge_request_fn * front_merge_fn;
Merge_requests_fn * merge_requests_fn;
Make_request_fn * make_request_fn;
Plug_device_fn * plug_device_fn;
/*
* The queue owner gets to use this for whatever they like.
* Ll_rw_blk doesn't touch it.
*/
Void * queuedata;

/*
* This is used to remove the plug when tq_disk runs.
*/
Struct tq_struct plug_tq;

/*
* Boolean that indicates whether this queue is plugged or not.
*/
Int plugged: 1;

/*
* Boolean that indicates whether current_request is active or
* Not.
*/
Int head_active: 1;

/*
* Boolean that indicates you will use blk_started_sectors
* And blk_finished_sectors in addition to blk_started_io
* And blk_finished_io. It enables the throttling code
* Help keep the sectors in flight to a reasonable value
*/
Int can_throttle: 1;

Unsigned long bounce_pfn;

/*
* Is meant to protect the queue in the future instead
* Io_request_lock
*/
Spinlock_t queue_lock;

/*
* Tasks wait here for free read and write requests
*/
Wait_queue_head_t wait_for_requests;

Struct request * last_request;
};

The buffer zone is associated with the corresponding I/O operations on the buffer zone in this task queue, waiting for Kernel scheduling. This data structure is not required if it is a character device.
The read () and write () functions of Block devices are passed to request_fn () when the initize of buffer_queue and the device Request queue process requests ().
Struct request_queue_t {} variable type of the device Request queue. the driver must enter request_fn () during initialization ().

Other data structures include I/O port, Irq, DMA resource allocation, construction and definition of cmd that complies with POSIX standard ioctl, and description of the device's own
Definition of related data structures-for example, definition of the data structure of the control register of a device, Parameter definition in BIOS, and device type definition.

B. initialization, registration, and elimination. The module-based driver is loaded and uninstalled.

After defining the data structure, the device driver starts initialization:
For example, I/o port check and registration, the kernel provides two functions for I/O PORT check and registration: check_region (int io_port, int off_set)
And request_region (int io_port, int off_set, char * devname). I/O Port after registration, you can use inb () and outb () for operations.

Check and register the initialization of DMA and Irq,
Int request_irq (unsigned int irq, void (* handle) (int, void *, struct pt_regs *), unsigned int long flags,

Const char * device );

Irq: the request is interrupted.

Handle: the pointer to the interrupt processing function.

Flags: a fast interrupt to the SA_INTERRUPT request, with 0 normal interruptions.

Device: device name.

If the registration succeeds, 0 is returned. In this case, you can view the request interruption in the/proc/interrupts file.

DMA is mainly used to allocate swap memory space in the memory, as well as a buffer and initialize the device Request queue.

Check and initialize the device control registers, initialize the data structures related to the device, and enter some specific device data.

Then, start registration
Devfs_register () registers a unified device operation function with VFS.
Static struct file_operations XXX_fops = {
Owner: THIS_MODULE, the device module to which XXX_fops belongs
Read: XXX_read, read Device operations
Write: XXX_write, write Device operations
Ioctl: XXX_ioctl to control device operations
Mmap: XXX_mmap, memory re ing operation
Open: XXX_open. open the device.
Release: XXX_release
/*...*/
};


Blk_init_queue () queue initialization function.
Request_irq () interrupt registration function
Corresponding injection function:
Devfs_unregister (devfs_handle_t de ){};
Free_irq () releases interrupted, I/O resources, releases the buffer, releases devices, request queues, and VFS nodes.

Module-based driver loading and uninstallation.

Static int _ init _ init_module (void)
{
/*...*/
}

Static void _ exit _ cleanup_module (void)
{

}

/* Loading driver module entry */
Module_init (_ init_module );

/* Uninstall driver module entry */
Module_exit (_ cleanup_module );


_ Intrrupt ()
The processing program when the device is interrupted.
{
1. Handling shared interruptions;
2. Processing of spinlock and other transactions;
}

C. Compile the underlying device operation functions
Read (). write (), open (), release (), check_media_change (), revalidate (), and so on.


Open () and release ()

The device is opened by calling the function open () in the file_operations structure, which is used by the driver to complete initialization for future operations. In most drivers, open () usually needs to do the following:

1. Check for device errors, such as the device is not ready.
2. If it is enabled for the first time, the hardware device is initialized.
3. Identify the secondary device number. If necessary, update the current position pointer f_ops for read/write operations.
4. Allocate and fill in the data structure to be placed in file-> private_data.
5. Increase the count by 1.

Releasing a device is done by calling the function release () in the file_operations structure. This device method is also called close (), which works exactly opposite to open, generally, you need to do the following:

1. Use count minus 1.
2. Release the memory allocated in file-> private_data.
3. If 0 is used, disable the device.

Read () and write ()

The read/write operations on character devices are relatively simple. You can simply use the read () and write () functions. However, if it is a block device, you need to call the functions block_read () and block_write () to read and write data. These two functions will add read and write requests to the device request table, so that the Linux kernel can optimize the request sequence. Because the operation is performed on the memory buffer rather than the device directly, the read/write speed can be greatly accelerated. If there is no data to be read in the memory buffer, or you need to perform a write operation to write data to the device, you need to perform real data transmission by calling the request_fn () function in the data structure blk_dev_struct ().

Ioctl () -- explain cmd and send it to the control register of the device. In fact, read () and write () must also be completed through ioctl.
Ioctl (){
Case cmd {
SWITCH CASE1 :{...};
SWITCH CASE2 :{...};
Switch case n :{...};
.
.
DEFAULT :{...};
}
END CASE
Summary:
We can see that a linux driver usually contains the following:
Initialize the device module,
{I/O port, DMA. Irq, memory buffer, initialization and fill in the specific device data structure, register the specific function of fops, etc}
Interrupt Processing Module, device release module, and device uninstall Module
Device Open Module, data read/write and control module,
Driver loading module and driver release module.

Computer Center of Zhejiang urban and rural planning and design institute
Chen Gang 2004.07.21

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.