第二部分 实 验 指 导

55
设设设设设设 _ 1 成成成成成成成成 成成 成成成成 成 成 成 成 成成成成 成 成 成 成 成成成成 成 成 成 成 成成成成 成 成 成 成 7.1 7.1 成成成成 成成成成 7.2 7.2 成成成成 成成成成 7.2.1 7.2.1 成成成成成成成成 成成成成成成成成

Upload: lilka

Post on 02-Feb-2016

134 views

Category:

Documents


0 download

DESCRIPTION

第二部分 实 验 指 导. 第二部分 实 验 指 导 7.1 实验目的 7.2 准备知识 7.2.1 设备驱动程序简介. 图 7-1 字符(块)设备、驱动程序和接口. 7.2.2 设备驱动程序与外界的接口 7.2.3 设备驱动程序的组织结构. 图 7-2 设备驱动程序与外界的接口. 7.2.4 设备驱动程序的代码. # include #include - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第二部分  实 验 指 导

设备管理实验 _ 1 成都信息工程学院 徐虹

第二部分 实 验 指 导第二部分 实 验 指 导 第二部分 实 验 指 导第二部分 实 验 指 导

第二部分 实 验 指 导第二部分 实 验 指 导

7.1 7.1 实验目的实验目的 7.2 7.2 准备知识 准备知识

• 7.2.1 7.2.1 设备驱动程序简介 设备驱动程序简介

Page 2: 第二部分  实 验 指 导

设备管理实验 _ 2 成都信息工程学院 徐虹

图图 7-1 7-1 字符字符 (( 块块 )) 设备、驱动程序和接口设备、驱动程序和接口 图图 7-1 7-1 字符字符 (( 块块 )) 设备、驱动程序和接口设备、驱动程序和接口

Page 3: 第二部分  实 验 指 导

设备管理实验 _ 3 成都信息工程学院 徐虹

•7.2.2 7.2.2 设备驱动程序与外界的设备驱动程序与外界的接口接口

•7.2.3 7.2.3 设备驱动程序的组织结设备驱动程序的组织结构构

Page 4: 第二部分  实 验 指 导

设备管理实验 _ 4 成都信息工程学院 徐虹

图图 7-2 7-2 设备驱动程序与外界的接口设备驱动程序与外界的接口 图图 7-2 7-2 设备驱动程序与外界的接口设备驱动程序与外界的接口

Page 5: 第二部分  实 验 指 导

设备管理实验 _ 5 成都信息工程学院 徐虹

7.2.4 7.2.4 设备驱动程序的代码设备驱动程序的代码 7.2.4 7.2.4 设备驱动程序的代码设备驱动程序的代码

• ##include <linux/fs.h> include <linux/fs.h> • #include <linux/errno.h> #include <linux/errno.h> • int register_chrdev(unsigned int major,const char int register_chrdev(unsigned int major,const char

*name, struct file_operations*name, struct file_operations *ops); *ops);

• struct blk_dev_struct { struct blk_dev_struct { • // queue_proc // queue_proc 指向的队列必须为原子操作指向的队列必须为原子操作 ,, 即指令的执行是即指令的执行是

一次性完成的一次性完成的 ,, 不能间断不能间断• request_queue_t request_queue ; request_queue_t request_queue ; • queue_proc *queue ; queue_proc *queue ; • void *data ; void *data ; • };}; • struct blk_dev_struct blk_dev[MAX_BLKDEV]struct blk_dev_struct blk_dev[MAX_BLKDEV]

Page 6: 第二部分  实 验 指 导

设备管理实验 _ 6 成都信息工程学院 徐虹

图图 7-3 7-3 blk_dev_structblk_dev_struct 图图 7-3 7-3 blk_dev_structblk_dev_struct

Page 7: 第二部分  实 验 指 导

设备管理实验 _ 7 成都信息工程学院 徐虹

• static struct { static struct { • const char *name;const char *name;• struct block_device_operations *bdops;struct block_device_operations *bdops;• } blkdevs[MAX_BLKDEV];} blkdevs[MAX_BLKDEV];

• int register_blkdev(unsigned int int register_blkdev(unsigned int major,const char *name,struct major,const char *name,struct block_device_block_device_ operations *bdops); operations *bdops);

  

Page 8: 第二部分  实 验 指 导

设备管理实验 _ 8 成都信息工程学院 徐虹

图图 7-4 7-4 块设备驱动程序的注册块设备驱动程序的注册 图图 7-4 7-4 块设备驱动程序的注册块设备驱动程序的注册

Page 9: 第二部分  实 验 指 导

设备管理实验 _ 9 成都信息工程学院 徐虹

7.3 7.3 实验内容实验内容

• 7.3.1 7.3.1 字符类型设备的驱动程序字符类型设备的驱动程序• 7.3.2 7.3.2 块类型设备的驱动程序块类型设备的驱动程序 7.4 7.4 实验指导 实验指导

• 7.4.1 7.4.1 字符类型设备驱动程序 字符类型设备驱动程序

Page 10: 第二部分  实 验 指 导

设备管理实验 _ 10 成都信息工程学院 徐虹

• struct device_struct{ struct device_struct{ • const char *name; const char *name; • struct file_operations *chops; struct file_operations *chops; • }; }; • static struct device_struct chrdevs[MAX_CHRDEV]; static struct device_struct chrdevs[MAX_CHRDEV]; • typedef struct Scull_Dev { typedef struct Scull_Dev { • void **data; void **data; • int quantum; // int quantum; // 当前容量的大小 当前容量的大小 • int qset; // int qset; // 当前数组的大小 当前数组的大小 • unsigned long size; unsigned long size; • unsigned int access_key; // unsigned int access_key; // 由由 sculluid sculluid 和和 scullpriv scullpriv 使用使用

的存取字段。的存取字段。• unsigned int usage; // unsigned int usage; // 当字符设备使用时加锁 当字符设备使用时加锁 • struct Scull_Dev *next; // struct Scull_Dev *next; // 指针指向下一字符设备 指针指向下一字符设备 • }}scullscull

Page 11: 第二部分  实 验 指 导

设备管理实验 _ 11 成都信息工程学院 徐虹

• static int scull_open(struct inode *inode,struct file static int scull_open(struct inode *inode,struct file *filp);// *filp);// 打开字符设备打开字符设备

• static int scull_release(struct inode *inode,struct file static int scull_release(struct inode *inode,struct file *filp);*filp);

• // // 释放字符设备释放字符设备• static ssize_t scull_write(struct inode *inode,struct file static ssize_t scull_write(struct inode *inode,struct file

*filp,const char *buffer,int count); *filp,const char *buffer,int count); // // 将数据送往将数据送往字符设备字符设备

• static ssize_t scull_read(struct inode *inode,struct file static ssize_t scull_read(struct inode *inode,struct file *filp,char *buffer,int count); *filp,char *buffer,int count); // // 从字符设备读出数据从字符设备读出数据 ,,写入用户空间写入用户空间

• static int scull_ioctl(struct inode *inode,struct file static int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg); *filp,unsigned long int cmd,unsigned long arg); // // 字符字符设备的控制操作设备的控制操作

Page 12: 第二部分  实 验 指 导

设备管理实验 _ 12 成都信息工程学院 徐虹

• struct file_operations chr_fops = {struct file_operations chr_fops = {• NULL, // seek,NULL, // seek, 改变字符设备的操作位置改变字符设备的操作位置• scull_read, // read,scull_read, // read, 字符设备的读操作字符设备的读操作• scull_write, // write,scull_write, // write, 字符设备的写操作字符设备的写操作• NULL, NULL, // readdir,// readdir, 读取某个子目录中读取某个子目录中

的内容的内容• NULL, NULL, // poll,// poll, 允许应用程序响应来自允许应用程序响应来自

字符设备的事件字符设备的事件• scull_ioctl, // ioctl,scull_ioctl, // ioctl, 字符设备的控制操作字符设备的控制操作• NULL, NULL, // mmap,// mmap, 字符设备地址空间到字符设备地址空间到

用户地址空间的映射用户地址空间的映射• scull_open, // open,scull_open, // open, 字符设备的打开操作字符设备的打开操作

Page 13: 第二部分  实 验 指 导

设备管理实验 _ 13 成都信息工程学院 徐虹

• NULL, // flush,NULL, // flush, 冲掉缓冲区的数据冲掉缓冲区的数据 ,, 对字符设备无用对字符设备无用• scull_release, // release,scull_release, // release, 字符设备的释放操作字符设备的释放操作• NULL, // fsync,NULL, // fsync, 同步内存与磁盘上的数据状态同步内存与磁盘上的数据状态 ,, 把输出把输出

缓冲区里缓冲区里• // // 尚未写到磁盘的数据写出尚未写到磁盘的数据写出• NULL, // fasync,NULL, // fasync, 改变字符设备行为改变字符设备行为• NULL, NULL, // check media change,// check media change, 检查检查

自上次操作后自上次操作后 ,, 介质介质 (( 软盘和软盘和• // // CD-ROM)CD-ROM) 是否更换是否更换• NULL, // revalidate,NULL, // revalidate, 若更换了介质若更换了介质 ,, 则更新信息 则更新信息 • NULL // lock,NULL // lock, 锁定字符设备操作锁定字符设备操作• };};

Page 14: 第二部分  实 验 指 导

设备管理实验 _ 14 成都信息工程学院 徐虹

• ##include <linux/fs.h>include <linux/fs.h>• #include <linux/errno.h>#include <linux/errno.h>• int register_chrdev(unsigned int major,const char int register_chrdev(unsigned int major,const char

*name,struct file_operation*name,struct file_operation• *fops);*fops);

• static int scull_open(struct inode *inode,struct file *filp) static int scull_open(struct inode *inode,struct file *filp) {{

• ......• MOD_INC_USE_COUNT;MOD_INC_USE_COUNT;• return 0;return 0;• }}

Page 15: 第二部分  实 验 指 导

设备管理实验 _ 15 成都信息工程学院 徐虹

• static int scull_release(struct inode static int scull_release(struct inode *inode,struct file *filp) {*inode,struct file *filp) {

• ......• MOD_DEC_USE_COUNT;MOD_DEC_USE_COUNT;• return 0;return 0;• }}•   • static int scull_ioctl(struct inode static int scull_ioctl(struct inode

*inode,struct file *filp,unsigned long int *inode,struct file *filp,unsigned long int cmd,unsigned long arg);cmd,unsigned long arg);

Page 16: 第二部分  实 验 指 导

设备管理实验 _ 16 成都信息工程学院 徐虹

图图 7-5 7-5 scull_openscull_open()() 流程图流程图 图图 7-5 7-5 scull_openscull_open()() 流程图流程图

Page 17: 第二部分  实 验 指 导

设备管理实验 _ 17 成都信息工程学院 徐虹

图图 7-6 7-6 scull_writescull_write()() 的流程图的流程图 图图 7-6 7-6 scull_writescull_write()() 的流程图的流程图

Page 18: 第二部分  实 验 指 导

设备管理实验 _ 18 成都信息工程学院 徐虹

图图 7-7 7-7 scull_readscull_read()() 流程图流程图 图图 7-7 7-7 scull_readscull_read()() 流程图流程图 • ##mknod /dev/chrdev c major minormknod /dev/chrdev c major minor

Page 19: 第二部分  实 验 指 导

设备管理实验 _ 19 成都信息工程学院 徐虹

图图 7-8 7-8 scull_ioctlscull_ioctl()() 流程图流程图 图图 7-8 7-8 scull_ioctlscull_ioctl()() 流程图流程图

• 图注:图注: SRTSRT :: SCULL_RESET SQNMSCULL_RESET SQNM ::SCULL_QUERY_NEW_MSG SQMLSCULL_QUERY_NEW_MSG SQML ::

SCULL_QUERY_MSG_LENGTHSCULL_QUERY_MSG_LENGTH

Page 20: 第二部分  实 验 指 导

设备管理实验 _ 20 成都信息工程学院 徐虹

图图 7-9 7-9 scull_releasescull_release()() 流程图流程图图图 7-9 7-9 scull_releasescull_release()() 流程图流程图

Page 21: 第二部分  实 验 指 导

设备管理实验 _ 21 成都信息工程学院 徐虹

图图 7-10 7-10 字符设备驱动程序的测试函数流程图字符设备驱动程序的测试函数流程图 图图 7-10 7-10 字符设备驱动程序的测试函数流程图字符设备驱动程序的测试函数流程图

• ##cat /proc/devices | awk "\\$2==\ "chrdev\"{ cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}"print\\$1}"

Page 22: 第二部分  实 验 指 导

设备管理实验 _ 22 成都信息工程学院 徐虹

7.4.2 7.4.2 块类型设备驱动程序块类型设备驱动程序 7.4.2 7.4.2 块类型设备驱动程序块类型设备驱动程序

• struct device_struct { struct device_struct { • const char *name; const char *name; • struct file_operations *chops; }; struct file_operations *chops; }; • static struct device_struct blkdevs[MAX_BLKDEV]; static struct device_struct blkdevs[MAX_BLKDEV]; • struct sbull_dev { struct sbull_dev { • void **data; void **data; • int quantum; int quantum; // // 当前容量的大小 当前容量的大小 • int qset; int qset; // // 当前数组的大小 当前数组的大小 • unsigned long size; unsigned long size; • unsigned int access_key; //unsigned int access_key; // 由由 sbulluidsbulluid 和和 sbullprivsbullpriv 使用的存取字段。 使用的存取字段。 • unsigned int usage; // unsigned int usage; // 当块设备正使用时加锁 当块设备正使用时加锁 • unsigned int new_msg; unsigned int new_msg; • struct sbull_dev *next; // struct sbull_dev *next; // 指向下一块设备 指向下一块设备 • }; }; extern struct sbull_dev *sbull;extern struct sbull_dev *sbull; // // 块设块设

备信息备信息

Page 23: 第二部分  实 验 指 导

设备管理实验 _ 23 成都信息工程学院 徐虹

• struct file_operations blk_fops = {struct file_operations blk_fops = {• NULL, NULL, // seek,// seek, 改变块设备的操作位置改变块设备的操作位置• block_read, block_read, // // 块设备的读操作块设备的读操作 ,, 为内核函数为内核函数• block_write, block_write, // // 块设备的写操作块设备的写操作 ,, 为内核函数为内核函数• NULL, // readdir,NULL, // readdir, 读取某个子目录中的内容读取某个子目录中的内容• NULL, // poll,NULL, // poll, 允许应用程序响应来自块设备的事件允许应用程序响应来自块设备的事件• sbull_ioctl, sbull_ioctl, // ioctl,// ioctl, 块设备的控制操作块设备的控制操作• NULL, NULL, // mmap,// mmap, 块设备地址空间到用户地址块设备地址空间到用户地址

空间的映射空间的映射• sbull_open, sbull_open, // open,// open, 块设备的打开操作块设备的打开操作• NULL, // flush,NULL, // flush, 冲掉块设备缓冲区的数据冲掉块设备缓冲区的数据• sbull_release, sbull_release, // release,// release, 块设备的释放操作块设备的释放操作

Page 24: 第二部分  实 验 指 导

设备管理实验 _ 24 成都信息工程学院 徐虹

• block_fsync, block_fsync, // // 同步内存与磁盘上的数据状态同步内存与磁盘上的数据状态 ,, 把输把输出缓冲区里出缓冲区里

• // // 尚未写到磁盘的数据写出去。为内核函数 尚未写到磁盘的数据写出去。为内核函数 • NULL, NULL, // fasync,// fasync, 改变块设备行为改变块设备行为• sbull_check_media_change, sbull_check_media_change, // check media change,// check media change, 检查检查

自上次操作后自上次操作后 ,, 介质介质• // (// ( 软盘和软盘和 CD-ROM)CD-ROM) 是否更换 是否更换 • NULL, NULL, // revalidate,// revalidate, 若更换了介质若更换了介质 ,,

则更新信息则更新信息• NULL NULL // lock,// lock, 锁定块设备操作锁定块设备操作• }; };

Page 25: 第二部分  实 验 指 导

设备管理实验 _ 25 成都信息工程学院 徐虹

• struct blk_dev_struct {struct blk_dev_struct {• void (*request_fn)(void);void (*request_fn)(void);• struct request *current_request;struct request *current_request;• struct request plug;struct request plug;• struct tq_struct plug_tq;};struct tq_struct plug_tq;};•   struct request {struct request {• ......• kdev_t rq_dev;kdev_t rq_dev;• int cmd; // int cmd; // 读或写读或写• int errors;int errors;• unsigned long sector;unsigned long sector;• char *buffer;char *buffer;• struct request *next;struct request *next;• ......• };};

Page 26: 第二部分  实 验 指 导

设备管理实验 _ 26 成都信息工程学院 徐虹

• ##define CURRENT (blk_dev[MAJOR_NR].current_request)define CURRENT (blk_dev[MAJOR_NR].current_request)•   • void sbull_request(void) {void sbull_request(void) {• unsigned long offset,total;unsigned long offset,total;• BeginBegin ::• INIT_REQUESTINIT_REQUEST ::• offset = CURRENT -> sector * sbull_hard;offset = CURRENT -> sector * sbull_hard;• total = CURRENT -> current_nr_sectors * total = CURRENT -> current_nr_sectors *

sbull_hard;sbull_hard;• // // 判断对设备的访问是否越界判断对设备的访问是否越界• if(total + offset > sbull_size * 1024) {if(total + offset > sbull_size * 1024) {• // // 请求操作错误请求操作错误• end_request(0);end_request(0);

Page 27: 第二部分  实 验 指 导

设备管理实验 _ 27 成都信息工程学院 徐虹

goto Begin;goto Begin;• } } • if(CURRENT -> cmd == READ) {if(CURRENT -> cmd == READ) {• memcpy(CURRENT -> buffer,sbull_storage + memcpy(CURRENT -> buffer,sbull_storage +

offset,total);offset,total);• }}• else if(CURRENT -> cmd == WRITE) {else if(CURRENT -> cmd == WRITE) {• memcpy(sbull_storage+ offset,CURRENT -> buffer,total);memcpy(sbull_storage+ offset,CURRENT -> buffer,total);• }}• else {else {• end_request(0);end_request(0);• }// }// 成功成功• end_request(1);// end_request(1);// 操作结束操作结束 ,,INIT_REQUESTINIT_REQUEST 返回。返回。• goto Begin;goto Begin;• }}

Page 28: 第二部分  实 验 指 导

设备管理实验 _ 28 成都信息工程学院 徐虹

• sbull_init();sbull_init();•   •

if(register_blkdev(sbull_MAJOR,"sbull",&sbull_fif(register_blkdev(sbull_MAJOR,"sbull",&sbull_fops)) {ops)) {

• printk("Registering block device majorprintk("Registering block device major :: %d %d failed\n",sbull_MAJOR);failed\n",sbull_MAJOR);

• return –EIO;return –EIO;• };};•   • blk_dev[sbull_MAJOR].request_fn= blk_dev[sbull_MAJOR].request_fn=

DEVICE_REQUEST;DEVICE_REQUEST;

Page 29: 第二部分  实 验 指 导

设备管理实验 _ 29 成都信息工程学院 徐虹

• ##define sbull_HARDS_SIZE 512define sbull_HARDS_SIZE 512• #define sbull_BLOCK_SIZE 1024#define sbull_BLOCK_SIZE 1024• static int sbull_hard = sbull_HARDS_SIZE;static int sbull_hard = sbull_HARDS_SIZE;• static int sbull_soft = sbull_BLOCK_SIZE;static int sbull_soft = sbull_BLOCK_SIZE;• hardsect_size[sbull_MAJOR] = &sbull_hard;hardsect_size[sbull_MAJOR] = &sbull_hard;• blksize_size[sbull_MAJOR] = &sbull_soft;blksize_size[sbull_MAJOR] = &sbull_soft;•   • #define MAJOR_NR sbull_MAJOR#define MAJOR_NR sbull_MAJOR• #define DEVICE_NAME "sbull"#define DEVICE_NAME "sbull"• #define DEVICE_REQUEST sbull_request#define DEVICE_REQUEST sbull_request• #define DEVICE_NR(device) (MINOR(device))#define DEVICE_NR(device) (MINOR(device))• #define DEVICE_ON(device) #define DEVICE_ON(device)

• #define DEVICE_OFF(device)#define DEVICE_OFF(device)

Page 30: 第二部分  实 验 指 导

设备管理实验 _ 30 成都信息工程学院 徐虹

图图 7-11 7-11 sbull_opensbull_open()() 流程图流程图 图图 7-11 7-11 sbull_opensbull_open()() 流程图流程图

Page 31: 第二部分  实 验 指 导

设备管理实验 _ 31 成都信息工程学院 徐虹

图图 7-12 7-12 sbull_ioctlsbull_ioctl()() 流程图流程图 图图 7-12 7-12 sbull_ioctlsbull_ioctl()() 流程图流程图

Page 32: 第二部分  实 验 指 导

设备管理实验 _ 32 成都信息工程学院 徐虹

• 图注图注• BGZBGZ :: BLKGETSIZE BFBBLKGETSIZE BFB :: BLKFLSBUFBLKFLSBUF• BRRPBRRP :: BLKRRPART UCBLKRRPART UC :: Unknown CommandUnknown Command• void sleep_on(struct wait_queue **ptr);void sleep_on(struct wait_queue **ptr);• void interruptible_sleep_on(struct wait_queue **ptr);void interruptible_sleep_on(struct wait_queue **ptr);•   •   • void wake_up(struct wait_queue **ptr);void wake_up(struct wait_queue **ptr);• void wake_up_interruptible(struct wait_queue **ptr);void wake_up_interruptible(struct wait_queue **ptr);•   •   • struct buffer_head *getblk(kdev_t,int block,int size);struct buffer_head *getblk(kdev_t,int block,int size);• void breles(struct buffer_head *buf);void breles(struct buffer_head *buf);

Page 33: 第二部分  实 验 指 导

设备管理实验 _ 33 成都信息工程学院 徐虹

图图 7-13 7-13 sbull_releasesbull_release()() 流程图流程图 图图 7-13 7-13 sbull_releasesbull_release()() 流程图流程图

Page 34: 第二部分  实 验 指 导

设备管理实验 _ 34 成都信息工程学院 徐虹

7.5 7.5 参考源程序代码 参考源程序代码 • 7.5.1 7.5.1 字符设备驱动程序 字符设备驱动程序 • int scull_open(struct inode *inode,struct file *filp) {int scull_open(struct inode *inode,struct file *filp) {•   • MOD_INC_USE_COUNT; // MOD_INC_USE_COUNT; // 增加该模块的用户数目 增加该模块的用户数目

• printk("This chrdev is in open\n"); printk("This chrdev is in open\n");

• return 0; return 0;

• } } •   • int scull_write(struct inode *inode,struct file *filp,const char int scull_write(struct inode *inode,struct file *filp,const char

*buffer,int *buffer,int count) count) { {

Page 35: 第二部分  实 验 指 导

设备管理实验 _ 35 成都信息工程学院 徐虹

• if(count < 0) if(count < 0) • return –EINVAL; return –EINVAL;

• if(scull.usage || scull.new_msg) if(scull.usage || scull.new_msg)

• return –EBUSY; return –EBUSY; • scull.usage = 1; scull.usage = 1;

• kfree(scull.data); kfree(scull.data);

• data = kmalloc(sizeof(char) *(count+1),GFP_KERNEL); data = kmalloc(sizeof(char) *(count+1),GFP_KERNEL);

• if(!scull.data) { if(!scull.data) {

• return ENOMEM; return ENOMEM; • } } • copy_from_user(scull.data,buffer,count + 1); copy_from_user(scull.data,buffer,count + 1);

• scull.usage = 0; scull.usage = 0; • scull.new_msg = 1; scull.new_msg = 1;

• return count; } return count; }

Page 36: 第二部分  实 验 指 导

设备管理实验 _ 36 成都信息工程学院 徐虹

• int scull_read(struct inode *inode,struct file *filp,char *buffer,int int scull_read(struct inode *inode,struct file *filp,char *buffer,int count){count){

• int length; int length; • if(count < 0) if(count < 0)

• return –EINVAL; return –EINVAL; • if(scull.usage) if(scull.usage)

• return –EBUSY; return –EBUSY;

• scull.usage = 1; scull.usage = 1;

• if(scull.data == 0) if(scull.data == 0)

• return 0; return 0;

• length = strlen(scull.data);length = strlen(scull.data);

Page 37: 第二部分  实 验 指 导

设备管理实验 _ 37 成都信息工程学院 徐虹

• if(length < count) if(length < count)

• count = length; count = length;

• copy_to_user(buf,scull.data,count + 1); copy_to_user(buf,scull.data,count + 1);

• scull.new_msg = 0; scull.new_msg = 0;

• scull.usage = 0; scull.usage = 0;

• return count; return count;

• } }

Page 38: 第二部分  实 验 指 导

设备管理实验 _ 38 成都信息工程学院 徐虹

• ##include <linux/ioctl.h> include <linux/ioctl.h> • #define SCULL_MAJOR 0 #define SCULL_MAJOR 0 • #define SCULL_MAGIC SCULL_MAJOR #define SCULL_MAGIC SCULL_MAJOR • #define SCULL_RESET _IO(SCULL_MAGIC,0) // #define SCULL_RESET _IO(SCULL_MAGIC,0) // 重置数重置数

据 据 • ##define SCULL_QUERY_NEW_MSG _IO(SCULL_MAGIC,1)define SCULL_QUERY_NEW_MSG _IO(SCULL_MAGIC,1)

// // 检查新的消息 检查新的消息 • ##define SCULL_QUERY_MSG_LENGTH define SCULL_QUERY_MSG_LENGTH

_IO(SCULL_MAGIC,2)_IO(SCULL_MAGIC,2) // // 获取消息长度获取消息长度• ##define IOC_NEW_MSG 1define IOC_NEW_MSG 1• static int usage,new_msg; // static int usage,new_msg; // 控制标志控制标志• static char *data;static char *data;

• int scull_ioctl(struct inode *inode,struct file int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg) { *filp,unsigned long int cmd,unsigned long arg) {

Page 39: 第二部分  实 验 指 导

设备管理实验 _ 39 成都信息工程学院 徐虹

• int ret=0; int ret=0; • switch(cmd) { switch(cmd) { • case SCULL_RESET: case SCULL_RESET: • kfree(data); kfree(data); • data = NULL; data = NULL; • usage = 0; usage = 0; • new_msg = 0; new_msg = 0; • break; break; • case SCULL_QUERY_NEW_MSG: case SCULL_QUERY_NEW_MSG: • if(new_msg) if(new_msg) • return IOC_NEW_MSG; return IOC_NEW_MSG; • break; break; • case SCULL_QUERY_MSG_LENGTH: case SCULL_QUERY_MSG_LENGTH: • if(data == NULL){ return 0; }if(data == NULL){ return 0; }

Page 40: 第二部分  实 验 指 导

设备管理实验 _ 40 成都信息工程学院 徐虹

• else {else {

• return strlen(data);return strlen(data);• }}• break;break;• default:default:• return –ENOTTY; return –ENOTTY; • }}• return ret;return ret;• } }

Page 41: 第二部分  实 验 指 导

设备管理实验 _ 41 成都信息工程学院 徐虹

• void scull_release(struct inode *inode,struct file *filp) { void scull_release(struct inode *inode,struct file *filp) { • MOD_DEC_USE_COUNT; // MOD_DEC_USE_COUNT; // 该模块的该模块的

用户数目减用户数目减 11• printk("This chrdev is in release\n");printk("This chrdev is in release\n");• return 0; return 0; • #ifdef DEBUG #ifdef DEBUG • printk("scull_release(%p,%p)\printk("scull_release(%p,%p)\

n",inode,filp); n",inode,filp); • #endif #endif • } }

#mknod /dev/chrdev c major minor #mknod /dev/chrdev c major minor

##cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}")cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}")

Page 42: 第二部分  实 验 指 导

设备管理实验 _ 42 成都信息工程学院 徐虹

• ##include <stdio.h> include <stdio.h> • #include <sys/types.h> #include <sys/types.h> • #include <sys/stat.h> #include <sys/stat.h> • #include <sys/ioctl.h> #include <sys/ioctl.h> • #include <stdlib.h> #include <stdlib.h> • #include <string.h> #include <string.h>

• #include <fcntl.h>#include <fcntl.h> • ##include <unistd.h> include <unistd.h> • #include <errno.h>#include <errno.h>• #include "chardev.h" // #include "chardev.h" // 定义字符设备 定义字符设备 • void write_proc(void); void write_proc(void);

• void read_proc(void);void read_proc(void);

Page 43: 第二部分  实 验 指 导

设备管理实验 _ 43 成都信息工程学院 徐虹

• main(int argc,char **argv) { main(int argc,char **argv) { • if(argc == 1) { if(argc == 1) { • puts("syntax: testprog[write|read]\n"); puts("syntax: testprog[write|read]\n"); • exit(0); exit(0); • } } • if(!strcmp(argv[1], "write")) if(!strcmp(argv[1], "write")) • { write_porc(); } { write_porc(); } • else if(!strcmp(argv[1],"read")) else if(!strcmp(argv[1],"read")) • { read_proc(); } { read_proc(); } • else { else { • puts("testprog: invalid command!\n"); puts("testprog: invalid command!\n"); • } } • return 0; return 0; • } }

Page 44: 第二部分  实 验 指 导

设备管理实验 _ 44 成都信息工程学院 徐虹

• void write_proc() { void write_proc() { • int fd,len,quit = 0; int fd,len,quit = 0; • char buf[100]; char buf[100]; • fd = open("/dev/chrdev",O_WRONLY); fd = open("/dev/chrdev",O_WRONLY); • if(fd <= 0) { if(fd <= 0) { • printf("Error opening device for writing!\n"); printf("Error opening device for writing!\n"); • exit(1); exit(1); • } } • while(!quit) { while(!quit) { • printf("\n Please write intoprintf("\n Please write into :: "); "); • gets(buf); gets(buf); • if(!strcmp(buf,"exit")) if(!strcmp(buf,"exit"))

• quit = 1;quit = 1;

Page 45: 第二部分  实 验 指 导

设备管理实验 _ 45 成都信息工程学院 徐虹

• while(ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) while(ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) • usleep(100); usleep(100); • len = write(fd,buf,strlen(buf)); len = write(fd,buf,strlen(buf)); • if(len < 0) { if(len < 0) { • printf("Error writing to device!\n"); printf("Error writing to device!\n"); • close(fd); close(fd); • exit(1); exit(1); • } } • printf("\n There are %d bytes written to printf("\n There are %d bytes written to

device!\n",len);device!\n",len);• } } • close(fd); close(fd);

• }}

Page 46: 第二部分  实 验 指 导

设备管理实验 _ 46 成都信息工程学院 徐虹

void read_proc() { void read_proc() { • int fd,len,quit = 0; int fd,len,quit = 0; • char *buf = NULL; char *buf = NULL; • fd=open("/dev/chrdev",O_RDONLY); fd=open("/dev/chrdev",O_RDONLY); • if(fd < 0) { if(fd < 0) { • printf("Error opening device for reading!\printf("Error opening device for reading!\

n""); n""); • exit(1); exit(1); • } } • while(!quit) { while(!quit) { • printf("\n Please read outprintf("\n Please read out :: "); "); • while(!while(!

ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) • usleep(100); // usleep(100); // 获取消息长度 获取消息长度

Page 47: 第二部分  实 验 指 导

设备管理实验 _ 47 成都信息工程学院 徐虹

• len = ioctl(fd,DYNCHAR_QUERY_MSG_LENGTH,NULL); len = ioctl(fd,DYNCHAR_QUERY_MSG_LENGTH,NULL); • if(len) { if(len) { • if(buf != NULL) if(buf != NULL) • free(buf); free(buf); • buf = malloc(sizeof(char) * (len+1)); buf = malloc(sizeof(char) * (len+1)); • len = read(fd,buf,len); len = read(fd,buf,len); • if(len < 0) { if(len < 0) { • printf("Error reading from device!\n"); } printf("Error reading from device!\n"); }

• else { else { • if(!strcmp(buf,"exit") { if(!strcmp(buf,"exit") { • ioctl(fd,DYNCHAR_RESET); // ioctl(fd,DYNCHAR_RESET); // 复位复位• quit = 1; quit = 1; • } }

Page 48: 第二部分  实 验 指 导

设备管理实验 _ 48 成都信息工程学院 徐虹

• else else • printf("%s\n",buf); } printf("%s\n",buf); } • } } • } } • free(buf); free(buf); • close(fd);} close(fd);} • #ifndef _DYNCHAR_DEVICE_H #define #ifndef _DYNCHAR_DEVICE_H #define

_DYNCHAR_DEVICE_H_DYNCHAR_DEVICE_H• #include <linux/ioctl.h> #define DYNCHAR_MAJOR 42#include <linux/ioctl.h> #define DYNCHAR_MAJOR 42• #define DYNCHAR_MAGIC DYNCHAR_MAJOR#define DYNCHAR_MAGIC DYNCHAR_MAJOR• #define DYNCHAR_RESET _IO(DYNCHAR_MAGIC,0) // #define DYNCHAR_RESET _IO(DYNCHAR_MAGIC,0) // 重置重置

数据数据• ##define DYNCHAR_QUERY_NEW_MSG define DYNCHAR_QUERY_NEW_MSG

_IO(DYNCHAR_MAGIC,1) // _IO(DYNCHAR_MAGIC,1) // 检查新的消息检查新的消息• ##define DYNCHAR_QUERY_MSG_LENGTH define DYNCHAR_QUERY_MSG_LENGTH

_IO(DYNCHAR_MAGIC,2)_IO(DYNCHAR_MAGIC,2) // // 获到消息长度获到消息长度• ##define IOC_NEW_MSG 1define IOC_NEW_MSG 1• #endif #endif

Page 49: 第二部分  实 验 指 导

设备管理实验 _ 49 成都信息工程学院 徐虹

7.5.2 7.5.2 块设备驱动程序块设备驱动程序 7.5.2 7.5.2 块设备驱动程序块设备驱动程序

• typedef struct Sbull_Dev {typedef struct Sbull_Dev {• void * *data; void * *data; • int quantum; // int quantum; // 当前容量的大小 当前容量的大小 • int qset; // int qset; // 当前数组的大小 当前数组的大小 • unsigned long size; unsigned long size; • unsigned int new_msg; unsigned int new_msg; • unsigned int usage; unsigned int usage; // // 当块设备正使用时加当块设备正使用时加

锁 锁 • unsigned int access_key;unsigned int access_key; // // 由由 sbulluidsbulluid 和和

sbullprivsbullpriv 使用的存取字段使用的存取字段• struct Sbull_Dev *next;struct Sbull_Dev *next; // // 指向下一块设备指向下一块设备• }; }; • extern struct sbull_dev *sbull;extern struct sbull_dev *sbull; // // 块设备信息块设备信息

Page 50: 第二部分  实 验 指 导

设备管理实验 _ 50 成都信息工程学院 徐虹

• int sbull_open(struct inode *inode,struct file *filp) int sbull_open(struct inode *inode,struct file *filp) • {{• int num = MINOR(inode -> i_rdev); int num = MINOR(inode -> i_rdev); • if(num >= sbull -> size) if(num >= sbull -> size) • return –ENODEV; return –ENODEV; • sbull -> size = sbull -> size + num; sbull -> size = sbull -> size + num; • if(!sbull -> usage) { if(!sbull -> usage) { • check_disk_change(inode -> i_rdev); check_disk_change(inode -> i_rdev); • if(!* (sbull -> data)) if(!* (sbull -> data)) • return –ENOMEM; return –ENOMEM; • } } • sbull -> usage++; sbull -> usage++; • MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;

• return 0;}return 0;}

Page 51: 第二部分  实 验 指 导

设备管理实验 _ 51 成都信息工程学院 徐虹

• ##include <linux/ioctl.h> include <linux/ioctl.h> • #include <linux/fs.h> // BLKGETSIZE#include <linux/fs.h> // BLKGETSIZE 、、 BLKFLSBUFBLKFLSBUF 和和

BLKRRPARTBLKRRPART 在此头文件中定义 在此头文件中定义 • int sbull_ioctl(struct inode *inode,struct file int sbull_ioctl(struct inode *inode,struct file

*filp,unsigned int cmd,unsigned long arg) *filp,unsigned int cmd,unsigned long arg) • { { • int err; int err; • struct hd_geometry *geo = (struct hd_geometry struct hd_geometry *geo = (struct hd_geometry

*)arg; *)arg; • PDEBUG("ioctl 0x%x 0x%lx\n",cmd,arg); PDEBUG("ioctl 0x%x 0x%lx\n",cmd,arg); • switch(cmd) { switch(cmd) { • case BLKGETSIZE: case BLKGETSIZE: • // // 返回以扇区表示的设备大小。 返回以扇区表示的设备大小。

Page 52: 第二部分  实 验 指 导

设备管理实验 _ 52 成都信息工程学院 徐虹

• if(!arg) if(!arg) • return –EINVAL; // NULL return –EINVAL; // NULL 指针:设备不可用 指针:设备不可用 • err=verify_area(VERIFY_WRITE,(long*)arg, err=verify_area(VERIFY_WRITE,(long*)arg,

sizeof(long)); sizeof(long)); • if(err)if(err)• return err;return err;• put_user(1024*sbull_sizes[MINOR(inode -> i_rdev) put_user(1024*sbull_sizes[MINOR(inode -> i_rdev) • /sbull_hardsects[MINOR(inode -> /sbull_hardsects[MINOR(inode ->

i_rdev)], i_rdev)], • (long *)arg); (long *)arg); • return 0; return 0; • case BLKFLSBUF: // case BLKFLSBUF: // 冲缓冲区 冲缓冲区 • if(!suser()) if(!suser())

• return –EACCES; return –EACCES; // // 只对根目录只对根目录

Page 53: 第二部分  实 验 指 导

设备管理实验 _ 53 成都信息工程学院 徐虹

• fsync_dev(inode -> i_rdev); fsync_dev(inode -> i_rdev); • return 0; return 0; • case BLKRRPART: case BLKRRPART: // // 重读分区表:重读分区表:

不能做 不能做 • return –EINVAL; return –EINVAL; • RO_IOCTLS(inode -> i_rdev,arg); RO_IOCTLS(inode -> i_rdev,arg); • // // 默 认 的默 认 的 RO operationsRO operations 操 作操 作 ,, 宏宏

RO_IOCTLS(kdev_t dev,RO_IOCTLS(kdev_t dev,• // unsigned long where)// unsigned long where) 在在 blk.hblk.h 中定义 中定义 • } } • return –EINVAL; // return –EINVAL; // 未知命令 未知命令 • }}

Page 54: 第二部分  实 验 指 导

设备管理实验 _ 54 成都信息工程学院 徐虹

• void sbull_release(struct inode *inode,struct file *filp) void sbull_release(struct inode *inode,struct file *filp) • {{• sbull -> size = sbull -> size + MINOR(inode -> sbull -> size = sbull -> size + MINOR(inode ->

i_rdev); i_rdev); • sbull -> usage--; sbull -> usage--; • MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT; • printk("This blkdev is in release!\n"); printk("This blkdev is in release!\n"); • return 0; return 0; • #ifdef DEBUG #ifdef DEBUG • printk("sbull_release(%p,%p)\n",inode,filp); printk("sbull_release(%p,%p)\n",inode,filp); • #endif #endif • } }

Page 55: 第二部分  实 验 指 导

设备管理实验 _ 55 成都信息工程学院 徐虹

• extern struct request *CURRENT; extern struct request *CURRENT; • void sbull_request(void)void sbull_request(void)• { { • while(1) { while(1) { • INIT_REQUEST(); INIT_REQUEST(); • printk("request %p: cmd %i sec %li (nr.%li),next printk("request %p: cmd %i sec %li (nr.%li),next

%p\n", %p\n", • CURRENT, CURRENT, • CURRENT -> cmd, CURRENT -> cmd, • CURRENT -> sector, CURRENT -> sector, • CURRENT -> current_nr_sectors); CURRENT -> current_nr_sectors); • end_request(1); // end_request(1); // 请求成功 请求成功 • } } • } }