Block device driver registration and logoff
The 1th work in block device drivers is usually to register themselves to the kernel, and the function to complete this task is Register_blkdev (), whose prototype is:
int Register_blkdev (unsigned int major, const char *name);
The major parameter is the main device number to be used by the block device, name is the device name, and it is displayed in/proc/devices. If major is 0, the kernel automatically assigns a new main device number Register_blkdev () The return value of the function is the main device number. If 1 negative values are returned, an error has occurred.
The logoff function corresponding to Register_blkdev () is Unregister_blkdev (), and its prototype is:
int Unregister_blkdev (unsigned int major, const char *name);
Here, the arguments passed to Register_blkdev () must match the arguments passed to Register_blkdev (), otherwise the function returns-einval.
Request queue operations for block devices
The standard request handler can sort requests and merge adjacent requests, and if a block device wants to use a standard request handler, it must call the function Blk_init_queue to initialize the request queue. When processing requests on the queue, the queue spin lock must be held. Initializing the request queue
request_queue_t *blk_init_queue (Request_fn_proc *rfn, spinlock_t *lock);
The 1th parameter of the function is a pointer to the request handler function, and the 2nd parameter is a spin lock that controls access to the queue, and this function can have memory allocation behavior, so it may fail and function calls
Returns a pointer to the initialization request queue, otherwise, NULL is returned. This function is typically called in the block device-driven module load function. Clear the request queue
void Blk_cleanup_queue (request_queue_t * q);
This function completes the task of returning the request queue to the system, typically called in the Block Device driver module unload function.
Fetch request
struct Request *elv_next_request (request_queue_t *queue);
The above function returns the next request to be processed (determined by the I/O scheduler) and returns NULL if no request is made.
Removal request
void Blkdev_dequeue_request (struct request *req);
The above function removes 1 requests from the queue. If multiple requests are being manipulated from the same queue at the same time in the driver, it must be removed from the queue in such a way.
Assigning the request queue
request_queue_t *blk_alloc_queue (int gfp_mask);
For non-mechanical devices with completely random access, such as Flash, RAM disks, which do not require complex I/O scheduling, you should use the above function to allocate 1 "request Queues" and use the following functions to bind the request queue and manufacturing request functions.
void Blk_queue_make_request (request_queue_t * q,
MAKE_REQUEST_FN * MFN);
void Blk_queue_hardsect_size (request_queue_t *queue,
unsigned short max);
This function is used to tell the size of the hardware sector of the kernel block device, and all requests generated by the kernel are multiples of this size and are correctly bounded. However, the communication between the kernel block device layer and the driver is performed in 512-byte sectors.
Steps:
The following work is typically done in block device-driven module loading functions:
① allocates, initializes the request queue, binds the request queue, and requests the function.
② Assign, initialize Gendisk, give Gendisk major, FoPs, queue, etc.
Add the Gendisk to the last member assignment.
③ Register block device driver.
In block-device-driven module unloading functions, it is often necessary to work in the opposite direction of the module loading function:
① clears the request queue.
② Delete Gendisk and references to Gendisk.
③ Remove the reference to the block device and unregister the block device driver.
Summarize:
The I/O operation of block devices differs greatly from that of character devices, thus introducing
Request_queue, request, bio and a series of data structures. Throughout the I/O operation of the block device, the "request" is always used, and the I/O operation of the character device is directly detours.
I/O operations for block devices are queued and consolidated.
The driver's task is to process the request, and the queue and consolidation of the request is resolved by the I/O scheduling algorithm, so the core of the block device driver is the request handler function or the "Manufacturing request" function.
Although the block_device_operations struct and its member functions are still present in the block device driver, they no longer contain member functions that read and write, but only include open, release, I/O control, etc.
Functions unrelated to the specific read and write. Block device-driven architecture is quite complex, but fortunately, block devices are not all-encompassing as a character device, which is typically a storage device, and the driver's body has
Provided by the Linux kernel, for a particular hardware system, the job of the driver engineer is often to write only a small amount of code that interacts directly with the hardware.
1#include <linux/init.h>2#include <linux/module.h>3#include <linux/kernel.h>4#include <linux/fs.h>5#include <asm/uaccess.h>6#include <linux/spinlock.h>7#include <linux/sched.h>8#include <linux/types.h>9#include <linux/fcntl.h>Ten#include <linux/hdreg.h> One#include <linux/genhd.h> A#include <linux/blkdev.h> - - #defineMAXBUF 1024 the - - #defineBlk_major 253 - + Charblk_dev_name[]="Blk_dev"; - Static Charflash[1024x768* -]; + A at intMajor; -spinlock_tLock; - structGendisk *GD; - - - in /*block Device data transfer*/ - Static voidBlk_transfer (unsignedLongsector, unsignedLongNsect,Char*buffer,intwrite) to { + intRead =!write; - if(Read) the { *memcpy (Buffer, flash+sector* +, nsect* +); $ } Panax Notoginseng Else - { thememcpy (flash+sector* +, Buffer, nsect* +); + } A } the + /*block Device Request handler function*/ - Static voidBlk_request_func (structRequest_queue *q) $ { $ structRequest *req; - while((req = elv_next_request (q))! =NULL) - { the if(!blk_fs_request (req)) - { WuyiEnd_request (req,0); the Continue; - } Wu -Blk_transfer (Req->sector, Req->current_nr_sectors, req->buffer, Rq_data_dir (req)); About /*Rq_data_dir directions for data transfer from request*/ $ /*req->current_nr_sectors number of sectors to be completed in the current segment*/ - /*Req->sector The next sector that will be submitted*/ -End_request (req,1); - } A } + the /*strcut block_device_operations*/ - Static intBlk_ioctl (structBlock_device *dev, fmode_t No, unsigned cmd, unsignedLongArg) $ { the return-Enotty; the } the the Static intBlk_open (structBlock_device *Dev, fmode_t No) - { inPrintk"Blk Mount Succeed\n"); the return 0; the } About Static intBlk_release (structGendisk *GD, fmode_t No) the { thePrintk"Blk umount succeed\n"); the return 0; + } - structBlock_device_operations blk_ops= the { Bayi. Owner =This_module, the. Open =Blk_open, the. Release =Blk_release, -. IOCTL =Blk_ioctl, - }; the the //----------------------------------------------- the the Static int__init Block_module_init (void) - { the the the if(!register_blkdev (Blk_major, Blk_dev_name))//registering a piece of equipment94 { theMajor =Blk_major; thePrintk"regiser Blk Dev succeed\n"); the } 98 Else About { - return-Ebusy; 101 } 102GD = Alloc_disk (1);//assign a gendisk, the partition is a103Spin_lock_init (&Lock);//initialize a spin lock104Gd->major =Major; theGd->first_minor =0;//first secondary device number106Gd->fops = &blk_ops;//Associative operation functions107 108Gd->queue = Blk_init_queue (Blk_request_func, &Lock);//Initialize the request queue and associate to the Gendisk109 thesnprintf (Gd->disk_name, +,"blk%c",'a'); 111Blk_queue_hardsect_size (Gd->queue, +);//Set Sector size 512 bytes theSet_capacity (GD, +);//Set block device size 512*32=16k113 Add_disk (GD); thePrintk"gendisk Init success!\n"); the return 0; the } 117 Static void__exit Block_module_exit (void) 118 { 119Blk_cleanup_queue (gd->queue); - Del_gendisk (GD); 121 Unregister_blkdev (Blk_major, blk_dev_name); 122Printk"block module Exit succeed!\n"); 123 } 124 the Module_init (Block_module_init); 126 Module_exit (block_module_exit); 127 -Module_license ("GPL"); 129Module_author ("GEC");
Linux block device driver---program design (RPM)