日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

【操作系统实验】设备驱动(Linux环境下)

發(fā)布時(shí)間:2023/12/10 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【操作系统实验】设备驱动(Linux环境下) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【實(shí)驗(yàn)?zāi)康摹?/strong>
實(shí)驗(yàn)?zāi)康?#xff1a;熟悉Linux下驅(qū)動(dòng)程序設(shè)計(jì)
?????編譯內(nèi)核
實(shí)驗(yàn)要求:在Linux系統(tǒng)下,編譯內(nèi)核,并在該內(nèi)核下完成實(shí)驗(yàn);
?????自主設(shè)計(jì)驅(qū)動(dòng)程序,完成驅(qū)動(dòng)程序的安裝

【實(shí)驗(yàn)內(nèi)容】
1.編譯內(nèi)核,構(gòu)造內(nèi)核源碼樹(shù)
2.ubantu14.04 32位下編寫(xiě)hello world程序以及加載驅(qū)動(dòng)
3.ubantu14.04第二個(gè)memory驅(qū)動(dòng)程序
4.ubantu14.04第三個(gè)使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng)
5.Linux設(shè)備驅(qū)動(dòng)中的阻塞與非阻塞I/O

【實(shí)驗(yàn)環(huán)境】(含主要設(shè)計(jì)設(shè)備、器材、軟件等)
Pc電腦一臺(tái)

【實(shí)驗(yàn)步驟、過(guò)程】(含原理圖、流程圖、關(guān)鍵代碼,或?qū)嶒?yàn)過(guò)程中的記錄、數(shù)據(jù)等)

1.編譯內(nèi)核,構(gòu)造內(nèi)核源碼樹(shù)(itc-centos)

(1)編譯指令
①指導(dǎo)書(shū)上的指令

uname -r //查看內(nèi)核版本 ls /usr/src //輸出:linux-headers-3.13.0-32,linux-headers-3.13.0-32-generic apt-cache search linux-source //查看一下可一下載的源碼包 sudo apt-get install linux-source-3.13.0 //下載完成后,在/usr/sr下會(huì)有壓縮包,然后解壓 make oldconfig //開(kāi)始配置內(nèi)核 選擇最快的原版的配置方式,menuconfig , xconfig也行 make bzImage //執(zhí)行結(jié)束后,可以看到在當(dāng)前目錄下生成了一個(gè)新的文件: vmlinux make modules和make modules_install

②自己查閱的資料
??以一個(gè)不是root用戶的戶口,創(chuàng)建一個(gè)以~/rpmbuild為基礎(chǔ)的目錄樹(shù):

[user@host] $ mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SPRMS} [user@host] $ echo ‘%_topdir % (echo $HOME) / rpmbuild’ > ~/.rpmmacros

??以一個(gè)不是root用戶的普通戶口,執(zhí)行以下指令來(lái)安裝源代碼組件:

[user@host] $ rpm -i http://vault.centos.org/7.7.1908/updates/Source/SPackages /kernel-3.10.0-1062.9.1.e17.src.rpm 2>&1 | grep -v exist

解壓及預(yù)備源代碼文件:

[user@host] $ cd ~/rpmbuild/SPECS [user@host SPECS] $ rpmbuild -bp --target = $(uname -m) kernel.spec

??其中,$(uname -m)這條命令,可以將目標(biāo)結(jié)構(gòu)設(shè)置為你現(xiàn)有的內(nèi)核的結(jié)構(gòu),一般來(lái)說(shuō)這是可行的,因?yàn)槎鄶?shù)人需要以i686或x86_64為目標(biāo)。

(2)編譯過(guò)程截圖

????????????圖1 編譯內(nèi)核過(guò)程

(3)編譯過(guò)程注意事項(xiàng)
??如果這一步中沒(méi)有建立內(nèi)核源碼樹(shù),按下面步驟進(jìn)行,雖然能夠生成hello.ko,但執(zhí)行sudo insmod hello.ko后,執(zhí)行l(wèi)smod會(huì)沒(méi)反應(yīng),導(dǎo)致系統(tǒng)報(bào)告問(wèn)題,會(huì)導(dǎo)致下次開(kāi)機(jī)或重啟時(shí)有問(wèn)題,若啟動(dòng)不了,可以進(jìn)入recovery模式,執(zhí)行fsck,開(kāi)機(jī)時(shí)做嵌入式linux開(kāi)發(fā)一般在PC機(jī)上編譯好了,下到板子上去運(yùn)行,板子上的linux內(nèi)核和PC機(jī)上的linux版本很多時(shí)候都是不一樣的,比如pc機(jī)上的是linux2.6,板子上的是linux3.1,這個(gè)時(shí)候就要下linux3.1的內(nèi)核,用它編譯的驅(qū)動(dòng)模塊在板子上才能加載上,不然會(huì)出錯(cuò)。
??在執(zhí)行最后一條指令make modules和make modules_install時(shí),執(zhí)行結(jié)束之后,會(huì)在/lib/modules下生成新的目錄/lib/modules/3.13.0-32-generic/,但若由于主機(jī)本身內(nèi)核版本就為3.13.0-32-generic,所以/lib/modules/3.13.0-32-generic/本身就存在,此時(shí)這兩條指令make modules和make modules_install就不需要執(zhí)行了。

2.ubantu14.04 32位下編寫(xiě)hello world程序以及加載驅(qū)動(dòng)

(1)實(shí)驗(yàn)步驟
①編寫(xiě)hello. c程序并寫(xiě)Makefile文件;
②之后通過(guò)make指令,生成hello.ko等其他文件;
③執(zhí)行sudo insmod hello.ko,在lsmod即可驗(yàn)證模塊是否已裝載,最后rmmod移出模塊;
④通過(guò)cat /var/log/syslog | grep world來(lái)觀察其輸出。

(2)實(shí)驗(yàn)過(guò)程截圖

??????????圖2 hello.c代碼

??????????圖3 對(duì)于Makefile內(nèi)容

??????????圖4 執(zhí)行make指令

??????????圖5 執(zhí)行l(wèi)smod指令

??????????圖6 運(yùn)行結(jié)果

(3)實(shí)驗(yàn)過(guò)程注意事項(xiàng)

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

??這句是Makefile的規(guī)則:這里的$(MAKE)就相當(dāng)于make,-C 選項(xiàng)的作用是指將當(dāng)前工作目錄轉(zhuǎn)移到你所指定的位置。“M=”選項(xiàng)的作用是,當(dāng)用戶需要以某個(gè)內(nèi)核為基礎(chǔ)編譯一個(gè)外部模塊的話,需要在make modules 命令中加入“M=dir”,程序會(huì)自動(dòng)到你所指定的dir目錄中查找模塊源碼,將其編譯,生成ko文件。
??一定要實(shí)現(xiàn)查看電腦Linux的內(nèi)核版本,機(jī)房不同電腦的內(nèi)核版本可能不一樣,要事先查好之后并且在Makefile文件中版本號(hào)要改。
??用printk,內(nèi)核會(huì)根據(jù)日志級(jí)別,可能把消息打印到當(dāng)前控制臺(tái)上,這個(gè)控制臺(tái)通常是一個(gè)字符模式的終端、一個(gè)串口打印機(jī)或是一個(gè)并口打印機(jī)。這些消息正常輸出的前提是──日志輸出級(jí)別小于console_loglevel(在內(nèi)核中數(shù)字越小優(yōu)先級(jí)越高)。

3.ubantu14.04第二個(gè)memory驅(qū)動(dòng)程序

(1)實(shí)驗(yàn)步驟
①編寫(xiě)c程序并寫(xiě)Makefile文件;
②根據(jù)設(shè)備號(hào),從內(nèi)核空間將數(shù)據(jù)取出,寫(xiě)入相應(yīng)的設(shè)備空間內(nèi);
③通過(guò)程序創(chuàng)建主從設(shè)備,將數(shù)據(jù)寫(xiě)入;
④再通過(guò)模塊功能讀出,觀察其輸出。

(2)實(shí)驗(yàn)過(guò)程截圖
①到包含Makefile和mydm1.c的目錄下執(zhí)行make,生成mydm1.ko;
②執(zhí)行sudo insmod mydm1.ko;
③驗(yàn)證:lsmod | grep mydm1
④需要?jiǎng)?chuàng)建一個(gè)文件(該設(shè)備文件用于和設(shè)備驅(qū)動(dòng)操作)
mknod /dev/fgj c 224 0 c代表字符設(shè)備 224為主設(shè)備號(hào),0為從設(shè)備號(hào)
⑤ gcc test.c

主要代碼如下:
1.mydm1.c:

int devMajor = 224; // 主設(shè)備號(hào)用于內(nèi)核把文件和它的驅(qū)動(dòng)鏈接在一起static unsigned char simple_inc = 0; static unsigned char demoBuffer[256]; // 用于存儲(chǔ)該驅(qū)動(dòng)的數(shù)據(jù)int simple_open( struct inode *inode, struct file *filp ) {printk(" : open Success!\n");if(simple_inc>0){return -1;}simple_inc = simple_inc + 1;return 0; }int simple_release(struct inode *inode, struct file *filp) {printk(": release Success%d!\n",devMajor);simple_inc = simple_inc - 1;return 0; }ssize_t simple_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos) {printk(": read Success%d!\n", devMajor);/*把數(shù)據(jù)復(fù)制到應(yīng)用程序空間從內(nèi)核空間demoBuffer中拷貝數(shù)據(jù)到用戶空間buf中*/if( copy_to_user(buf,demoBuffer,count) ) {count=-EFAULT;}return count; }ssize_t simple_write(struct file *filp, const char __user *buf,size_t count,loff_t *f_pos) {printk(": write Success%d!\n",devMajor);/*把數(shù)據(jù)復(fù)制到內(nèi)核空間*/if(copy_from_user(demoBuffer + *f_pos,buf,count)){count=-EFAULT;}return count; }struct file_operations simple_fops={ .owner=THIS_MODULE, .read=simple_read, .write=simple_write, .open=simple_open, .release=simple_release, };/******************************************************* MODULEROUTINE *******************************************************/ static void __exit simple_cleanup_module(void) {unregister_chrdev(devMajor,"mydm1");printk(" : simple_cleanup_module!\n");//return 0; }static int __init simple_init_module(void) {int ret;//根據(jù)設(shè)備號(hào)與設(shè)備名注冊(cè)字符設(shè)備,此處設(shè)備名不一定要與模塊名相同,/*register_chrdev函數(shù)用于在內(nèi)核空間,把驅(qū)動(dòng)和/dev下設(shè)備文件鏈接在一起*/ret=register_chrdev( devMajor,"mydm1",&simple_fops);if(ret<0){printk(" : Unabletoregistercharacterdevice%d!\n",devMajor);return ret;}else{printk(" : Success%d!\n",devMajor );}return 0; }module_init(simple_init_module); module_exit(simple_cleanup_module);

2.Makefile:

obj-m := mydm1.o #KERNELDIR := /lib/modules/3.16.61-32-generic/build KERNELDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean:rm *.o *.ko *.mod.c *.order *.symvers

3.test.c:

#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h>void main(void) {int fd;int i;char data[256];int retval;fd = open("/dev/fgj",O_RDWR);if(fd==-1){perror("erroropen\n");exit(-1);}printf("open/dev/fgjsuccessfully\n");//寫(xiě)數(shù)據(jù)retval = write(fd,"fgj",3);if(retval==-1){perror("writeerror\n");exit(-1);}printf("write successfully\n");//讀數(shù)據(jù)retval=read(fd,data,3);if(retval==-1){perror("readerror\n");exit(-1);}data[retval]=0;printf("readsuccessfully:%s\n",data);//關(guān)閉設(shè)備close(fd); }

運(yùn)行結(jié)果如下:

?? ?? ?? ?? ??圖7 執(zhí)行make命令

?? ?? ?? ?? ??圖8 執(zhí)行結(jié)果

(3)實(shí)驗(yàn)過(guò)程注意事項(xiàng)
①保證/dev/fgj有讀寫(xiě)權(quán)限 chmod 666 /dev/fgj;
②printk打印的消息若滅有在控制臺(tái)上顯示,可以同構(gòu)dmesg命令或查看系統(tǒng)的日志文件cat /var/log/syslog命令看到;
③驅(qū)動(dòng)編譯:gcc必須用系統(tǒng)自帶的版本,gcc -v查看當(dāng)前版本, 否則insmod后,lsmod會(huì)沒(méi)反應(yīng),系統(tǒng)直接卡死,注銷也不行,只能重啟;

4.ubantu14.04第三個(gè)使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng)

(1)實(shí)驗(yàn)步驟
①編寫(xiě)c程序并寫(xiě)Makefile文件;
②執(zhí)行:make ,然后sudo insmod globalmem.ko;
③驗(yàn)證:lsmod 可以看到該模塊,mknod /dev/globalmem c 354 0, echo ‘good nihao’ > /dev/globalmem, cat /dev/globalmem可以看到輸出good nihao;

(2)實(shí)驗(yàn)過(guò)程截圖
代碼如下:

#define GLOBALMEM_SIZE 0X1000 /*全局內(nèi)存最大4KB*/ #define MEM_CLEAR 0x1 /*清零全局內(nèi)存*/ #define GLOBALMEM_MAJOR 354static int globalmem_major = GLOBALMEM_MAJOR;/*預(yù)設(shè)的globalmem的主設(shè)備號(hào)*//*globalmem的設(shè)備結(jié)構(gòu)體:包含了對(duì)應(yīng)于globalmem字符設(shè)備的cdev 和 使用內(nèi)存mem[GLOBALMEM_SIZE]*/ struct globalmem_dev {struct cdev cdev; //cdev結(jié)構(gòu)體unsigned char mem[GLOBALMEM_SIZE]; //全局內(nèi)存 };struct globalmem_dev *globalmem_devp; //設(shè)備結(jié)構(gòu)體指針/*文件打開(kāi)函數(shù)*/ int globalmem_open(struct inode *inode,struct file *filp) {filp->private_data = globalmem_devp; //將設(shè)備結(jié)構(gòu)體指針賦值給文件私有數(shù)據(jù)指針return 0; }/*文件釋放函數(shù)*/ int globalmem_release(struct inode *inode,struct file *filp) {return 0; }/*設(shè)備控制函數(shù):ioctl()函數(shù)接受的MEM_CLEAR命令,這個(gè)命令將全局內(nèi)存的有效數(shù)據(jù)長(zhǎng)度清零,對(duì)于設(shè)備不支持的命令,ioctl()函數(shù)應(yīng)該返回-EINVAL*/ static long globalmem_ioctl( /*struct inode *inodep,*/struct file *filp,unsigned int cmd,unsigned long arg) {struct globalmem_dev *dev = filp->private_data; //獲得設(shè)備結(jié)構(gòu)體指針switch(cmd){case MEM_CLEAR:memset(dev->mem,0,GLOBALMEM_SIZE);printk(KERN_INFO"globalmem is set to zero\n");break;default:return -EINVAL;}return 0; }/*讀函數(shù):讀寫(xiě)函數(shù)主要是讓設(shè)備結(jié)構(gòu)體的mem[]數(shù)組與用戶空間交互數(shù)據(jù),并隨著訪問(wèn)字節(jié)數(shù)變更返回用戶的文件讀寫(xiě)偏移位置*/ static ssize_t globalmem_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos ) {unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct globalmem_dev *dev = filp->private_data; //獲得設(shè)備結(jié)構(gòu)體指針if(p >= GLOBALMEM_SIZE) //分析和獲取有效的寫(xiě)長(zhǎng)度{return count ? -ENXIO:0;}if(count > GLOBALMEM_SIZE - p){count = GLOBALMEM_SIZE - p;}if(copy_to_user(buf,(void *)(dev->mem+p),count)) //內(nèi)核空間->用戶空間{ret = -EFAULT;}else{*ppos += count;ret = count;printk(KERN_INFO"read %d bytes(s) from %ld\n",count,p);}return ret; }/*寫(xiě)函數(shù)*/ static ssize_t globalmem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos) {unsigned long p = *ppos;unsigned int count = size;int ret = 0;struct globalmem_dev *dev = filp->private_data;if(p >= GLOBALMEM_SIZE) //分析和獲取有效的寫(xiě)長(zhǎng)度{return count? -ENXIO:0;}if(count > GLOBALMEM_SIZE - p){count = GLOBALMEM_SIZE - p;}if(copy_from_user(dev->mem + p,buf,count)) // 用戶空間->內(nèi)核空間{ret = -EFAULT;}else{*ppos =+ count;ret = count;printk(KERN_INFO"written %d bytes(s) from %ld\n",count,p);}return ret; }/*seek文件定位函數(shù):seek()函數(shù)對(duì)文件定位的起始地址可以是文件開(kāi)頭(SEEK_SET,0)、當(dāng)前位置(SEEK_CUR,1)、文件尾(SEEK_END,2)*/ static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig) {loff_t ret = 0;switch(orig){case 0: //相對(duì)文件開(kāi)始位置偏移if(offset <0 ){ret = -EINVAL;break;}if((unsigned int )offset > GLOBALMEM_SIZE){ret = - EINVAL;break;}filp->f_pos = (unsigned int)offset;ret = filp->f_pos;break;case 1: //相對(duì)文件當(dāng)前位置偏移if((filp->f_pos + offset) > GLOBALMEM_SIZE){ret = -EINVAL;break;}if((filp->f_pos + offset)<0){ret = -EINVAL;break;}filp->f_pos +=offset;ret = filp->f_pos;break;default:ret = -EINVAL;break; }return ret; }/*文件操作結(jié)構(gòu)體*/ static const struct file_operations globalmem_fops= {.owner = THIS_MODULE,.llseek = globalmem_llseek,.read = globalmem_read,.write = globalmem_write, // .ioctl = globalmem_ioctl,.unlocked_ioctl = globalmem_ioctl,.open = globalmem_open,.release = globalmem_release, };/*初始化并注冊(cè)cdev*/ static void globalmem_setup_cdev(struct globalmem_dev *dev,int index) {int err,devno = MKDEV(globalmem_major,index);cdev_init(&dev->cdev,&globalmem_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &globalmem_fops;err = cdev_add(&dev->cdev,devno,1);if(err){printk(KERN_NOTICE"Error %d adding LED%d",err,index);} }/*設(shè)備驅(qū)動(dòng)模塊加載函數(shù)*/ static int __init globalmem_init(void) {int result;dev_t devno = MKDEV(globalmem_major,0);if(globalmem_major) //申請(qǐng)?jiān)O(shè)備號(hào){result = register_chrdev_region(devno,1,"globalmem");}else //動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào){result = alloc_chrdev_region(&devno,0,1,"globalmem");globalmem_major = MAJOR(devno);}if(result < 0){return result;}globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL); //申請(qǐng)?jiān)O(shè)備結(jié)構(gòu)體的內(nèi)存if(!globalmem_devp){result = -ENOMEM;goto fail_malloc;}memset(globalmem_devp,0,sizeof(struct globalmem_dev));globalmem_setup_cdev(globalmem_devp,0);return 0;fail_malloc:unregister_chrdev_region(devno,1);return result; }/*模塊卸載函數(shù)*/ static void __exit globalmem_exit(void) {cdev_del(&globalmem_devp->cdev); //注銷cdevkfree(globalmem_devp); //釋放設(shè)備結(jié)構(gòu)體內(nèi)存unregister_chrdev_region(MKDEV(globalmem_major,0),1); //釋放設(shè)備號(hào) }MODULE_AUTHOR("Song Baohua"); MODULE_LICENSE("Dual BSD/GPL");module_param(globalmem_major,int,S_IRUGO);module_init(globalmem_init); module_exit(globalmem_exit);

2.Makefile:

KERNELDIR := /lib/modules/$(shell uname -r)/build obj-m := globalmem.o modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean:make -C $(KERNELDIR) M=`pwd` modules clean rm -rf modules.order

??????????圖9 執(zhí)行make指令

??????????圖10 執(zhí)行l(wèi)smod指令

??????????圖11 驗(yàn)證結(jié)果

5.Linux設(shè)備驅(qū)動(dòng)中的阻塞與非阻塞I/O

(1)實(shí)驗(yàn)內(nèi)容
??阻塞和非阻塞I/O是設(shè)備訪問(wèn)的兩種不同模式,驅(qū)動(dòng)程序可以靈活的支持用戶空間對(duì)設(shè)備的這兩種訪問(wèn)方式。本例子講述了這兩者的區(qū)別并實(shí)現(xiàn)I/O的等待隊(duì)列機(jī)制,并進(jìn)行了用戶空間的驗(yàn)證。

基本概念:
1> 阻塞操作是指在執(zhí)行設(shè)備操作時(shí),若不能獲得資源,則掛起進(jìn)程直到滿足操作條件后再進(jìn)行操作。被掛起的進(jìn) 程進(jìn)入休眠,被從調(diào)度器移走,直到條件滿足。
2> 非阻塞操作在不能進(jìn)行設(shè)備操作時(shí),并不掛起,它或者放棄,或者不停地查詢,直到可以進(jìn)行操作。非阻塞應(yīng)用程序通常使用select系統(tǒng)調(diào)用查詢是否可以對(duì)設(shè)備進(jìn)行無(wú)阻塞的訪問(wèn)最終會(huì)引發(fā)設(shè)備驅(qū)動(dòng)中poll函數(shù)執(zhí)行。

(2)實(shí)驗(yàn)過(guò)程截圖
主要代碼如下;

/*globalfifo設(shè)備結(jié)構(gòu)體*/struct globalfifo_dev {struct cdev cdev; //cdev結(jié)構(gòu)體unsigned int current_len; //fifo有效數(shù)據(jù)長(zhǎng)度unsigned char mem[GLOBALFIFO_SIZE];struct semaphore sem; //并發(fā)控制用的信號(hào)量wait_queue_head_t r_wait; //阻塞讀用的等待隊(duì)列 內(nèi)核雙向循環(huán)鏈表 都可以為頭wait_queue_head_t w_wait; //阻塞寫(xiě)用的等待隊(duì)列頭 }; /*globalfifo讀函數(shù)*/ static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {int ret;struct globalfifo_dev *dev = filp->private_data;DECLARE_WAITQUEUE(wait, current);down(&dev->sem); /*獲得信號(hào)量*/add_wait_queue(&dev->r_wait, &wait); /*加入讀等待隊(duì)列頭 到內(nèi)核*//*等待FIFO非空*/if(dev->current_len == 0){if(filp->f_flags & O_NONBLOCK){ /*如果進(jìn)程為 非阻塞打開(kāi) 設(shè)備文件*/ret = -EAGAIN;goto out;}__set_current_state(TASK_INTERRUPTIBLE); /*改變進(jìn)程狀態(tài)為睡眠*/up(&dev->sem); /*釋放信號(hào)量*/schedule(); /*調(diào)度其他進(jìn)程執(zhí)行*/if(signal_pending(current)){/*如果是因?yàn)樾盘?hào)喚醒*/ret = -ERESTARTSYS;goto out2;}down(&dev->sem);} 通過(guò)Up和down獲取信號(hào)量以及釋放信號(hào)量。 /*ioctl 設(shè)備控制函數(shù)*/ static long globalfifo_ioctl(/*struct inode *inodep,*/struct file *filp, unsigned int cmd, unsigned long arg) {struct globalfifo_dev *dev = filp->private_data;/*獲得設(shè)備結(jié)構(gòu)體指針*/switch(cmd){case FIFO_CLEAR:down(&dev->sem); /*獲得信號(hào)量*/dev->current_len = 0;memset(dev->mem,0,GLOBALFIFO_SIZE);up(&dev->sem); /*釋放信號(hào)量*/printk(KERN_INFO"globalfifo is set to zero");break;default:return -EINVAL;}return 0; } 加入輪詢方式,判斷FIFO空和滿。 /*在驅(qū)動(dòng)中的增加輪詢操作*/ static unsigned int globalfifo_poll(struct file *filp, poll_table *wait) {unsigned int mask = 0;struct globalfifo_dev *dev = filp->private_data;/*獲得設(shè)備結(jié)構(gòu)體指針*/down(&dev->sem);poll_wait(filp, &dev->r_wait, wait);poll_wait(filp, &dev->w_wait, wait);/*fifo非空*/if(dev->current_len != 0){mask |= POLLIN | POLLRDNORM; /*標(biāo)示數(shù)據(jù)可以獲得*/}/*fifo 非滿*/if(dev->current_len != GLOBALFIFO_SIZE){mask |= POLLOUT | POLLWRNORM ; /*標(biāo)示數(shù)據(jù)可以寫(xiě)入*/}up(&dev->sem);return mask; /*返回驅(qū)動(dòng)是否可讀 或可寫(xiě)的 狀態(tài)*/ }

????????????圖12 運(yùn)行結(jié)果1

????????????圖13 運(yùn)行結(jié)果2

【實(shí)驗(yàn)結(jié)果或總結(jié)】(對(duì)實(shí)驗(yàn)結(jié)果進(jìn)行相應(yīng)分析,或總結(jié)實(shí)驗(yàn)的心得體會(huì),并提出實(shí)驗(yàn)的改進(jìn)意見(jiàn))

1.在編寫(xiě) hello world 程序以及加載驅(qū)動(dòng)的時(shí)候,module_init(hello_init); module_exit(hello_exit); 這兩個(gè)是函數(shù)的入口地址和出口地址。同時(shí)Makefile文件記得更改KERNELDIR := /lib/modules/3.16.61-32-generic/build的版本號(hào),包括32也需要改成自己電腦相匹配的。

2.$(MAKE) -C (KERNELDIR)M=(KERNELDIR) M=(KERNELDIR)M=(PWD) modules 這句是 Makefile 的規(guī)則:這里的$(MAKE)就相當(dāng)于 make,-C 選項(xiàng)的作用是指將當(dāng)前,工作目錄轉(zhuǎn)移到你所指定的位置。“M=”選項(xiàng)的作用是,當(dāng)用戶需要以某個(gè)內(nèi)核為基礎(chǔ)。

3.通過(guò)查閱相關(guān)資料,我明白了Makefile文件的作用,它相當(dāng)于是覆寫(xiě)了make指令,讓make指令的指向目標(biāo)變?yōu)楫?dāng)前目錄下的文件了。而sudo的作用在于,普通用戶在安裝時(shí),是沒(méi)有權(quán)限的,因此要通過(guò)sudo來(lái)獲取超級(jí)用戶權(quán)限。

4.在第二個(gè)memory驅(qū)動(dòng)程序中 ret=register_chrdev( devMajor,“mydm1”,&simple_fops); register_chrdev 函數(shù)用于在內(nèi)核空間,把驅(qū)動(dòng) 和/dev 下設(shè)備文件鏈接在一起,mydm1.c :read()函數(shù),將內(nèi)核空間中的數(shù)據(jù)復(fù)制到用戶空間中,從而讀取出數(shù)據(jù)。在驗(yàn)證過(guò)程中,首先是在內(nèi)核的設(shè)備區(qū)創(chuàng)建了對(duì)應(yīng)程序的設(shè)備區(qū),再通過(guò)測(cè)試程序往里面寫(xiě)入數(shù)據(jù),最后再在用戶空間中讀出來(lái)。Write()函數(shù)則相反。

5.Makefile 里的KERNELDIR := /lib/modules/$(shell uname -r)/build 則是用腳本的方法獲取 uname -r 即可不用對(duì)代碼進(jìn)行修改,動(dòng)態(tài)獲取內(nèi)核的版本信息。

6.使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng) :用到了內(nèi)核區(qū)的字符設(shè)備,將輸入的字符存儲(chǔ)到全局內(nèi)存區(qū)域,再?gòu)挠脩艨臻g中訪問(wèn)這個(gè)區(qū)域,獲取到其中的數(shù)據(jù)。struct globalmem_dev { struct cdev cdev; //cdev 結(jié)構(gòu)體 unsigned char mem[GLOBALMEM_SIZE]; //全局內(nèi)存 }; globalmem 的設(shè)備結(jié)構(gòu)體:包含了對(duì)應(yīng)于 globalmem 字符設(shè)備的 cdev 和 使用內(nèi)存 mem[GLOBALMEM_SIZE],其他與上一個(gè)實(shí)驗(yàn)類似。增加了一個(gè)ioctl函數(shù):ioctl()函數(shù)接受的 MEM_CLEAR 命令,這個(gè)命令將全局內(nèi)存的有效數(shù)據(jù)長(zhǎng)度 清零,對(duì)于設(shè)備不支持的命令,ioctl()函數(shù)應(yīng)該返回-EINVAL。,mknod /dev/globalmem c 354 0, echo ‘good nihao’ > /dev/globalmem, cat /dev/globalmem 即可驗(yàn)證輸出 ,cat是讀出,echo是寫(xiě)入。

??最后感謝倪福川老師以及各位同學(xué)給我的幫助,通過(guò)一學(xué)期對(duì)于操作系統(tǒng)理論和實(shí)驗(yàn)的學(xué)習(xí),讓我對(duì)操作系統(tǒng)加深了理解,在自己原有知識(shí)的基礎(chǔ)上得到了更深層次的感悟,我也會(huì)把在操作系統(tǒng)課程之中學(xué)到的知識(shí)應(yīng)用到今后的學(xué)習(xí)生活中去,思考問(wèn)題也要更細(xì)致,要學(xué)會(huì)從底層去思考問(wèn)題的起源,并學(xué)會(huì)從底層去解決問(wèn)題。最后再一次感謝倪福川老師這一學(xué)期以來(lái)的諄諄教誨,我定當(dāng)銘記于心,認(rèn)真完成后續(xù)課程的學(xué)習(xí)。

總結(jié)

以上是生活随笔為你收集整理的【操作系统实验】设备驱动(Linux环境下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。