块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)

来源:互联网 发布:搜索引擎和大数据 编辑:程序博客网 时间:2024/04/29 07:04

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");


0 0