550 likes | 759 Views
第二部分 实 验 指 导. 第二部分 实 验 指 导 7.1 实验目的 7.2 准备知识 7.2.1 设备驱动程序简介. 图 7-1 字符(块)设备、驱动程序和接口. 7.2.2 设备驱动程序与外界的接口 7.2.3 设备驱动程序的组织结构. 图 7-2 设备驱动程序与外界的接口. 7.2.4 设备驱动程序的代码. # include <linux/fs.h> #include <linux/errno.h>
E N D
第二部分 实 验 指 导 第二部分 实 验 指 导 7.1 实验目的 7.2 准备知识 • 7.2.1 设备驱动程序简介 设备管理实验 _ 1 成都信息工程学院 徐虹
图7-1 字符(块)设备、驱动程序和接口 设备管理实验 _ 2 成都信息工程学院 徐虹
7.2.2 设备驱动程序与外界的接口 • 7.2.3 设备驱动程序的组织结构 设备管理实验 _ 3 成都信息工程学院 徐虹
图7-2 设备驱动程序与外界的接口 设备管理实验 _ 4 成都信息工程学院 徐虹
7.2.4 设备驱动程序的代码 • #include <linux/fs.h> • #include <linux/errno.h> • int register_chrdev(unsigned int major,const char *name, struct file_operations *ops); • struct blk_dev_struct { • // queue_proc 指向的队列必须为原子操作,即指令的执行是一次性完成的,不能间断 • request_queue_t request_queue ; • queue_proc *queue ; • void *data ; • }; • struct blk_dev_struct blk_dev[MAX_BLKDEV] 设备管理实验 _ 5 成都信息工程学院 徐虹
图7-3 blk_dev_struct 设备管理实验 _ 6 成都信息工程学院 徐虹
static struct { • const char *name; • struct block_device_operations *bdops; • } blkdevs[MAX_BLKDEV]; • int register_blkdev(unsigned int major,const char *name,struct block_device_ operations *bdops); 设备管理实验 _ 7 成都信息工程学院 徐虹
图7-4 块设备驱动程序的注册 设备管理实验 _ 8 成都信息工程学院 徐虹
7.3 实验内容 • 7.3.1 字符类型设备的驱动程序 • 7.3.2 块类型设备的驱动程序 7.4 实验指导 • 7.4.1 字符类型设备驱动程序 设备管理实验 _ 9 成都信息工程学院 徐虹
struct device_struct{ • const char *name; • struct file_operations *chops; • }; • static struct device_struct chrdevs[MAX_CHRDEV]; • typedef struct Scull_Dev { • void **data; • int quantum; // 当前容量的大小 • int qset; // 当前数组的大小 • unsigned long size; • unsigned int access_key; // 由sculluid 和scullpriv 使用的存取字段。 • unsigned int usage; // 当字符设备使用时加锁 • struct Scull_Dev *next; // 指针指向下一字符设备 • }scull 设备管理实验 _ 10 成都信息工程学院 徐虹
static int scull_open(struct inode *inode,struct file *filp);// 打开字符设备 • static int scull_release(struct inode *inode,struct file *filp); • // 释放字符设备 • static ssize_t scull_write(struct inode *inode,struct file *filp,const char *buffer,int count); // 将数据送往字符设备 • static ssize_t scull_read(struct inode *inode,struct file *filp,char *buffer,int count); // 从字符设备读出数据,写入用户空间 • static int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg); // 字符设备的控制操作 设备管理实验 _ 11 成都信息工程学院 徐虹
struct file_operations chr_fops = { • NULL, // seek,改变字符设备的操作位置 • scull_read, // read,字符设备的读操作 • scull_write, // write,字符设备的写操作 • NULL, // readdir,读取某个子目录中的内容 • NULL, // poll,允许应用程序响应来自字符设备的事件 • scull_ioctl, // ioctl,字符设备的控制操作 • NULL, // mmap,字符设备地址空间到用户地址空间的映射 • scull_open, // open,字符设备的打开操作 设备管理实验 _ 12 成都信息工程学院 徐虹
NULL, // flush,冲掉缓冲区的数据,对字符设备无用 • scull_release, // release,字符设备的释放操作 • NULL, // fsync,同步内存与磁盘上的数据状态,把输出缓冲区里 • // 尚未写到磁盘的数据写出 • NULL, // fasync,改变字符设备行为 • NULL, // check media change,检查自上次操作后,介质(软盘和 • // CD-ROM)是否更换 • NULL, // revalidate,若更换了介质,则更新信息 • NULL // lock,锁定字符设备操作 • }; 设备管理实验 _ 13 成都信息工程学院 徐虹
#include <linux/fs.h> • #include <linux/errno.h> • int register_chrdev(unsigned int major,const char *name,struct file_operation • *fops); • static int scull_open(struct inode *inode,struct file *filp) { • ... • MOD_INC_USE_COUNT; • return 0; • } 设备管理实验 _ 14 成都信息工程学院 徐虹
static int scull_release(struct inode *inode,struct file *filp) { • ... • MOD_DEC_USE_COUNT; • return 0; • } • static int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg); 设备管理实验 _ 15 成都信息工程学院 徐虹
图7-5 scull_open()流程图 设备管理实验 _ 16 成都信息工程学院 徐虹
图7-6 scull_write()的流程图 设备管理实验 _ 17 成都信息工程学院 徐虹
图7-7 scull_read()流程图 • #mknod /dev/chrdev c major minor 设备管理实验 _ 18 成都信息工程学院 徐虹
图7-8 scull_ioctl()流程图 • 图注:SRT:SCULL_RESET SQNM:SCULL_QUERY_NEW_MSG SQML:SCULL_QUERY_MSG_LENGTH 设备管理实验 _ 19 成都信息工程学院 徐虹
图7-9 scull_release()流程图 设备管理实验 _ 20 成都信息工程学院 徐虹
图7-10 字符设备驱动程序的测试函数流程图 • #cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}" 设备管理实验 _ 21 成都信息工程学院 徐虹
7.4.2 块类型设备驱动程序 • struct device_struct { • const char *name; • struct file_operations *chops; }; • static struct device_struct blkdevs[MAX_BLKDEV]; • struct sbull_dev { • void **data; • int quantum; // 当前容量的大小 • int qset; // 当前数组的大小 • unsigned long size; • unsigned int access_key; //由sbulluid和sbullpriv使用的存取字段。 • unsigned int usage; // 当块设备正使用时加锁 • unsigned int new_msg; • struct sbull_dev *next; // 指向下一块设备 • }; extern struct sbull_dev *sbull; // 块设备信息 设备管理实验 _ 22 成都信息工程学院 徐虹
struct file_operations blk_fops = { • NULL, // seek,改变块设备的操作位置 • block_read, // 块设备的读操作,为内核函数 • block_write, // 块设备的写操作,为内核函数 • NULL, // readdir,读取某个子目录中的内容 • NULL, // poll,允许应用程序响应来自块设备的事件 • sbull_ioctl, // ioctl,块设备的控制操作 • NULL, // mmap,块设备地址空间到用户地址空间的映射 • sbull_open, // open,块设备的打开操作 • NULL, // flush,冲掉块设备缓冲区的数据 • sbull_release, // release,块设备的释放操作 设备管理实验 _ 23 成都信息工程学院 徐虹
block_fsync, // 同步内存与磁盘上的数据状态,把输出缓冲区里 • // 尚未写到磁盘的数据写出去。为内核函数 • NULL, // fasync,改变块设备行为 • sbull_check_media_change, // check media change,检查自上次操作后,介质 • // (软盘和CD-ROM)是否更换 • NULL, // revalidate,若更换了介质,则更新信息 • NULL // lock,锁定块设备操作 • }; 设备管理实验 _ 24 成都信息工程学院 徐虹
struct blk_dev_struct { • void (*request_fn)(void); • struct request *current_request; • struct request plug; • struct tq_struct plug_tq;}; • struct request { • ... • kdev_t rq_dev; • int cmd; // 读或写 • int errors; • unsigned long sector; • char *buffer; • struct request *next; • ... • }; 设备管理实验 _ 25 成都信息工程学院 徐虹
#define CURRENT (blk_dev[MAJOR_NR].current_request) • void sbull_request(void) { • unsigned long offset,total; • Begin: • INIT_REQUEST: • offset = CURRENT -> sector * sbull_hard; • total = CURRENT -> current_nr_sectors * sbull_hard; • // 判断对设备的访问是否越界 • if(total + offset > sbull_size * 1024) { • // 请求操作错误 • end_request(0); 设备管理实验 _ 26 成都信息工程学院 徐虹
goto Begin; • } • if(CURRENT -> cmd == READ) { • memcpy(CURRENT -> buffer,sbull_storage + offset,total); • } • else if(CURRENT -> cmd == WRITE) { • memcpy(sbull_storage+ offset,CURRENT -> buffer,total); • } • else { • end_request(0); • }// 成功 • end_request(1);// 操作结束,INIT_REQUEST返回。 • goto Begin; • } 设备管理实验 _ 27 成都信息工程学院 徐虹
sbull_init(); • if(register_blkdev(sbull_MAJOR,"sbull",&sbull_fops)) { • printk("Registering block device major:%d failed\n",sbull_MAJOR); • return –EIO; • }; • blk_dev[sbull_MAJOR].request_fn= DEVICE_REQUEST; 设备管理实验 _ 28 成都信息工程学院 徐虹
#define sbull_HARDS_SIZE 512 • #define sbull_BLOCK_SIZE 1024 • static int sbull_hard = sbull_HARDS_SIZE; • static int sbull_soft = sbull_BLOCK_SIZE; • hardsect_size[sbull_MAJOR] = &sbull_hard; • blksize_size[sbull_MAJOR] = &sbull_soft; • #define MAJOR_NR sbull_MAJOR • #define DEVICE_NAME "sbull" • #define DEVICE_REQUEST sbull_request • #define DEVICE_NR(device) (MINOR(device)) • #define DEVICE_ON(device) • #define DEVICE_OFF(device) 设备管理实验 _ 29 成都信息工程学院 徐虹
图7-11 sbull_open()流程图 设备管理实验 _ 30 成都信息工程学院 徐虹
图7-12 sbull_ioctl()流程图 设备管理实验 _ 31 成都信息工程学院 徐虹
图注 • BGZ:BLKGETSIZE BFB:BLKFLSBUF • BRRP:BLKRRPART UC:Unknown Command • void sleep_on(struct wait_queue **ptr); • void interruptible_sleep_on(struct wait_queue **ptr); • void wake_up(struct wait_queue **ptr); • void wake_up_interruptible(struct wait_queue **ptr); • struct buffer_head *getblk(kdev_t,int block,int size); • void breles(struct buffer_head *buf); 设备管理实验 _ 32 成都信息工程学院 徐虹
图7-13 sbull_release()流程图 设备管理实验 _ 33 成都信息工程学院 徐虹
7.5 参考源程序代码 • 7.5.1 字符设备驱动程序 • int scull_open(struct inode *inode,struct file *filp) { • MOD_INC_USE_COUNT; // 增加该模块的用户数目 • printk("This chrdev is in open\n"); • return 0; • } • int scull_write(struct inode *inode,struct file *filp,const char *buffer,int count) { 设备管理实验 _ 34 成都信息工程学院 徐虹
if(count < 0) • return –EINVAL; • if(scull.usage || scull.new_msg) • return –EBUSY; • scull.usage = 1; • kfree(scull.data); • data = kmalloc(sizeof(char) *(count+1),GFP_KERNEL); • if(!scull.data) { • return ENOMEM; • } • copy_from_user(scull.data,buffer,count + 1); • scull.usage = 0; • scull.new_msg = 1; • return count; } 设备管理实验 _ 35 成都信息工程学院 徐虹
int scull_read(struct inode *inode,struct file *filp,char *buffer,int count){ • int length; • if(count < 0) • return –EINVAL; • if(scull.usage) • return –EBUSY; • scull.usage = 1; • if(scull.data == 0) • return 0; • length = strlen(scull.data); 设备管理实验 _ 36 成都信息工程学院 徐虹
if(length < count) • count = length; • copy_to_user(buf,scull.data,count + 1); • scull.new_msg = 0; • scull.usage = 0; • return count; • } 设备管理实验 _ 37 成都信息工程学院 徐虹
#include <linux/ioctl.h> • #define SCULL_MAJOR 0 • #define SCULL_MAGIC SCULL_MAJOR • #define SCULL_RESET _IO(SCULL_MAGIC,0) // 重置数据 • #define SCULL_QUERY_NEW_MSG _IO(SCULL_MAGIC,1) // 检查新的消息 • #define SCULL_QUERY_MSG_LENGTH _IO(SCULL_MAGIC,2) // 获取消息长度 • #define IOC_NEW_MSG 1 • static int usage,new_msg; // 控制标志 • static char *data; • int scull_ioctl(struct inode *inode,struct file *filp,unsigned long int cmd,unsigned long arg) { 设备管理实验 _ 38 成都信息工程学院 徐虹
int ret=0; • switch(cmd) { • case SCULL_RESET: • kfree(data); • data = NULL; • usage = 0; • new_msg = 0; • break; • case SCULL_QUERY_NEW_MSG: • if(new_msg) • return IOC_NEW_MSG; • break; • case SCULL_QUERY_MSG_LENGTH: • if(data == NULL){ return 0; } 设备管理实验 _ 39 成都信息工程学院 徐虹
else { • return strlen(data); • } • break; • default: • return –ENOTTY; • } • return ret; • } 设备管理实验 _ 40 成都信息工程学院 徐虹
void scull_release(struct inode *inode,struct file *filp) { • MOD_DEC_USE_COUNT; // 该模块的用户数目减1 • printk("This chrdev is in release\n"); • return 0; • #ifdef DEBUG • printk("scull_release(%p,%p)\n",inode,filp); • #endif • } #mknod /dev/chrdev c major minor #cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}") 设备管理实验 _ 41 成都信息工程学院 徐虹
#include <stdio.h> • #include <sys/types.h> • #include <sys/stat.h> • #include <sys/ioctl.h> • #include <stdlib.h> • #include <string.h> • #include <fcntl.h> • #include <unistd.h> • #include <errno.h> • #include "chardev.h" // 定义字符设备 • void write_proc(void); • void read_proc(void); 设备管理实验 _ 42 成都信息工程学院 徐虹
main(int argc,char **argv) { • if(argc == 1) { • puts("syntax: testprog[write|read]\n"); • exit(0); • } • if(!strcmp(argv[1], "write")) • { write_porc(); } • else if(!strcmp(argv[1],"read")) • { read_proc(); } • else { • puts("testprog: invalid command!\n"); • } • return 0; • } 设备管理实验 _ 43 成都信息工程学院 徐虹
void write_proc() { • int fd,len,quit = 0; • char buf[100]; • fd = open("/dev/chrdev",O_WRONLY); • if(fd <= 0) { • printf("Error opening device for writing!\n"); • exit(1); • } • while(!quit) { • printf("\n Please write into:"); • gets(buf); • if(!strcmp(buf,"exit")) • quit = 1; 设备管理实验 _ 44 成都信息工程学院 徐虹
while(ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) • usleep(100); • len = write(fd,buf,strlen(buf)); • if(len < 0) { • printf("Error writing to device!\n"); • close(fd); • exit(1); • } • printf("\n There are %d bytes written to device!\n",len); • } • close(fd); • } 设备管理实验 _ 45 成都信息工程学院 徐虹
void read_proc() { • int fd,len,quit = 0; • char *buf = NULL; • fd=open("/dev/chrdev",O_RDONLY); • if(fd < 0) { • printf("Error opening device for reading!\n""); • exit(1); • } • while(!quit) { • printf("\n Please read out:"); • while(!ioctl(fd,DYNCHAR_QUERY_NEW_MSG)) • usleep(100); // 获取消息长度 设备管理实验 _ 46 成都信息工程学院 徐虹
len = ioctl(fd,DYNCHAR_QUERY_MSG_LENGTH,NULL); • if(len) { • if(buf != NULL) • free(buf); • buf = malloc(sizeof(char) * (len+1)); • len = read(fd,buf,len); • if(len < 0) { • printf("Error reading from device!\n"); } • else { • if(!strcmp(buf,"exit") { • ioctl(fd,DYNCHAR_RESET); // 复位 • quit = 1; • } 设备管理实验 _ 47 成都信息工程学院 徐虹
else • printf("%s\n",buf); } • } • } • free(buf); • close(fd);} • #ifndef _DYNCHAR_DEVICE_H #define _DYNCHAR_DEVICE_H • #include <linux/ioctl.h> #define DYNCHAR_MAJOR 42 • #define DYNCHAR_MAGIC DYNCHAR_MAJOR • #define DYNCHAR_RESET _IO(DYNCHAR_MAGIC,0) // 重置数据 • #define DYNCHAR_QUERY_NEW_MSG _IO(DYNCHAR_MAGIC,1) // 检查新的消息 • #define DYNCHAR_QUERY_MSG_LENGTH _IO(DYNCHAR_MAGIC,2) // 获到消息长度 • #define IOC_NEW_MSG 1 • #endif 设备管理实验 _ 48 成都信息工程学院 徐虹
7.5.2 块设备驱动程序 • typedef struct Sbull_Dev { • void * *data; • int quantum; // 当前容量的大小 • int qset; // 当前数组的大小 • unsigned long size; • unsigned int new_msg; • unsigned int usage; // 当块设备正使用时加锁 • unsigned int access_key; // 由sbulluid和sbullpriv使用的存取字段 • struct Sbull_Dev *next; // 指向下一块设备 • }; • extern struct sbull_dev *sbull; // 块设备信息 设备管理实验 _ 49 成都信息工程学院 徐虹
int sbull_open(struct inode *inode,struct file *filp) • { • int num = MINOR(inode -> i_rdev); • if(num >= sbull -> size) • return –ENODEV; • sbull -> size = sbull -> size + num; • if(!sbull -> usage) { • check_disk_change(inode -> i_rdev); • if(!* (sbull -> data)) • return –ENOMEM; • } • sbull -> usage++; • MOD_INC_USE_COUNT; • return 0;} 设备管理实验 _ 50 成都信息工程学院 徐虹