作業系統實驗六
阿新 • • 發佈:2021-12-15
Linux字元裝置驅動程式
實驗內容:
使用記憶體模擬字元裝置,編寫一個簡單字元型別裝置驅動程式(要求該驅動程式支援字元的讀寫操作和字元裝置的開啟與釋放),然後採用make命令對該程式進行編譯生成模組,並將該模組動態插入到Linux核心。在此基礎上再編寫一個測試程式來測試所編寫的字元裝置驅動程式
實驗過程:
(1)字元裝置驅動程式原始碼
#include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <linux/version.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(3,3,0) #include <asm/switch_to.h> #else #include <asm/system.h> #endif #include <asm/uaccess.h> #include "memdev.h" static mem_major = MEMDEV_MAJOR; module_param(mem_major, int, S_IRUGO); struct mem_dev *mem_devp; struct cdev cdev; int mem_open(struct inode *inode, struct file *filp) { struct mem_dev *dev; int num = MINOR(inode->i_rdev); if (num >= MEMDEV_NR_DEVS) return -ENODEV; dev = &mem_devp[num]; filp->private_data = dev; return 0; } int mem_release(struct inode *inode, struct file *filp) { return 0; } static ssize_t mem_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 mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_to_user(buf, (void*)(dev->data + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count; printk(KERN_INFO "read %d bytes(s) from %d\n", count, p); } return ret; } static ssize_t mem_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 mem_dev *dev = filp->private_data; if (p >= MEMDEV_SIZE) return 0; if (count > MEMDEV_SIZE - p) count = MEMDEV_SIZE - p; if (copy_from_user(dev->data + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count; printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); } return ret; } static loff_t mem_llseek(struct file *filp, loff_t offset, int whence) { loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = offset; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + offset; break; case 2: /* SEEK_END */ newpos = MEMDEV_SIZE -1 + offset; break; default: /* can't happen */ return -EINVAL; } if ((newpos<0) || (newpos>MEMDEV_SIZE)) return -EINVAL; filp->f_pos = newpos; return newpos; } static const struct file_operations mem_fops = { .owner = THIS_MODULE, .llseek = mem_llseek, .read = mem_read, .write = mem_write, .open = mem_open, .release = mem_release, }; static int memdev_init(void) { int result; int i; dev_t devno = MKDEV(mem_major, 0); if (mem_major) result = register_chrdev_region(devno, 2, "memdev"); else { result = alloc_chrdev_region(&devno, 0, 2, "memdev"); mem_major = MAJOR(devno); } if (result < 0) return result; cdev_init(&cdev, &mem_fops); cdev.owner = THIS_MODULE; cdev.ops = &mem_fops; cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS); mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL); if (!mem_devp) { result = - ENOMEM; goto fail_malloc; } memset(mem_devp, 0, sizeof(struct mem_dev)); for (i=0; i < MEMDEV_NR_DEVS; i++) { mem_devp[i].size = MEMDEV_SIZE; mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL); memset(mem_devp[i].data, 0, MEMDEV_SIZE); } return 0; fail_malloc: unregister_chrdev_region(devno, 1); return result; } static void memdev_exit(void) { cdev_del(&cdev); kfree(mem_devp); unregister_chrdev_region(MKDEV(mem_major, 0), 2); } MODULE_LICENSE("GPL"); module_init(memdev_init); module_exit(memdev_exit);
(2)makefile檔案內容
ifneq ($(KERNELRELEASE),)
obj-m:=memdev.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko
endif
(3)編譯生成字元裝置驅動程式模組及模組安裝
uname -r 命令來檢視當前核心的版本號
sudo make -C /lib/modules/3.5.0-17-generic/build M=/home/lenovo/zhang modules
cat /proc/devices
sudo insmod ./memdev.ko
(4)測試程式
原始碼:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <linux/i2c.h> #include <linux/fcntl.h> int main() { int fd; char buf[]="this is a example for character devices driver!"; char buf_read[4096]; if((fd=open("/dev/memdev",O_RDWR))==-1) printf("open memdev WRONG \n"); else printf("open memdev SUCCESS!\n"); printf("buf is %s\n",buf); write(fd,buf,sizeof(buf)); lseek(fd,0,SEEK_SET); read(fd,buf_read,sizeof(buf)); printf("buf_read is %s\n",buf_read); return 0; }
ubuntu中內容
在/dev/目錄下建立與該驅動程式相對應的檔案節點
sudo mknod /dev/memdev c 260 0
改變檔案節點的許可權
sudo chmod 777 /dev/memdev
測試驅動程式
編譯memdevtest.c,然後測試執行
解除安裝程式
sudo rmmod ./memdev.ko
刪除檔案結點
sudo rm /dev/memdev
再檢視
cat /proc/devices
實驗截圖: