转载:谢谢原作者:块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)
1.6介紹一種內核與用戶空間通信的方法-misc設備ioctl機制
塊設備驅動開發中往往需要配合用戶態的管理程序工具,管理我們的塊設備,此時我們需要涉及用戶空間程序與塊設備通信的方法,ioctl機制就是接下來需要學習和實戰的,通過ioctl機制,用戶態負責發送各種命令給內核驅動;內核態接收用戶態發送的命令,并根據命令執行相應的動作,如下圖所示。
?
ioctl提供用戶態程序使用內核態函數的通道,此時需要注冊一個字符設備來實現,我們使用misc這個字符設備來實現。
?
Ioctl.h
? 1 #ifndef _IOCTL_H
? 2 #define _IOCTL_H
? 3
? 4 /* misc device name*/
? 5 #define MISC_NAME "ioctl_test"
? 6
? 7 /**
? 8? *define ioctl codes for interfacing between kernel_module and user program
? 9? */
?10 #define IOCTL_CODE????? 0xcc?/* major type code - adjusted for target system */
?11
?12 #define TEST_CMD??????? _IOWR (IOCTL_CODE,? 0x09, unsigned long)
?13
?14 #endif
user.c
?
? 1 #include <sys/ioctl.h>
? 2 #include <unistd.h>
? 3 #include <fcntl.h>
? 4 #include <stdio.h>
? 5 #include "ioctl.h"
? 6
? 7 int main(void)
? 8 {
? 9????????unsigned long arg = 2013;
?10????????int fd;
?11
?12????????fd = open("/dev/"MISC_NAME, O_RDWR, 0);
?13????????if (fd < 0) {
?14???????????????? printf("Failed to open/dev/%s\n", MISC_NAME);
?15???????????????? goto out;
?16????????}
?17
?18????????if (ioctl(fd, TEST_CMD, &arg) < 0) {
?19???????????????? printf("Failed to executeioctl!\n");
?20????????}
?21
?22????????close(fd);
?23 out:
?24????????return 0;
?25 }
kernel.c
? 1 /*
? 2? * IOCTL
? 3? *Author: talk@studio
? 4? */
? 5
? 6 #include <linux/fs.h>
? 7 #include <linux/uaccess.h>
? 8 #include <linux/module.h>
? 9 #include <linux/miscdevice.h>
?10
?11 #include "ioctl.h"
?12
?13 static int ioctl(struct inode *inode,struct file *file,
?14????????????????????? unsigned int cmd,unsigned long user)
?15 {
?16????????unsigned long arg;
?17????????int ret = 0;
?18
?19????????if (_IOC_TYPE(cmd) != IOCTL_CODE) {
?20???????????????? printk("Unknown ioctlcommand 0x%x\n", cmd);
?21???? ????????????ret = -ENOTTY;
?22???????????????? goto out;
?23????????}
?24
?25????????switch (cmd) {
?26???????????????? case TEST_CMD:
?27???????????????????????? ret =copy_from_user(&arg, (unsigned long *)user, sizeof(unsigned lon??? g));
?28????????????????????????if (ret) {
?29????????????????????????????????printk("copy from user failed!\n");
?30???????????????????????? } else {
?31????????????????????????????????printk("received IOctl[arg=%lu] from user!\n", arg);
?32???????????????????????? }
?33???????????????????????? break;
?34???????????????? default:
?35???????????????????????? printk("Unknownioctl command[0x%x].\n", cmd);
36???????????????????????? ret = -ENOTTY;
?37???????????????????????? break;
?38????????}
?39 out:
?40????????return ret;
?41 }
?42
?43 static struct file_operations_misc_ctl_fops = {
?44????????.ioctl = ioctl,
?45????????.owner = THIS_MODULE,
?46 };
?47
?48 static struct miscdevice _misc_dev = {
?49????????.minor = MISC_DYNAMIC_MINOR,
?50????????.name = MISC_NAME,
?51????????.fops = &_misc_ctl_fops
?52 };
?53
?54 static int __init ioctl_init(void)
?55 {
?56????????int ret;
?57
?58????????ret = misc_register(&_misc_dev);
?59????????if (ret) {
?60???????????????? printk("Register ioctldevice[%s] failed\n", _misc_dev.name);
?61????????}
?62????????return ret;
?63 }
?64
?65 static void __exit ioctl_exit(void)
?66 {
?67????????if (misc_deregister(&_misc_dev) < 0) {
?68???????????????? printk("Deregister ioctlcontrol device[%s] failed\n",?_misc_dev.name);
?69????????}
?70????????return;
71 }
?72
?73 module_init(ioctl_init);
?74 module_exit(ioctl_exit);
?75 MODULE_LICENSE("GPL");
1.7逐漸成型 - 構件完善的管理工具及內核塊設備驅動模塊
經過上面四節的實戰和學習,我們把代碼完善一下,實現一個完整的用戶態管理功能和內核塊設備驅動的代碼設計,我們需要完成如下功能,下圖展示了我們程序各個模塊的關系。
?
?
我們看一下代碼如何實現,首先看公用頭文件定義
fbd_ioctl.h
?
? 1 /*
? 2? *Author: talk@studio
? 3? */
? 4
? 5 #ifndef _IOCTL_H
? 6 #define _IOCTL_H
? 7
? 8 /* misc device name*/
? 9 #define MISC_NAME "fbd_misc_dev"
?10
?11 /* param structure for device create */
?12 struct create_param {
?13????????char fbd_dev_name[32];
?14????????char lower_dev_path[64];
?15 };
?16
?17 struct delete_param {
?18????????char fbd_dev_name[32];
?19 };
?20
?21 /**
?22? *define ioctl codes for interfacing between kernel_module and user program
?23? */
?24 #define IOCTL_CODE????? 0xcc?/* major type code - adjusted for target system */
?25
?26 #define CREATE_CMD????? _IOWR (IOCTL_CODE,? 0x0A, struct create_param)
?27 #define DELETE_CMD????? _IOWR (IOCTL_CODE,? 0x0B, struct delete_param)
?28
?29 #endif
?
?
?
用戶態代碼
?
? 1 /*
? 2? *Author: talk@studio
? 3? */
? 4
? 5 #include <sys/ioctl.h>
? 6 #include <unistd.h>
? 7 #include <fcntl.h>
? 8 #include <stdio.h>
? 9
?10 #include"../common/include/fbd_ioctl.h"
?11
?12 int main(void)
?13 {
?14????????int fd;
?15????????struct create_param ctr_param = {
?16???????????????? .fbd_dev_name ="fbd_dev1",
?17???????????????? .lower_dev_path = "/dev/sdb",
?18????????};
?19
?20????????fd = open("/dev/"MISC_NAME, O_RDWR, 0);
?21????????if (fd < 0) {
?22???????????????? printf("Failed to open/dev/%s\n", MISC_NAME);
?23???????????????? goto out;
?24????????}
?25
?26????????if (ioctl(fd, CREATE_CMD, &ctr_param) < 0) {
?27???????????????? printf("Failed to executeioctl!\n");
?28????????}
?29
?30????????close(fd);
?31 out:
?32????????return 0;
?33 }
?34
? 1 /*
? 2? *Author: talk@studio
? 3? */
? 4
? 5 #include <sys/ioctl.h>
? 6 #include <unistd.h>
? 7 #include <fcntl.h>
? 8 #include <stdio.h>
? 9
?10 #include"../common/include/fbd_ioctl.h"
?11
?12 int main(void)
?13 {
?14????????int fd;
?15????????struct delete_param del_param = {
?16???????????????? .fbd_dev_name ="fbd_dev1",
?17????????};
?18
?19????????fd = open("/dev/"MISC_NAME, O_RDWR, 0);
?20????????if (fd < 0) {
?21???????????????? printf("Failed to open/dev/%s\n", MISC_NAME);
?22???????????????? goto out;
?23????????}
?24
?25????????if (ioctl(fd, DELETE_CMD, &del_param) < 0) {
?26???????????????? printf("Failed to executeioctl!\n");
?27????????}
?28
?29????????close(fd);
?30 out:
?31????????return 0;
?32 }
?33
?
?
內核驅動代碼
?
? 1 #ifndef?_FBD_DRIVER_H
? 2 #define?_FBD_DRIVER_H
? 3 #include <linux/init.h>
? 4 #include <linux/module.h>
? 5 #include <linux/blkdev.h>
? 6 #include <linux/bio.h>
? 7 #include <linux/genhd.h>
? 8 #include <linux/fs.h>
? 9 #include <linux/uaccess.h>
?10 #include <linux/miscdevice.h>
?11
?12 #define SECTOR_BITS???????????? (9)
?13 #define DEV_NAME_LEN??????????? 32
?14
?15 #define DRIVER_NAME???????????? "filter driver"
?16
?17 struct fbd_dev {
?18????????char fbd_dev_name[DEV_NAME_LEN];
?19????????struct request_queue *queue;
?20????????struct gendisk *disk;
?21????????sector_t size;????????? /* devicesize in Bytes */
?22
?23????????char lower_dev_name[DEV_NAME_LEN];
?24????????struct block_device *lower_bdev;
?25 };
?26
?27 struct bio_context {
?28????????void *old_private;
?29????????void *old_callback;
?30 };
?31 #endif
?
? 1 /**
? 2?*? fbd-driver - filter blockdevice driver
? 3?*? Author: Talk@studio
? 4 **/
? 5 #include "fbd_driver.h"
? 6 #include "../common/include/fbd_ioctl.h"
? 7
? 8 static int fbd_driver_major = 0;
? 9
?10 static struct fbd_dev fbd_dev =
?11 {
?12????????.fbd_dev_name = "\0",
?13????????.queue = NULL,
?14????????.disk = NULL,
?15????????.lower_dev_name = "\0",
?16????????.lower_bdev = NULL,
?17??? ?????.size = 0
?18 };
?19
?20 static int fbddev_open(struct inode *inode,struct file *file);
?21 static int fbddev_close(struct inode*inode, struct file *file);
?22
?23 static struct block_device_operationsdisk_fops = {
?24????????.open = fbddev_open,
?25????????.release = fbddev_close,
?26????????.owner = THIS_MODULE,
?27 };
?28
?29 static int fbddev_open(struct inode *inode,struct file *file)
?30 {
?31????????printk("device is opened by:[%s]\n", current->comm);
?32????????return 0;
?33 }
?34
?35 static int fbddev_close(struct inode*inode, struct file *file)
?36 {
37???????? printk("device is closedby:[%s]\n", current->comm);
?38????????return 0;
?39 }
?40
?41 static int fbd_io_callback(struct bio *bio,unsigned int bytes_done, int error)
?42 {
?43????????struct bio_context *ctx = bio->bi_private;
?44
?45????????bio->bi_private = ctx->old_private;
?46????????bio->bi_end_io = ctx->old_callback;
?47????????kfree(ctx);
?48
?49????????printk("returned [%s] io request, end on sector %llu!\n",
?50???????????????? bio_data_dir(bio) == READ ?"read" : "write",
?51???????????????? bio->bi_sector);
?52
?53????????if (bio->bi_end_io) {
?54???????????????? bio->bi_end_io(bio,bytes_done, error);
?55????????}
?56
?57????????return 0;
?58 }
?59
?60 static int make_request(structrequest_queue *q, struct bio *bio)
?61 {
?62????????struct fbd_dev *dev = (struct fbd_dev *)q->queuedata;
?63????????struct bio_context *ctx;
?64
?65????????printk("device [%s] recevied [%s] io request, "
?66????????????????"access on devsector [%llu], length is [%u] sectors.\n",
?67???????????????? dev->disk->disk_name,
?68???????????????? bio_data_dir(bio) == READ ?"read" : "write",
?69???????????????? bio->bi_sector,
?70???????????????? bio_sectors(bio));
?71
?72????????ctx = kmalloc(sizeof(struct bio_context), GFP_KERNEL);
73???????? if (!ctx) {
?74???????????????? printk("alloc memory forbio_context failed!\n");
?75???????????????? bio_endio(bio,bio->bi_size, -ENOMEM);
?76???????????????? goto out;
?77??? ?????}
?78????????memset(ctx, 0, sizeof(struct bio_context));
?79
?80????????ctx->old_private = bio->bi_private;
?81????????ctx->old_callback = bio->bi_end_io;
?82????????bio->bi_private = ctx;
?83????????bio->bi_end_io = fbd_io_callback;
?84
?85?? ??????bio->bi_bdev = dev->lower_bdev;
?86????????submit_bio(bio_rw(bio), bio);
?87 out:
?88????????return 0;
?89 }
?90
?91 static int dev_create(char *fbd_dev_name,char *lower_dev_path)
?92 {
?93????????int ret = 0;
?94????????struct fbd_dev *dev = &fbd_dev;
?95
?96????????if(fbd_dev.disk){
?97???????????????? printk("device[%s] isalready exist, delete it first!\n", fbd_dev.fbd_dev_nam??? e);
?98???????????????? ret = -EEXIST;
?99???????????????? return ret;
100???????? }
101
102???????? dev->disk = alloc_disk(1);
103???????? if (!dev->disk) {
104???????????????? printk("alloc diskerror");
105???????????????? ret = -ENOMEM;
106???????????????? goto err_out1;
107???????? }
108
109???????? dev->queue =blk_alloc_queue(GFP_KERNEL);
110???????? if (!dev->queue) {
111???????????????? printk("alloc queueerror");
112???????????????? ret = -ENOMEM;
113???????????????? goto err_out2;
114???????? }
115
116???????? /* init queue */
117???????? blk_queue_make_request(dev->queue,make_request);
118???????? dev->queue->queuedata = dev;
119
120???????? /* init gendisk */
121???????? strncpy(dev->disk->disk_name,fbd_dev_name, DEV_NAME_LEN);
122???????? dev->disk->major =fbd_driver_major;
123???????? dev->disk->first_minor = 0;
124???????? dev->disk->fops = &disk_fops;
125
126???????? dev->lower_bdev =open_bdev_excl(lower_dev_path, FMODE_WRITE | FMODE_READ, dev->lower??? _bdev);
127???????? if (IS_ERR(dev->lower_bdev)) {
128???????????????? printk("Open thedevice[%s]'s lower dev [%s] failed!\n", fbd_dev_name, lower_??? dev_path);
129???????????????? ret = -ENOENT;
130???????????????? goto err_out3;
131???????? }
132
133???????? dev->size =get_capacity(dev->lower_bdev->bd_disk) << SECTOR_BITS;
134
135???????? set_capacity(dev->disk,(dev->size >> SECTOR_BITS));
136
137???????? /* bind queue to disk */
138???????? dev->disk->queue =dev->queue;
139
140???????? /* add disk to kernel */
141???????? add_disk(dev->disk);
142
143???????? strncpy(dev->fbd_dev_name,fbd_dev_name, DEV_NAME_LEN);
144???????? strncpy(dev->lower_dev_name,lower_dev_path, DEV_NAME_LEN);
145???????? return 0;
146err_out3:
147???????? blk_cleanup_queue(dev->queue);
148err_out2:
149???????? put_disk(dev->disk);
150err_out1:
151???????? memset(&fbd_dev, 0, sizeof(structfbd_dev));
152? ???????return ret;
153 }
154
155 staticint dev_delete(char *fbd_dev_name)
156 {
157???????? int ret = 0;
158???????? struct fbd_dev *dev = &fbd_dev;
159
160???????? if (strcmp(fbd_dev_name,dev->fbd_dev_name) == 0) {
161???????????????? printk("delete the device[%s]!\n", fbd_dev_name);
162????????????????close_bdev_excl(dev->lower_bdev);
163???????????????? del_gendisk(dev->disk);
164???????????????? put_disk(dev->disk);
165????????????????blk_cleanup_queue(dev->queue);
166???????????????? memset(&fbd_dev, 0,sizeof(struct fbd_dev));
167???????? } else {
168???????????????? printk("device[%s] isn'texist!\n", fbd_dev_name);
169???????????????? ret = -EEXIST;
170???????? }
171???????? return ret;
172 }
173
174 staticint ioctl(struct inode *inode, struct file *file,
175????????????????????? unsigned int cmd,unsigned long user)
176 {
177???????? struct delete_param del_param;
178???????? struct create_param ctr_param;
179???????? int ret = 0;
180
181???????? if (_IOC_TYPE(cmd) != IOCTL_CODE) {
182???? ????????????printk("Unknown ioctl command0x%x\n", cmd);
183???????????????? ret = -ENOTTY;
184???????????????? goto out;
185???????? }
186
187???????? switch (cmd) {
188???????????????? case CREATE_CMD:
189???????????????????????? ret =copy_from_user(&ctr_param, (void *)user, sizeof(struct create_p??? aram));
190???????????????????????? if (ret) {
191????????????????????????????????printk("copy from user failed!\n");
192???????????????????????? } else {
193???????????????????????????????? ret = dev_create(ctr_param.fbd_dev_name,ctr_param.lower_dev_??? path);
194???????????????????????? }
195???????????????????????? break;
196???????????????? case DELETE_CMD:
197???????????????????????? ret =copy_from_user(&del_param, (void *)user, sizeof(struct delete_p??? aram));
198???????????????????????? if (ret) {
199????????????????????????????????printk("copy from user failed!\n");
200???????????????????????? } else {
201???????????????????????????????? ret =dev_delete(del_param.fbd_dev_name);
202????????????? ???????????}
203???????????????????????? break;
204???????????????? default:
205???????????????????????? printk("Unknownioctl command[0x%x].\n", cmd);
206???????????????????????? ret = -ENOTTY;
207???????????????????????? break;
208???????? }
209 out:
210???????? return ret;
211 }
212
213 staticstruct file_operations _misc_ctl_fops = {
214???????? .ioctl = ioctl,
215???????? .owner = THIS_MODULE,
216 };
217
218 staticstruct miscdevice _misc_dev = {
219???????? .minor = MISC_DYNAMIC_MINOR,
220???????? .name = MISC_NAME,
221???????? .fops = &_misc_ctl_fops
222 };
223
224 staticint __init fbd_driver_init(void)
225 {
226???????? int ret;
227
228???????? /* register fbd driver, get the drivermajor number*/
229???????? fbd_driver_major = register_blkdev(fbd_driver_major,DRIVER_NAME);
230???????? if (fbd_driver_major < 0) {
231???????????????? printk("get majorfail");
232???????????????? ret = -EIO;
233???????????????? goto err_out1;
234???????? }
235
236???????? ret = misc_register(&_misc_dev);
237???? ????if (ret) {
238???????????????? printk("Register ioctldevice[%s] failed\n", _misc_dev.name);
239???????????????? goto err_out2;
240???????? }
241
242???????? printk("block device driver initsuccessfuly!\n");
243???????? return ret;
244err_out2:
245 ????????unregister_blkdev(fbd_driver_major,DRIVER_NAME);
246err_out1:
247???????? return ret;
248 }
249
250 staticvoid __exit fbd_driver_exit(void)
251 {
252???????? if(fbd_dev.disk){
253???????????????? printk("device[%s] isalready exist, delete it first!\n", fbd_dev.fbd_dev_nam??? e);
254????????????????dev_delete(fbd_dev.fbd_dev_name);
255???????? }
256
257???????? if(misc_deregister(&_misc_dev)< 0) {
258???????????????? printk("Deregister ioctlcontrol device[%s] failed\n",?_misc_dev.name);
259???????? }
260
261???????? /* unregister fbd driver */
262???????? unregister_blkdev(fbd_driver_major,DRIVER_NAME);
263???????? printk("block device driver exitsuccessfuly!\n");
264 }
265
266module_init(fbd_driver_init);
267module_exit(fbd_driver_exit);
268MODULE_LICENSE("GPL");
總結
以上是生活随笔為你收集整理的转载:谢谢原作者:块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转载:谢谢原作者:块设备驱动实战基础篇三
- 下一篇: BIO bi_sector submit