1 / 55

第二部分 实 验 指 导

第二部分 实 验 指 导. 第二部分 实 验 指 导 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>

lilka
Download Presentation

第二部分 实 验 指 导

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第二部分 实 验 指 导 第二部分 实 验 指 导 7.1 实验目的 7.2 准备知识 • 7.2.1 设备驱动程序简介 设备管理实验 _ 1 成都信息工程学院 徐虹

  2. 图7-1 字符(块)设备、驱动程序和接口 设备管理实验 _ 2 成都信息工程学院 徐虹

  3. 7.2.2 设备驱动程序与外界的接口 • 7.2.3 设备驱动程序的组织结构 设备管理实验 _ 3 成都信息工程学院 徐虹

  4. 图7-2 设备驱动程序与外界的接口 设备管理实验 _ 4 成都信息工程学院 徐虹

  5. 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 成都信息工程学院 徐虹

  6. 图7-3 blk_dev_struct 设备管理实验 _ 6 成都信息工程学院 徐虹

  7. 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 成都信息工程学院 徐虹

  8. 图7-4 块设备驱动程序的注册 设备管理实验 _ 8 成都信息工程学院 徐虹

  9. 7.3 实验内容 • 7.3.1 字符类型设备的驱动程序 • 7.3.2 块类型设备的驱动程序 7.4 实验指导 • 7.4.1 字符类型设备驱动程序 设备管理实验 _ 9 成都信息工程学院 徐虹

  10. 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 成都信息工程学院 徐虹

  11. 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 成都信息工程学院 徐虹

  12. 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 成都信息工程学院 徐虹

  13. NULL, // flush,冲掉缓冲区的数据,对字符设备无用 • scull_release, // release,字符设备的释放操作 • NULL, // fsync,同步内存与磁盘上的数据状态,把输出缓冲区里 • // 尚未写到磁盘的数据写出 • NULL, // fasync,改变字符设备行为 • NULL, // check media change,检查自上次操作后,介质(软盘和 • // CD-ROM)是否更换 • NULL, // revalidate,若更换了介质,则更新信息 • NULL // lock,锁定字符设备操作 • }; 设备管理实验 _ 13 成都信息工程学院 徐虹

  14. #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 成都信息工程学院 徐虹

  15. 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 成都信息工程学院 徐虹

  16. 图7-5 scull_open()流程图 设备管理实验 _ 16 成都信息工程学院 徐虹

  17. 图7-6 scull_write()的流程图 设备管理实验 _ 17 成都信息工程学院 徐虹

  18. 图7-7 scull_read()流程图 • #mknod /dev/chrdev c major minor 设备管理实验 _ 18 成都信息工程学院 徐虹

  19. 图7-8 scull_ioctl()流程图 • 图注:SRT:SCULL_RESET SQNM:SCULL_QUERY_NEW_MSG SQML:SCULL_QUERY_MSG_LENGTH 设备管理实验 _ 19 成都信息工程学院 徐虹

  20. 图7-9 scull_release()流程图 设备管理实验 _ 20 成都信息工程学院 徐虹

  21. 图7-10 字符设备驱动程序的测试函数流程图 • #cat /proc/devices | awk "\\$2==\ "chrdev\"{ print\\$1}" 设备管理实验 _ 21 成都信息工程学院 徐虹

  22. 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 成都信息工程学院 徐虹

  23. 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 成都信息工程学院 徐虹

  24. block_fsync, // 同步内存与磁盘上的数据状态,把输出缓冲区里 • // 尚未写到磁盘的数据写出去。为内核函数 • NULL, // fasync,改变块设备行为 • sbull_check_media_change, // check media change,检查自上次操作后,介质 • // (软盘和CD-ROM)是否更换 • NULL, // revalidate,若更换了介质,则更新信息 • NULL // lock,锁定块设备操作 • }; 设备管理实验 _ 24 成都信息工程学院 徐虹

  25. 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 成都信息工程学院 徐虹

  26. #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 成都信息工程学院 徐虹

  27. 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 成都信息工程学院 徐虹

  28. 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 成都信息工程学院 徐虹

  29. #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 成都信息工程学院 徐虹

  30. 图7-11 sbull_open()流程图 设备管理实验 _ 30 成都信息工程学院 徐虹

  31. 图7-12 sbull_ioctl()流程图 设备管理实验 _ 31 成都信息工程学院 徐虹

  32. 图注 • 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 成都信息工程学院 徐虹

  33. 图7-13 sbull_release()流程图 设备管理实验 _ 33 成都信息工程学院 徐虹

  34. 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 成都信息工程学院 徐虹

  35. 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 成都信息工程学院 徐虹

  36. 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 成都信息工程学院 徐虹

  37. if(length < count) • count = length; • copy_to_user(buf,scull.data,count + 1); • scull.new_msg = 0; • scull.usage = 0; • return count; • } 设备管理实验 _ 37 成都信息工程学院 徐虹

  38. #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 成都信息工程学院 徐虹

  39. 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 成都信息工程学院 徐虹

  40. else { • return strlen(data); • } • break; • default: • return –ENOTTY; • } • return ret; • } 设备管理实验 _ 40 成都信息工程学院 徐虹

  41. 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 成都信息工程学院 徐虹

  42. #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 成都信息工程学院 徐虹

  43. 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 成都信息工程学院 徐虹

  44. 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 成都信息工程学院 徐虹

  45. 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 成都信息工程学院 徐虹

  46. 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 成都信息工程学院 徐虹

  47. 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 成都信息工程学院 徐虹

  48. 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 成都信息工程学院 徐虹

  49. 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 成都信息工程学院 徐虹

  50. 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 成都信息工程学院 徐虹

More Related