linux字符设备驱动课程设计报告

合集下载

实验五嵌入式Linux设备驱动开发试验

实验五嵌入式Linux设备驱动开发试验

合肥学院嵌入式系统设计实验报告(2013- 2014第二学期)专业: 11自动化卓越班实验项目:实验五 Linux设备驱动开发实验实验时间: 2014 年 5 月 20实验成员:、_____指导老师:干开峰电子信息与电气工程系2014年4月制一、实验目的1、熟悉嵌入式Linux下设备驱动程序的设计的进本方法。

2、掌握字符设备驱动程序的设计和调试方法。

3、熟悉设备驱动的测试和使用。

二、实验内容本实验要求学生熟悉嵌入式Linux下设备驱动程序的设计的基本方法,掌握字符设备驱动程序的设计和调试方法,完成LED驱动程序的编写和调试,并在目标开发板上测试。

三、实验步骤1、在linux-2.6.32.2/arch/arm/plat-s3c24x文件夹中打开gpio.c文件,查看s3c2410_gpio_cfgpin函数,void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function){void __iomem *base = S3C24XX_GPIO_BASE(pin);unsigned long mask;unsigned long con;unsigned long flags;if (pin < S3C2410_GPIO_BANKB) {mask = 1 << S3C2410_GPIO_OFFSET(pin);} else {mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;}switch (function) {case S3C2410_GPIO_LEAVE:mask = 0;function = 0;break;case S3C2410_GPIO_INPUT:case S3C2410_GPIO_OUTPUT:case S3C2410_GPIO_SFN2:case S3C2410_GPIO_SFN3:if (pin < S3C2410_GPIO_BANKB) {function -= 1;function &= 1;function <<= S3C2410_GPIO_OFFSET(pin);} else {function &= 3;function <<= S3C2410_GPIO_OFFSET(pin)*2;}}/* modify the specified register wwith IRQs off */local_irq_save(flags);con = __raw_readl(base + 0x00);con &= ~mask;con |= function;__raw_writel(con, base + 0x00);local_irq_restore(flags);}2、在drivers/char目录下,我们建立一个驱动程序文件mini2440_leds.c,内容如下:#include <linux/miscdevice.h>#include <linux/delay.h>#include <asm/irq.h>#include <mach/regs-gpio.h>#include <mach/hardware.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/string.h>#include <linux/list.h>#include <linux/pci.h>#include <linux/gpio.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <asm/unistd.h>#define DEVICE_NAME "leds"//设备名(/dev/leds)//LED对应的GPIO端口列表static unsigned long led_table [] = {S3C2410_GPB(5),S3C2410_GPB(6),S3C2410_GPB(7),S3C2410_GPB(8),};//LED对应端口将要输出的状态列表static unsigned int led_cfg_table [] = {S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,S3C2410_GPIO_OUTPUT,};/*ioctl函数的实现* 在应用/用户层将通过ioctl函数向内核传递参数,以控制LED的输出状态*/static int sbc2440_leds_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg){switch(cmd) {case 0:case 1:if (arg > 4) {return -EINVAL;}//根据应用/用户层传递来的参数(取反),通过s3c2410_gpio_setpin函数设置LED对应的端口寄存器,s3c2410_gpio_setpin(led_table[arg], !cmd);return 0;default:return -EINVAL;}}/** 设备函数操作集,在此只有ioctl函数,通常还有read, write, open, close等,因为本LED驱动在下面已经* 注册为misc设备,因此也可以不用open/close*/static struct file_operations dev_fops = {.owner = THIS_MODULE,.ioctl = sbc2440_leds_ioctl,};/** 把LED驱动注册为MISC设备*/static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR, //动态设备号.name = DEVICE_NAME,.fops = &dev_fops,};/** 设备初始化*/static int __init dev_init(void){int ret;int i;for (i = 0; i < 4; i++) {//设置LED对应的端口寄存器为输出(OUTPUT)s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);//设置LED对应的端口寄存器为低电平输出,在模块加载结束后,四个LED应该是全部都是发光状态s3c2410_gpio_setpin(led_table[i], 0);}ret = misc_register(&misc); //注册设备printk (DEVICE_NAME"\tinitialized\n"); //打印初始化信息return ret;}static void __exit dev_exit(void){misc_deregister(&misc);}module_init(dev_init); //模块初始化,仅当使用insmod/podprobe命令加载时有用,如果设备不是通过模块方式加载,此处将不会被调用module_exit(dev_exit);//卸载模块,当该设备通过模块方式加载后,可以通过rmmod命令卸载,将调用此函数MODULE_LICENSE("GPL"); //版权信息MODULE_AUTHOR("FriendlyARM Inc.");//开发者信息3、我们添加LED设备的内核配置选项,打开drivers/char/Kconfig文件,添加如下部分内容:config LEDS_MINI2440tristate "LED Support for Mini2440 GPIO LEDs"depends on MACH_MINI2440default y if MACH_MINI2440helpThis option enables support for LEDs connected to GPIO lines on Mini2440 boards.4、把对应的驱动目标文件加入内核中,打开linux-2.6.32.2/drivers/char/Makefile文件,添加如下部分内容:obj-$(CONFIG_LEDS_MINI2440) += mini2440_leds.o这样,我们就在内核中添加做好了LED驱动。

Linux及Linux设备驱动程序设计

Linux及Linux设备驱动程序设计

目录正文 ..................................................................................................... 错误!未定义书签。

1. 主要功能 (1)2. 功能模块 (1)2.1. 字符设备驱动程序的基本数据结构 (2)2.1.1. file_operations结构 (2)2.1.2. inode结构 ............................................................ 错误!未定义书签。

2.1.3. file结构 (3)2.2. 字符设备驱动程序的初始化和清除函数 (4)2.2.1. 初始化函数scull_init( )的实现 (4)2.2.2. 清除函数scull_exit( )的实现 (4)2.3. 字符设备驱动程序的入口点 (5)2.3.1. open( )操作的实现 (5)2.3.2. release( )操作的实现 (6)2.3.3. read( )操作的实现 (6)2.3.4. write( )操作的实现 (6)2.3.5. llseek( )操作的实现 (7)2.4. 设备驱动程序的编译、装卸和卸载 (7)设备驱动程序的编译方式 (7)2.4.1. 设备驱动模块的编译 (8)2.4.2. 设备驱动模块的装载 (8)2.4.3. 设备驱动模块的卸载 (9)3. 程序流程图 (10)4. 程序调试 (11)4.1. 用vi编辑器编写程序 (11)4.2. 头文件无法找到 (12)4.3. 程序运行结果 (13)5. 总结 (14)6. 附录: (14)1.主要功能因为Linux系统将所有的外围设备都高度抽象成一些字节序列,并且以文件形式来表示这些设备。

所以Linux设备驱动程序被集成在内核中,构成了处理或操作硬件控制器的软件模块。

linux课课程设计字符设备驱动

linux课课程设计字符设备驱动

linux课课程设计字符设备驱动一、教学目标本章节的教学目标是使学生掌握Linux系统中字符设备驱动的基本原理和编程方法。

通过本章节的学习,学生将能够:1.理解字符设备驱动的概念和作用;2.掌握字符设备驱动的原理和编程方法;3.能够编写简单的字符设备驱动程序。

二、教学内容本章节的教学内容主要包括:1.字符设备驱动的概念和作用;2.字符设备驱动的原理和编程方法;3.字符设备驱动的实例分析。

具体的教学大纲如下:1.字符设备驱动的概念和作用:介绍字符设备驱动的基本概念,解释其在Linux系统中的作用;2.字符设备驱动的原理:讲解字符设备驱动的工作原理,包括驱动程序的加载、设备文件的创建和使用;3.字符设备驱动的编程方法:介绍编写字符设备驱动程序的基本步骤和方法,包括文件操作、缓冲区管理和中断处理;4.字符设备驱动的实例分析:分析实际的字符设备驱动程序代码,让学生了解和掌握驱动程序的具体实现方法。

三、教学方法为了达到本章节的教学目标,将采用以下教学方法:1.讲授法:讲解字符设备驱动的基本概念、原理和编程方法;2.案例分析法:分析实际的字符设备驱动程序代码,让学生了解和掌握驱动程序的具体实现方法;3.实验法:让学生动手编写和调试字符设备驱动程序,巩固所学的知识和技能。

四、教学资源为了支持本章节的教学内容和教学方法的实施,将准备以下教学资源:1.教材:《Linux设备驱动程序设计与实现》;2.参考书:《Linux内核设计与实现》;3.多媒体资料:教学PPT、视频教程等;4.实验设备:计算机、开发板等。

五、教学评估为了全面、客观地评估学生在Linux字符设备驱动课程中的学习成果,将采用以下评估方式:1.平时表现:通过课堂参与、提问和讨论等方式评估学生的学习态度和理解程度;2.作业:布置相关的编程练习和理论作业,评估学生对知识的掌握和应用能力;3.考试:进行期中和期末考试,以评估学生对课程内容的整体理解和掌握程度。

Linux课程设计实验报告

Linux课程设计实验报告

pdata->activity_mode = !pdata->activity_mode; gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata->pbar)); gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata->pbar),0.00); gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata->pbar), "0.00"); gtk_container_add (GTK_CONTAINER (align), pdata->pbar); gtk_widget_show (pdata->pbar); /* 加一个定时器(timer), 以更新进度条 的值 */ pdata->timer = gtk_timeout_add (100, progress_timeout, pdata); separator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0); gtk_widget_show (separator); /* 行数、 列数、 同质性(homogeneous) */ table = gtk_table_new (2, 2, FALSE); gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); gtk_widget_show (table);
3. 通过系统调用实现文件拷贝
5
a.程序说明: 要在 linux 下实现系统调用,首先修改内核中的三个文件,分别是 unistd.h,sys.c 和 syscalltable.s(这个是 2.6 版本和 2.4 版本的区别所在,2.4 版本要改的文件是 entry.s), 然后需要重新编译内核,具体步骤如下: Make clean Make bzImage Make modules Make modules_install Make install 最后一步最为关键,2.6 版本不需要手动修改 grub,只需要执行 make install 就会自动 修改 grub,然后只要在启动时选择新内核即可,完全不需要手工操作. 此外还需要一个测试文件,文件拷贝的代码当然是原先写在内核里,这里是 sys.c 文 件.编译后的内核下通过系统调用同样实现了程序一文件拷贝的效果. b.程序源码 测试程序: while(!feof(f1)) #include <stdio.h> { #include <stdlib.h> #include <string.h> s=fgetc(f1); if(s==EOF) break; fputc(s,f2); int mysyscall(char *f1,char *f2) } { sys_close(f1); sys_close(f2); printk("Copy complete!!\n"); f1=sys_open(f1,"r"); } f2=sys_open(f2,"w"); int s=0; Sys.c 里的文件拷贝代码:

实验二:字符设备驱动实验

实验二:字符设备驱动实验

实验二:字符设备驱动实验一、实验目的通过本实验的学习,了解Linux操作系统中的字符设备驱动程序结构,并能编写简单的字符设备的驱动程序以及对所编写的设备驱动程序进行测试,最终了解Linux操作系统如何管理字符设备。

二、准备知识字符设备驱动程序主要包括初始化字符设备、字符设备的I/O调用和中断服务程序。

在字符设备驱动程序的file_operations结构中,需要定义字符设备的基本入口点。

open()函数;release()函数read()函数write()函数ioctl()函数select()函数。

另外,注册字符设备驱动程序的函数为register_chrdev()。

register_chrdev() 原型如下:int register_chrdev(unsigned int major, //主设备号const char *name, //设备名称struct file_operations *ops); //指向设备操作函数指针其中major是设备驱动程序向系统申请的主设备号。

如果major为0,则系统为该驱动程序动态分配一个空闲的主设备号。

name是设备名称,ops是指向设备操作函数的指针。

注销字符设备驱动程序的函数是unregister_chrdev(),原型如下:int unregister_chrdev(unsigned int major,const char *name);字符设备注册后,必须在文件系统中为其创建一个设备文件。

该设备文件可以在/dev目录中创建,每个设备文件代表一个具体的设备。

使用mknod命令来创建设备文件。

创建设备文件时需要使用设备的主设备号和从设备号作为参数。

阅读教材相关章节知识,了解字符设备的驱动程序结构。

三、实验内容根据教材提供的实例。

编写一个简单的字符设备驱动程序。

要求该字符设备包括open()、write()、read()、ioctl()和release()五个基本操作,并编写一个测试程序来测试所编写的字符设备驱动程序。

字符设备驱动实验报告(3篇)

字符设备驱动实验报告(3篇)

第1篇一、实验背景与目的随着计算机技术的飞速发展,操作系统对硬件设备的支持越来越丰富。

设备驱动程序作为操作系统与硬件之间的桥梁,扮演着至关重要的角色。

本实验旨在通过学习Linux字符设备驱动的开发,加深对设备驱动程序的理解,提高实践能力。

二、实验环境与工具1. 操作系统:Linux Ubuntu 20.042. 编程语言:C3. 开发工具:gcc、make4. 驱动框架:Linux内核三、实验内容本实验主要完成以下内容:1. 字符设备驱动程序的基本框架2. 字符设备的打开、读取、写入和关闭操作3. 字符设备驱动的注册与注销4. 字符设备驱动的用户空间交互四、实验步骤1. 创建设备文件首先,我们需要在`/dev`目录下创建一个名为`mychar`的字符设备文件。

可以使用以下命令:```bashmknod /dev/mychar c 123 0```其中,`123`是主设备号,`0`是次设备号。

2. 编写字符设备驱动程序创建一个名为`mychar.c`的文件,并编写以下代码:```cinclude <linux/module.h>include <linux/fs.h>include <linux/uaccess.h>static int major = 123; // 设备号static int device_open(struct inode inode, struct file filp);static int device_release(struct inode inode, struct file filp);static ssize_t device_read(struct file filp, char __user buf, size_t count, loff_t pos);static ssize_t device_write(struct file filp, const char __user buf, size_t count, loff_t pos);static struct file_operations fops = {.open = device_open,.release = device_release,.read = device_read,.write = device_write,};static int __init mychar_init(void) {major = register_chrdev(0, "mychar", &fops);if (major < 0) {printk(KERN_ALERT "mychar: can't get major number\n");return major;}printk(KERN_INFO "mychar: registered correctly with major number %d\n", major);return 0;}static void __exit mychar_exit(void) {unregister_chrdev(major, "mychar");printk(KERN_INFO "mychar: Goodbye from the LKM!\n");}static int device_open(struct inode inode, struct file filp) {printk(KERN_INFO "mychar: Device has been opened\n");return 0;}static int device_release(struct inode inode, struct file filp) {printk(KERN_INFO "mychar: Device has been closed\n");return 0;}static ssize_t device_read(struct file filp, char __user buf, size_t count, loff_t pos) {printk(KERN_INFO "mychar: Device has been read\n");return count;}static ssize_t device_write(struct file filp, const char __user buf, size_t count, loff_t pos) {printk(KERN_INFO "mychar: Device has been written\n"); return count;}module_init(mychar_init);module_exit(mychar_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("A simple character device driver");```保存文件,并使用以下命令编译:```bashmake```3. 加载字符设备驱动程序将编译生成的`mychar.ko`文件加载到内核中:```bashinsmod mychar.ko```4. 测试字符设备驱动程序使用以下命令查看`/dev/mychar`设备文件:```bashls -l /dev/mychar```使用`cat`命令测试读取和写入操作:```bashcat /dev/mycharecho "Hello, world!" > /dev/mychar```观察系统日志,确认驱动程序的打开、读取、写入和关闭操作。

基于Linux的字符设备驱动程序的设计

基于Linux的字符设备驱动程序的设计

基于Linux的字符设备驱动程序的设计1 选题意义驱动程序在 Linux 内核里扮演着特殊的角色. 它们是截然不同的"黑盒子", 使硬件的特殊的一部分响应定义好的内部编程接口.它们完全隐藏了设备工作的细节. 用户的活动通过一套标准化的调用来进行,这些调用与特别的驱动是独立的; 设备驱动的角色就是将这些调用映射到作用于实际硬件的和设备相关的操作上. 这个编程接口是这样, 驱动可以与内核的其他部分分开建立, 并在需要的时候在运行时"插入". 这种模块化使得 Linux 驱动易写, 以致于目前有几百个驱动可用.尽管编写设备代码并不一定比编写应用程序更困难,但它需要掌握一些新函数库,并考虑一些新问题,而这些问题是在应用程序空间里不曾遇到的。

在应用程序空间写程序,内核能够为犯的一些错误提供一张安全网,但当我们工作在内核空间时,这张安全网已不复存在。

因为内核代码对计算机有绝对的控制权,它能够阻止其他任何进程的执行,所以编写的设备代码绝对小心不能滥用这种权利。

在 Linux 设备驱动中,字符设备驱动较为基础,所以本次实验设计一个简单的字符设备驱动程序,然后通过模块机制加载该驱动,并通过一个测试程序来检验驱动设计的正确与否,并对出现的问题进行调试解决。

2 技术路线模块实际上是一种目标对象文件(后缀名为ko ),没有链接,不能独立运行,但是其代码可以在运行时链接到系统中作为内核的一部分运行或从内核中取下,从而可以动态扩充内核的功能。

模块有一个入口(init_module())和一个出口(exit_module())函数,分别是模块加载和卸载时执行的操作,加载模块使用insmod命令,卸载使用rmmod命令。

字符设备以字节为单位进行数据处理,一般不适用缓存。

大多数字符设备仅仅是数据通道,只能按照顺序读写。

主设备号表示设备对应的驱动程序,次设备号用来区分具体设备的实例。

LINUX为文件和设备提供一致的用户接口,对用户来说,设备文件与普通文件并无区别,设备文件也可以挂接到任何需要的地方。

linux设备驱动程序之简单字符设备驱动

linux设备驱动程序之简单字符设备驱动

linux设备驱动程序之简单字符设备驱动⼀、linux系统将设备分为3类:字符设备、块设备、⽹络设备。

使⽤驱动程序:1、字符设备:是指只能⼀个字节⼀个字节读写的设备,不能随机读取设备内存中的某⼀数据,读取数据需要按照先后数据。

字符设备是⾯向流的设备,常见的字符设备有⿏标、键盘、串⼝、控制台和LED设备等。

2、块设备:是指可以从设备的任意位置读取⼀定长度数据的设备。

块设备包括硬盘、磁盘、U盘和SD卡等。

每⼀个字符设备或块设备都在/dev⽬录下对应⼀个设备⽂件。

linux⽤户程序通过设备⽂件(或称设备节点)来使⽤驱动程序操作字符设备和块设备。

⼆、字符设备驱动程序基础:1、主设备号和次设备号(⼆者⼀起为设备号): ⼀个字符设备或块设备都有⼀个主设备号和⼀个次设备号。

主设备号⽤来标识与设备⽂件相连的驱动程序,⽤来反映设备类型。

次设备号被驱动程序⽤来辨别操作的是哪个设备,⽤来区分同类型的设备。

linux内核中,设备号⽤dev_t来描述,2.6.28中定义如下: typedef u_long dev_t; 在32位机中是4个字节,⾼12位表⽰主设备号,低12位表⽰次设备号。

可以使⽤下列宏从dev_t中获得主次设备号: 也可以使⽤下列宏通过主次设备号⽣成dev_t: MAJOR(dev_t dev); MKDEV(int major,int minor);MINOR(dev_t dev);View Code//宏定义:#define MINORBITS 20#define MINORMASK ((1U << MINORBITS) - 1)#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))2、分配设备号(两种⽅法):(1)静态申请:int register_chrdev_region(dev_t from, unsigned count, const char *name);View Code/*** register_chrdev_region() - register a range of device numbers* @from: the first in the desired range of device numbers; must include* the major number.* @count: the number of consecutive device numbers required* @name: the name of the device or driver.** Return value is zero on success, a negative error code on failure.*/(2)动态分配:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);View Codeint alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);/*** alloc_chrdev_region() - register a range of char device numbers* @dev: output parameter for first assigned number* @baseminor: first of the requested range of minor numbers* @count: the number of minor numbers required* @name: the name of the associated device or driver** Allocates a range of char device numbers. The major number will be* chosen dynamically, and returned (along with the first minor number)* in @dev. Returns zero or a negative error code.*/注销设备号:void unregister_chrdev_region(dev_t from, unsigned count);创建设备⽂件:利⽤cat /proc/devices查看申请到的设备名,设备号。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、课程设计目的Linux 系统的开源性使其在嵌入式系统的开发中得到了越来越广泛的应用,但其本身并没有对种类繁多的硬件设备都提供现成的驱动程序,特别是由于工程应用中的灵活性,其驱动程序更是难以统一,这时就需开发一套适合于自己产品的设备驱动。

对用户而言,设备驱动程序隐藏了设备的具体细节,对各种不同设备提供了一致的接口,一般来说是把设备映射为一个特殊的设备文件,用户程序可以像对其它文件一样对此设备文件进行操作。

通过这次课程设计可以了解linux的模块机制,懂得如何加载模块和卸载模块,进一步熟悉模块的相关操作。

加深对驱动程序定义和设计的了解,了解linux驱动的编写过程,提高自己的动手能力。

二、课程设计内容与要求字符设备驱动程序1、设计目的:掌握设备驱动程序的编写、编译和装载、卸载方法,了解设备文件的创建,并知道如何编写测试程序测试自己的驱动程序是否能够正常工作2、设计要求:1) 编写一个简单的字符设备驱动程序,该字符设备包括打开、读、写、I\O控制与释放五个基本操作。

2) 编写一个测试程序,测试字符设备驱动程序的正确性。

3) 要求在实验报告中列出Linux内核的版本与内核模块加载过程。

三、系统分析与设计1、系统分析系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。

设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作。

设备驱动程序是内核的一部分,它完成以下的功能:1、对设备初始化和释放;2、把数据从内核传送到硬件和从硬件读取数据;3、读取应用程序传送给设备文件的数据和回送应用程序请求的数据;4、检测和处理设备出现的错误。

字符设备提供给应用程序的是一个流控制接口,主要包括op e n、clo s e(或r ele as e)、r e ad、w r i t e、i o c t l、p o l l和m m a p等。

在系统中添加一个字符设备驱动程序,实际上就是给上述操作添加对应的代码。

对于字符设备和块设备,L i n u x内核对这些操作进行了统一的抽象,把它们定义在结构体fi le_operations中。

2、系统设计:、模块设计:数据结构说明字符设备驱动主要应用了三种数据结构:①file_operations结构,这是设备驱动程序所提供的一组用一个结构向系统进行说明的入口点;②file结构,主要用于与文件系统对应的设备驱动程序。

代表一个打开的文件,它由内核在open时创建,并传递给在该文件上进行操作的所有函数,直到碰到最后的close函数。

在文件的所有实例都被关闭之后,内核会释放这个数据结构;③ inode结构,提供了关于特殊设备文件/dev/mydev的信息。

各个结构的定义如下:(1)file_operations结构:static const struct file_operations my_fops ={.owner = THIS_MODULE,.llseek = my_llseek,.read = my_read,.write = my_write,.open = my_open,.release = my_release,.unlocked_ioctl = ioctl,};(2)file结构:1)读static ssize_t my_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)2)写static ssize_t my_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)3)seek文件定位static loff_t my_llseek(struct file *filp, loff_t offset, int whence)4)I\O控制static int ioctl (struct file *file, unsigned int cmd, unsigned long arg)(3)inode结构:1)打开int my_open(struct inode *inode, struct file *filp) 2)释放int my_release(struct inode *inode, struct file *filp)、算法流程图:四、系统测试与调试分析系统测试启动超级管理员模式并输入密码命令:sudo su对源程序进行编译命令:make加载驱动程序并查看命令:insmod 和lsmod显示主设备号命令:cat /proc/devices 创建节点并查看命令:mknod /dev/lydev 55 0和cd /dev编译测试程序命令:gcc –o t运行测试函数命令:./t进行打开设备操作命令:1进行写操作并输入hello 命令:2进行读操作命令:3进行I/O控制命令:4进行释放设备操作命令:5进行退出操作命令:6卸载驱动程序命令:rmmod lydev查看日志命令:dmesg删除节点并查看命令:rm lydev和ls调试分析最开始的时候没有启用sudo模式,导致很多命令不能执行,启用模式的时候需要输入密码,但是输入密码的时候是不显示东西的以为出错,查阅资料之后才知道是应有的现象。

程序测试一遍之后再次测试很多命令不能执行,原因是第一次测试之后产生的各种文件没有删除,再次测试会显示已存在。

有一次测试程序,不能卸载驱动,用lsmod查看有两个进程使用,后来强制关机才能正常使用,原因不明,以后要加强学习。

五、程序清单1.主程序#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <linux/>#include <asm/>#include <asm/>#include <asm/>#include ""#define SCULL_IOC_MAGIC 'k' #define SCULL_IOCRESET_IO(SCULL_IOC_MAGIC, 0)#define SCULL_IOCSQUANTUM_IOW(SCULL_IOC_MAGIC, 1, int) #define SCULL_IOCSQSET_IOW(SCULL_IOC_MAGIC, 2, int) #define SCULL_IOCTQUANTUM_IO(SCULL_IOC_MAGIC, 3)#define SCULL_IOCTQSET_IO(SCULL_IOC_MAGIC, 4)#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)#define SCULL_IOCGQSET_IOR(SCULL_IOC_MAGIC, 6, int)#define SCULL_IOCQQUANTUM_IO(SCULL_IOC_MAGIC, 7)#define SCULL_IOCQQSET_IO(SCULL_IOC_MAGIC, 8)#define SCULL_IOCXQUANTUM_IOWR(SCULL_IOC_MAGIC, 9, int)#define SCULL_IOCXQSET_IOWR(SCULL_IOC_MAGIC,10, int)#define SCULL_IOCHQUANTUM_IO(SCULL_IOC_MAGIC, 11)#define SCULL_IOCHQSET_IO(SCULL_IOC_MAGIC, 12)#define SCULL_IOC_MAXNR 14static int ly_major = 55;module_param(ly_major, int, S_IRUGO); struct ly_dev *ly_devp; /*设备结构体指针*/struct cdev cdev;static int ioctl (struct file *file, unsigned int cmd, unsigned long arg); /*文件打开函数*/int ly_open(struct inode *inode,structfile *filp){struct ly_dev *dev;/*获取次设备号*/int num = MINOR(inode->i_rdev);if (num >= MYDEV_NR_DEVS)return -ENODEV;dev = &ly_devp[num];/*将设备描述结构指针赋值给文件私有数据指针*/filp->private_data = dev;return 0;}/*文件释放函数*/int ly_release(struct inode *inode, struct file *filp){return 0;}/*读函数*/static ssize_t ly_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 ly_dev *dev =filp->private_data; /*获得设备结构体指针*//*判断读位置是否有效*/if (p >= MYDEV_SIZE)return 0;if (count > MYDEV_SIZE - p)count = MYDEV_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 %lx\n", count, p);}return ret;}/*写函数*/static ssize_t ly_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 ly_dev *dev =filp->private_data; /*获得设备结构体指针*//*分析和获取有效的写长度*/if (p >= MYDEV_SIZE)return 0;if (count > MYDEV_SIZE - p)count = MYDEV_SIZE - p;/*从用户空间写入数据*/if (copy_from_user(dev->data + p, buf, count))ret = - EFAULT;else{*ppos += count;ret = count;printk(KERN_INFO "written %dbytes(s) from %lx\n", count, p);}return ret;}/*I\O控制函数*/static int ioctl (struct file *file, unsigned int cmd, unsigned long arg){if(_IOC_TYPE(cmd)!=SCULL_IOC_MAGI C){return -EFAULT;}if(_IOC_NR(cmd)>SCULL_IOC_MAXNR){return -EFAULT;}switch(cmd){case SCULL_IOCRESET:printk("SCULL_IOCRESET+ %lx",arg);break;case SCULL_IOCSQUANTUM: /* Set: arg points to the value */printk("SCULL_IOCSQUANTUM+ %lx",arg);break;case SCULL_IOCTQUANTUM: /* Tell: arg is the value */printk("SCULL_IOCTQUANTUM+ %lx",arg);break;case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */printk("SCULL_IOCGQUANTUM+ %lx",arg);break;case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */printk("SCULL_IOCQQUANTUM+ %lx",arg);break;case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */printk("SCULL_IOCXQUANTUM+ %lx",arg);break;case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */printk("SCULL_IOCHQUANTUM+ %lx",arg);break;}return 0;}/* seek文件定位函数 */static loff_t ly_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 = MYDEV_SIZE -1 + offset; break;default: /* can't happen */return -EINVAL;}if ((newpos<0) ||(newpos>MYDEV_SIZE))return -EINVAL;filp->f_pos = newpos;return newpos;}/*文件操作结构体*/static const struct file_operations ly_fops ={.owner = THIS_MODULE,.llseek = ly_llseek,.read = ly_read,.write = ly_write,.open = ly_open,.release = ly_release,.unlocked_ioctl = ioctl,};/*设备驱动模块加载函数*/static int lydev_init(void){int result;int i;dev_t devno = MKDEV(ly_major, 0);/* 静态申请设备号*/if (ly_major)result =register_chrdev_region(devno, 2, "lydev");else /* 动态分配设备号 */{result =alloc_chrdev_region(&devno, 0, 2, "lydev");ly_major = MAJOR(devno); }if (result < 0)return result;/*初始化cdev结构*/cdev_init(&cdev, &ly_fops);= THIS_MODULE;= &ly_fops;/* 注册字符设备 */cdev_add(&cdev, MKDEV(ly_major, 0), MYDEV_NR_DEVS);/* 为设备描述结构分配内存*/ly_devp = kmalloc(MYDEV_NR_DEVS * sizeof(struct ly_dev), GFP_KERNEL); if (!ly_devp) /*申请失败*/{result = - ENOMEM;goto fail_malloc;}memset(ly_devp, 0, sizeof(struct ly_dev));/*为设备分配内存*/for (i=0; i < MYDEV_NR_DEVS; i++) {ly_devp[i].size = MYDEV_SIZE; ly_devp[i].data =kmalloc(MYDEV_SIZE, GFP_KERNEL);memset(ly_devp[i].data, 0, MYDEV_SIZE);} printk("模块加载成功!\n");return 0;fail_malloc:unregister_chrdev_region(devno, 1); return result;}/*模块卸载函数*/static void lydev_exit(void){cdev_del(&cdev); /*注销设备*/kfree(ly_devp); /*释放设备结构体内存*/unregister_chrdev_region(MKDEV(ly_maj or, 0), 2); /*释放设备号*/printk("模块卸载成功!\n");}MODULE_LICENSE("GPL");module_init(lydev_init);module_exit(lydev_exit);2.测试程序#include <>#include<sys/>#include<>#include<>#include<linux/>#include<linux/>#include <>#include <>#define MAXBUF 20#define SCULL_IOC_MAGIC 'k'#define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0)#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int) #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int)#define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3)#define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4)#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int)#define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int)#define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7)#define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8)#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)#define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int)#define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11)#define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12)#define SCULL_IOC_MAXNR 14int main(){int testdev;int i,flag = 1,t,len = -1;char sel;char buf[MAXBUF],tmp[MAXBUF];printf("1、打开设备\n2、写操作\n3、读操作\n4、I/O控制\n5、释放设备\n6、退出\n");while(1) {printf("请输入要执行的操作:");sel = getchar();getchar();switch(sel) {case '1':testdev = open("/dev/lydev",O_RDWR);if ( testdev < 0 ) {printf("设备打开失败 \n");break;}flag = 0;printf("设备打开成功!\n"break;/*case '2':if (flag) {printf("请先打开设备!\n");break;}printf("请输入写入的字符串:");gets(tmp);len = strlen(tmp);printf("len = %d\n",len);t = write(testdev,tmp,len);if (t < 0) {printf("写操作失败!\n");break;}printf("%s字符串写入成功!\n",tmp);break;case '3':if (flag) {printf("请先打开设备!\n");break;}if (len < 0) {printf("请先进行写操作!\n");break;}t = read(testdev,buf,len);if (t < 0) {printf("读操作失败!\n");break;}printf("读操作成功!结果为:%s\n",buf);break;*/case '2':if (flag) {printf("请先打开设备!\n");continue;}printf("请输入要写入的字符串:");gets(tmp);len = sizeof(tmp);个设备文件都有其文件属性(c/b),表示是字符设备还块设备。

相关文档
最新文档