第二部分  实 验 指 导
This presentation is the property of its rightful owner.
Sponsored Links
1 / 55

第二部分 实 验 指 导 PowerPoint PPT Presentation


  • 137 Views
  • Uploaded on
  • Presentation posted in: General

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

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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


3308979

第二部分 实 验 指 导

第二部分 实 验 指 导

7.1 实验目的

7.2 准备知识

  • 7.2.1 设备驱动程序简介

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


3308979

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

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


3308979

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

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

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


3308979

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

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


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

图7-3 blk_dev_struct

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


3308979

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


3308979

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

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


3308979

7.3 实验内容

  • 7.3.1 字符类型设备的驱动程序

  • 7.3.2 块类型设备的驱动程序

    7.4 实验指导

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

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


3308979

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


3308979

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


3308979

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


3308979

  • NULL, // flush,冲掉缓冲区的数据,对字符设备无用

  • scull_release, // release,字符设备的释放操作

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

  • // 尚未写到磁盘的数据写出

  • NULL, // fasync,改变字符设备行为

  • NULL, // check media change,检查自上次操作后,介质(软盘和

  • // CD-ROM)是否更换

  • NULL, // revalidate,若更换了介质,则更新信息

  • NULL // lock,锁定字符设备操作

  • };

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


3308979

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


3308979

  • 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

图7-5 scull_open()流程图

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


7 6 scull write

图7-6 scull_write()的流程图

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


7 7 scull read

图7-7 scull_read()流程图

  • #mknod /dev/chrdev c major minor

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


7 8 scull ioctl

图7-8 scull_ioctl()流程图

  • 图注:SRT:SCULL_RESET SQNM:SCULL_QUERY_NEW_MSG SQML:SCULL_QUERY_MSG_LENGTH

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


7 9 scull release

图7-9 scull_release()流程图

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


3308979

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

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

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


7 4 2

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


3308979

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


3308979

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

  • // 尚未写到磁盘的数据写出去。为内核函数

  • NULL, // fasync,改变块设备行为

  • sbull_check_media_change, // check media change,检查自上次操作后,介质

  • // (软盘和CD-ROM)是否更换

  • NULL, // revalidate,若更换了介质,则更新信息

  • NULL // lock,锁定块设备操作

  • };

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


3308979

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


3308979

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


3308979

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


3308979

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


3308979

  • #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

图7-11 sbull_open()流程图

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


7 12 sbull ioctl

图7-12 sbull_ioctl()流程图

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


3308979

  • 图注

  • 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

图7-13 sbull_release()流程图

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


3308979

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


3308979

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


3308979

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


3308979

  • if(length < count)

  • count = length;

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

  • scull.new_msg = 0;

  • scull.usage = 0;

  • return count;

  • }

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


3308979

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


3308979

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


3308979

  • else {

  • return strlen(data);

  • }

  • break;

  • default:

  • return –ENOTTY;

  • }

  • return ret;

  • }

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


3308979

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


3308979

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


3308979

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


3308979

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


3308979

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


3308979

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


3308979

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


3308979

  • 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

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


3308979

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


3308979

  • #include <linux/ioctl.h>

  • #include <linux/fs.h> // BLKGETSIZE、BLKFLSBUF和BLKRRPART在此头文件中定义

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

  • {

  • int err;

  • struct hd_geometry *geo = (struct hd_geometry *)arg;

  • PDEBUG("ioctl 0x%x 0x%lx\n",cmd,arg);

  • switch(cmd) {

  • case BLKGETSIZE:

  • // 返回以扇区表示的设备大小。

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


3308979

  • if(!arg)

  • return –EINVAL; // NULL 指针:设备不可用

  • err=verify_area(VERIFY_WRITE,(long*)arg, sizeof(long));

  • if(err)

  • return err;

  • put_user(1024*sbull_sizes[MINOR(inode -> i_rdev)

  • /sbull_hardsects[MINOR(inode -> i_rdev)],

  • (long *)arg);

  • return 0;

  • case BLKFLSBUF: // 冲缓冲区

  • if(!suser())

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

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


3308979

  • fsync_dev(inode -> i_rdev);

  • return 0;

  • case BLKRRPART: // 重读分区表:不能做

  • return –EINVAL;

  • RO_IOCTLS(inode -> i_rdev,arg);

  • // 默认的RO operations操作,宏RO_IOCTLS(kdev_t dev,

  • // unsigned long where)在blk.h中定义

  • }

  • return –EINVAL; // 未知命令

  • }

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


3308979

  • void sbull_release(struct inode *inode,struct file *filp)

  • {

  • sbull -> size = sbull -> size + MINOR(inode -> i_rdev);

  • sbull -> usage--;

  • MOD_DEC_USE_COUNT;

  • printk("This blkdev is in release!\n");

  • return 0;

  • #ifdef DEBUG

  • printk("sbull_release(%p,%p)\n",inode,filp);

  • #endif

  • }

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


3308979

  • extern struct request *CURRENT;

  • void sbull_request(void)

  • {

  • while(1) {

  • INIT_REQUEST();

  • printk("request %p: cmd %i sec %li (nr.%li),next %p\n",

  • CURRENT,

  • CURRENT -> cmd,

  • CURRENT -> sector,

  • CURRENT -> current_nr_sectors);

  • end_request(1); // 请求成功

  • }

  • }

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


  • Login