linux设备驱动标准模板

合集下载

Linuxlinux硬件驱动架构

Linuxlinux硬件驱动架构

Linuxlinux硬件驱动架构linux硬件驱动(usb)??模块:模块用来装载到内核中,用来实现设备驱动程序。

??linux对于一个硬件的驱动,采用两种方式读取:??1.直接加载到内核代码中,启动内核时就会驱动此硬件设备??2.以模块方式读取,编程分解成一个.o的文件,当应用程序须要时读取入内核空间运转??so(通常说的硬件驱动其实就是一个硬件驱动模块及.o文件)??设备文件(设备节点):??设备文件(设备节点)指定(主设备号)&&(次设备号)??主设备号:对应着确认的驱动程序。

??(声明设备所使用的驱动程序,设备号相当于硬件驱动程序的一个标识)??次设备号:区分相同属性,相同采用方法,相同边线,相同操作方式??设备号从/proc/drives中获取,so先有驱动程序在内核中,才有设备节点在目录中。

??scsi(并口):通常采用的的usb存储设备,就是演示scsi硬盘而展开设计的。

??linux硬件驱动架构:??.o驱动模块文件--(如果须要采用这个驱动程序,首先必须读取运转它)-->insmod*.o--(驱动程序根据字符设备类型或块设备类型(鼠标属字符设备,硬盘属块设备))向系统登记注册-->登记注册顺利之后系统回到一个主设备号---(根据主设备号建立一个置放在/dev目录下的设备文件)-->(mknod用以建立设备文件须要使用设备号这个参数)----->我们出访硬件时,就可以对设备文件通过open,read,write等命令展开,而驱动就可以发送至适当的read,write操作方式而根据自己模块中的适当函数展开。

??上层调用api.o驱动drive.o??与模块有关的一些东西:??1./lib/modules/2.6.**目录,下面是针对当前内核版本的模块。

??2.查阅模块的倚赖关系与否恰当(depmod设置)??3.加载模块而不需要知道具体的模块位置(modprobe)??4.文件/etc/modules.conf文件,当kernel须要时轻易回去该文件中搜寻别称读取??modprobe用于加载系统已经通过depmod登记过的模块,insmod一般是针对具体的.o进行文件的加载。

关于linux的fb_framebuffer 设备驱动

关于linux的fb_framebuffer 设备驱动

草稿V2.4.01framebuffer设备即帧缓冲设备(简写fb)提供了显示接口的抽象描述。

他同时代表着显示接口的存储区,应用程序通过定义好的函数访问,不需要知道底层的任何操作。

Framebuffer驱动使用的设备节点,通常位于/dev目录,如/dev/fb*.从用户角度看,fb设备和其他/dev下面的设备类似:普通的字符设备,主设备号29,次设备号定义fb的索引。

通常,使用如下方式(前面的数字表示次设备号)0=/dev/fb0第一个fb设备1=/dev/fb1第二个fb设备考虑到向下兼容,可以创建符号链接:/dev/fb0current->fb0/dev/fb1current->fb1fb也是一种普通的内存设备,可以读写其内容。

例如,屏幕抓屏:cp/dev/fb0myfilefb虽然可以像内存设备(/dev/mem)一样,对其read,write,seek以及mmap。

但区别在于fb使用的不是整个内存区,而是显存部分。

通过ioctl可以读取或设定fb设备参数,很重要的一点,颜色表(cmap)也要通过Ioctl设定。

查看<linux/fb.h>就知道有多少ioctl应用以及相关数据结构。

这里给出摘要:-你可以获取设备一些不变的信息,如设备名,屏幕的组织(平面,象素,...)对应内存区的长度和起始地址。

-也可以获取能够改变的信息,例如位深,颜色格式,时序等。

如果你改变这些值,驱动程序将对值进行优化,以满足设备特性(如果你的设定,设备不支持,返回EINVAL)。

-你也可以获取或设定部分颜色表。

所有这些特性让应用程序十分容易的使用framebuffer设备。

Xserver可以使用/dev/fb*而不需知道硬件的寄存器是如何组织的。

XF68_FBDev是一个用于位映射(单色)Xserver,唯一要做的就是在应用程序在相应的位置设定是否显示。

在新内核中,帧缓冲设备可以工作于模块中,允许动态加载。

Linux设备驱动之Ioctl控制

Linux设备驱动之Ioctl控制

Linux设备驱动之Ioctl控制 ⼤部分驱动除了需要具备读写设备的能⼒之外,还需要具备对硬件控制的能⼒。

 ⼀、在⽤户空间,使⽤ioctl系统调⽤来控制设备,原型如下:int ioctl(int fd,unsigned long cmd,...);/*fd:⽂件描述符cmd:控制命令...:可选参数:插⼊*argp,具体内容依赖于cmd*/ ⽤户程序所作的只是通过命令码告诉驱动程序它想做什么,⾄于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

⼆、驱动ioctl⽅法:int (*ioctl) (struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);/*inode与filp两个指针对应于应⽤程序传递的⽂件描述符fd,这和传递open⽅法的参数⼀样。

cmd 由⽤户空间直接不经修改的传递给驱动程序arg 可选。

*/ 在驱动程序中实现的ioctl函数体内,实际上是有⼀个switch {case}结构,每⼀个case对应⼀个命令码,做出⼀些相应的操作。

怎么实现这些操作,这是每⼀个程序员⾃⼰的事情,因为设备都是特定的。

关键在于怎么样组织命令码,因为在ioctl中命令码是唯⼀联系⽤户程序命令和驱动程序⽀持的途径。

在Linux核⼼中是这样定义⼀个命令码的:____________________________________| 设备类型 | 序列号 | ⽅向 | 数据尺⼨ ||----------|--------|------|-------- || 8 bit | 8 bit | 2 bit |8~14 bit||----------|--------|------|-------- | 这样⼀来,⼀个命令就变成了⼀个整数形式的命令码。

但是命令码⾮常的不直观,所以Linux Kernel中提供了⼀些宏,这些宏可根据便于理解的字符串⽣成命令码,或者是从命令码得到⼀些⽤户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送⽅向和数据传输尺⼨。

Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。

为此,的内核一般不能动态的增加新的功能。

为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。

利用这个机制“模块”(module)。

利用这个机制,可以)。

利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。

正是这种机制,走已经安装的模块。

正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。

和可扩充性。

内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。

严格来说,卸载的内核软件。

严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。

但是,另一方面,可安装模块的形式实现的。

但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。

密切相关的部分(如文件系统等)。

课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。

且创建好该系统中的硬件设备的列表树:/sys 文件系统。

(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。

)。

linux驱动模型

linux驱动模型

我们将详细的介绍Linux的设备驱动模型。

Linux设备驱动模型是一个相当复杂的系统,对于初学者来说真有些无从入手。

而且更加困难的是,随着新的Linux Kernel的release,Linux 的设备驱动模型总会有或大或小的变化,我们将尽量展现Linux Kernel 的这种变化。

早期的Linux内核(版本2.4之前)并没有实现一个统一的设备模型,设备节点的创建一般是mknod命令手动创建或利用devfs文件系统创建。

早期的Linux发行版一般会采用手动创建的方式预先把通常用到的节点都创建出来,而嵌入式系统则会采用devfs的方式。

起初Linux 2.6 内核还支持devfs,但从2.6.18开始,内核完全移除了devfs系统而采用的udev的方式动态的创建设备节点。

因此,新的Linux发行版都采用udev的方式管理设备节点文件。

Linux2.6设备驱动模型的基本元素是Class、Bus、Device、Driver,下面我们分别介绍各个部分。

Class 和Class Device驱动模型最基本的概念是设备及其类别,Linux中使用struct class 和struct class_device来管理不同类别的设备。

由于设备驱动模型是一个复杂的系统,我们还是从一个简单的例子开始介绍,然后在逐步展开。

其实实现设备节点的动态创建是一个很简单的事情,并不需要太多的代码。

我们修改我们的驱动初始化函数如下:#include <linux/device.h>#define DEVNAME "hello"static dev_t dev;static struct class *hello_c lass;static struct cdev *hello_cdev;static int __init hello_init(void){int error;error = alloc_chrdev_region(&dev, 0, 2, "hello");if (error){printk("hello: alloc_chardev_region failed! ");goto out;}hello_cdev = cdev_alloc();if (hello_cdev == NULL){printk("hello: alloc cdev failed! ");error = -ENOMEM;goto out_chrdev;}hello_cdev->ops = &hello_fops;hello_cdev->owner = THIS_MODULE;error = cdev_add(hello_cdev, dev, 1);if (error){printk("hello: cdev_add failed! ");goto out_cdev;}hello_class = class_create(THIS_MODULE, DEVNAME);if (IS_ERR(hello_class)){error = PTR_ERR(hello_class);goto out_chrdev;}class_device_create(hello_class, NULL, dev, NULL, DEVNAME);memset (hello_buf, 0, sizeof(hello_buf));memcpy(hello_buf, DEFAULT_MSG, sizeof(DEFAULT_MSG));printk("hello: Hello World! ");return 0;out_cdev:cdev_del(hello_cdev);out_chrdev:unregister_chrdev_region(hello_cdev->dev, 2);out:return error;}static void __exit hello_exit(void){class_device_destroy(hello_class, dev);class_destroy(hello_class);unregister_chrdev_region(hello_cdev->dev, 2);cdev_del(hello_cdev);printk("hello: Goodbye World ");}重新编译这个驱动程序,当加载这个驱动到内核中时,系统(一般是hotplug和udev系统)就会自动的创建我们指定的设备名字:/dev/hello,同时,你也可以发现在sysfs系统中添加了新的文件:/sys/class/hello/hello/。

linux设备驱动之8250串口驱动

linux设备驱动之8250串口驱动

linux设备驱动之8250串口驱动一:前言前一段时间自己实践了一下8250芯片串口驱动的编写。

今天就在此基础上分析一下linux kernel自带的串口驱动。

毕竟只有对比专业的驱动代码才能更好的进步,同以往一样,基于linix kernel2.6.25.相应驱动代码位于:linux-2.6.25/drivers/serial/8250.c。

二:8250串口驱动初始化相应的初始化函数为serial8250_init().代码如下:static int __init serial8250_init(void){int ret, i;if (nr_uarts > UART_NR)nr_uarts = UART_NR;printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ ""%d ports, IRQ sharing %sabled\n", nr_uarts,share_irqs ? "en" : "dis");for (i = 0; i < NR_IRQS; i++)spin_lock_init(&irq_lists[i].lock);ret = uart_register_driver(&serial8250_reg);if (ret)goto out;serial8250_isa_devs = platform_device_alloc("serial8250",PLA T8250_DEV_LEGACY);if (!serial8250_isa_devs) {ret = -ENOMEM;goto unreg_uart_drv;}ret = platform_device_add(serial8250_isa_devs);if (ret)goto put_dev;serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);ret = platform_driver_register(&serial8250_isa_driver);if (ret == 0)goto out;platform_device_del(serial8250_isa_devs);put_dev:platform_device_put(serial8250_isa_devs);unreg_uart_drv:uart_unregister_driver(&serial8250_reg);out:return ret;}这段代码涉及到的知识要求,如platform ,uart等我们在之前都已经做过详细的分析。

Linux视频设备驱动编程(v4l2编程)

Linux视频设备驱动编程(v4l2编程)

Linux视频设备驱动编程(v4l2编程)一.什么是video4linuxVideo4linux2(简称V4L2),是linux中关于视频设备的内核驱动。

在Linux 中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。

二、一般操作流程(视频设备):1. 打开设备文件。

int fd=open(”/dev/video0″,O_RDWR);2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。

VIDIOC_QUERYCAP,struct v4l2_capability3. 选择视频输入,一个视频设备可以有多个视频输入。

VIDIOC_S_INPUT,struct v4l2_input4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。

VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format5. 向驱动申请帧缓冲,一般不超过5个。

struct v4l2_requestbuffers6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。

mmap7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer8. 开始视频的采集。

VIDIOC_STREAMON9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。

VIDIOC_DQBUF10. 将缓冲重新入队列尾,这样可以循环采集。

VIDIOC_QBUF11. 停止视频的采集。

VIDIOC_STREAMOFF12. 关闭视频设备。

close(fd);三、常用的结构体(参见/usr/include/linux/videodev2.h):struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备struct v4l2_input input; //视频输入struct v4l2_standard std;//视频的制式,比如PAL,NTSCstruct v4l2_format fmt;//帧的格式,比如宽度,高度等struct v4l2_buffer buf;//代表驱动中的一帧v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL_Bstruct v4l2_queryctrl query;//查询的控制struct v4l2_control control;//具体控制的值下面具体说明开发流程(网上找的啦,也在学习么)打开视频设备在V4L2中,视频设备被看做一个文件。

LinuxI2C驱动--用户态驱动简单示例

LinuxI2C驱动--用户态驱动简单示例

LinuxI2C驱动--⽤户态驱动简单⽰例1. Linux内核⽀持I2C通⽤设备驱动(⽤户态驱动:由应⽤层实现对硬件的控制可以称之为⽤户态驱动),实现⽂件位于drivers/i2c/i2c-dev.c,设备⽂件为/dev/i2c-02. I2C通⽤设备驱动以字符设备注册进内核的static const struct file_operations i2cdev_fops = {.owner = THIS_MODULE,.llseek = no_llseek,.read = i2cdev_read,.write = i2cdev_write,.unlocked_ioctl = i2cdev_ioctl,.open = i2cdev_open,.release = i2cdev_release,};res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);3. 对设备⽂件进⾏读写时,可以调⽤read、write或者ioctl等⽅法,他们都是通过调⽤函数i2c_transfer来实现对I2C设备的操作的int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num){int ret;/* REVISIT the fault reporting model here is weak:** - When we get an error after receiving N bytes from a slave,* there is no way to report "N".** - When we get a NAK after transmitting N bytes to a slave,* there is no way to report "N" ... or to let the master* continue executing the rest of this combined message, if* that's the appropriate response.** - When for example "num" is two and we successfully complete* the first message but get an error part way through the* second, it's unclear whether that should be reported as* one (discarding status on the second message) or errno* (discarding status on the first one).*/if (adap->algo->master_xfer) {#ifdef DEBUGfor (ret = 0; ret < num; ret++) {dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, ""len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)'R' : 'W', msgs[ret].addr, msgs[ret].len,(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");}#endifif (in_atomic() || irqs_disabled()) {ret = mutex_trylock(&adap->bus_lock);if (!ret)/* I2C activity is ongoing. */return -EAGAIN;} else {mutex_lock_nested(&adap->bus_lock, adap->level);}ret = adap->algo->master_xfer(adap,msgs,num);mutex_unlock(&adap->bus_lock);return ret;} else {dev_dbg(&adap->dev, "I2C level transfers not supported\n");return -EOPNOTSUPP;}}4. i2c_transfer通过代码可以看出,i2c_transfer 通过调⽤相应的 adapter 的 master_xfer ⽅法实现的,⽽ master_xfer 主要是根据 struct i2c_msg 类型的msgs来进⾏处理的。

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

/*Linux设备驱动标准模板,用于s3c2410实验,下面有配套应用程序内核版本:2.6.31交叉编译器:arm-linux-gccRead,write,ioctlS3C2410 GPF0~GPF3外接led灯,低电平点亮,高电平熄灭分别用write和ioctl实现led等的点亮经过验证,可点亮led流水灯*/#include<linux/module.h>#include<linux/kernel.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/device.h>#include<linux/errno.h>#include<linux/semaphore.h>#include<linux/cdev.h>#include<linux/types.h>#include<asm/uaccess.h>#include<linux/wait.h>#include<linux/sched.h>#include<linux/slab.h>#include<linux/ioctl.h>#include<mach/regs-gpio.h>#include<mach/hardware.h>#include<asm/io.h>#define BUF_SIZE 100#define DEVICE_NAME "mydriver"#define MYDEV_MAGIC 'g'#define MYDEV_MAXNR 3#define MYDEV_FUNC1 _IO(MYDEV_MAGIC, 0)#define MYDEV_FUNC2 _IO(MYDEV_MAGIC, 1)#define MYDEV_FUNC3 _IO(MYDEV_MAGIC, 2)#define MYDEV_FUNC4 _IO(MYDEV_MAGIC, 3)#define GPFCON *((unsignedlong*) ioremap(0x56000050, 4))#define GPFDAT *((unsignedlong*) ioremap(0x56000054, 4))#define GPFUP *((unsignedlong*) ioremap(0x56000058, 4))staticint MYDRIVER_Major = 0;struct mydev{struct cdevcdev;struct semaphore sem;wait_queue_head_trq;wait_queue_head_twq;char *buf;};struct mydev *devp;staticint mydriver_open(struct inode *inode, struct file *file) {struct mydev *devp;printk(KERN_INFO "My Driver Open Called!\n");devp = container_of(inode->i_cdev, struct mydev, cdev);file->private_data = devp;try_module_get (THIS_MODULE);GPFCON = (GPFCON |0XFF) & 0X55;GPFUP = GPFUP & 0XF0;GPFDAT = GPFDAT | 0x0f;return 0;}staticint mydriver_release(struct inode *inode, struct file *file){printk(KERN_INFO "My Driver Release Called!\n");module_put(THIS_MODULE);return 0;}static ssize_tmydriver_read(struct file *filp, char __user*buf, size_t count, loff_t *f_pos) {struct mydev *devp = (struct mydev *)filp->private_data;ssize_tretval = 0;unsignedint readbyte = 0;char *my_buf = devp->buf;printk(KERN_INFO "My Driver Read Called!\n");if(down_interruptible(&devp->sem))return -ERESTARTSYS;while(*my_buf == 0){up(&devp->sem);if(filp->f_flags& O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(devp->rq, *my_buf != 0))return -ERESTARTSYS;if(down_interruptible(&devp->sem))return -ERESTARTSYS;}if(count <= 0){retval = 0;goto out;}elseif(count > BUF_SIZE)count = BUF_SIZE;while(*my_buf != 0 && count != 0){put_user(*my_buf++, buf++);readbyte++;count--;}retval = readbyte;memset(devp->buf, 0, BUF_SIZE);wake_up_interruptible(&devp->wq);out:up(&devp->sem);printk(KERN_INFO "Leave Read func!\n");return retval;}static ssize_tmydriver_write(struct file *filp, constchar __user*buf, size_t count, loff_t *f_pos){struct mydev *devp =(struct mydev *)filp->private_data;ssize_tretval = 0;unsignedint writebyte = 0;char *my_buf = devp->buf;printk(KERN_INFO "My Driver Write Called!\n");if(down_interruptible(&devp->sem))return -ERESTARTSYS;while(*my_buf != 0){up(&devp->sem);if(filp->f_flags& O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(devp->wq, *my_buf == 0))return -ERESTARTSYS;if(down_interruptible(&devp->sem))return -ERESTARTSYS;}if(count <= 0){retval = 0;goto out;}elseif(count > BUF_SIZE)count = BUF_SIZE;while(count != 0){get_user(*my_buf++, buf++);writebyte++;count--;}retval = writebyte;switch(*devp->buf){case'1':GPFDAT = (GPFDAT |0x0f) & 0xfe;break;case'2':GPFDAT = (GPFDAT | 0x0f) & 0xfd;break;case'3':GPFDAT = (GPFDAT | 0x0f) & 0xfb;break;case'4':GPFDAT = (GPFDAT | 0x0f) & 0xf7;break;}wake_up_interruptible(&devp->rq);out:up(&devp->sem);printk(KERN_INFO "Leave wirtefunc!\n");return retval;}staticint mydriver_ioctl( struct inode *inode, struct file *file, unsignedint cmd, unsignedlong arg){if(_IOC_TYPE(cmd) != MYDEV_MAGIC)return -ENOTTY;if(_IOC_NR(cmd) > MYDEV_MAXNR)return -ENOTTY;switch(cmd){case MYDEV_FUNC1:printk("ioctl mydev_func1\n");GPFDAT = (GPFDAT |0x0f) & 0xfe;break;case MYDEV_FUNC2:printk("ioctl mydev_func2\n");GPFDAT = (GPFDAT | 0x0f) & 0xfd;break;case MYDEV_FUNC3:printk("ioctl mydev_func3\n");GPFDAT = (GPFDAT | 0x0f) & 0xfb;break;case MYDEV_FUNC4:printk("ioctl mydev_func4\n");GPFDAT = (GPFDAT | 0x0f) & 0xf7;break;}return 0;}staticstruct file_operationsmydriver_fops ={.owner = THIS_MODULE,.open = mydriver_open,.release = mydriver_release,.read = mydriver_read,.write =mydriver_write,.ioctl =mydriver_ioctl,};staticint setup_cdev(struct mydev *devp){int ret = 0;cdev_init(&devp->cdev, &mydriver_fops);devp->cdev.owner = THIS_MODULE;ret = cdev_add(&devp->cdev, MKDEV(MYDRIVER_Major, 0), 1);return ret;}staticstructclass *mydriver_class;staticint __initmydriver_init(void){int ret;dev_tmydevno;printk(KERN_INFO "Enter initfunc\n");mydevno = MKDEV(MYDRIVER_Major, 0);if(mydevno)ret = register_chrdev_region(mydevno, 1, DEVICE_NAME);else{ret = alloc_chrdev_region(&mydevno, 0, 1, DEVICE_NAME);MYDRIVER_Major = MAJOR(mydevno);}if(ret < 0){printk(DEVICE_NAME " can't register major number\n");return ret;}printk("register My Driver OK! Major = %d\n", MYDRIVER_Major);devp = (struct mydev*)kmalloc(sizeof(struct mydev), GFP_KERNEL);if(!devp){printk("Allocmydev error!");ret = -ENOMEM;goto fail_malloc1;}devp->buf = (char*)kmalloc(BUF_SIZE, GFP_KERNEL);if(!devp->buf){printk("allocbuf error!");ret = -ENOMEM;goto fail_malloc2;}/*初?始º?化¡¥设¦¨¨备À?结¨¢构1体¬?*/memset(devp->buf, 0, BUF_SIZE);init_MUTEX(&devp->sem);init_waitqueue_head(&devp->rq);init_waitqueue_head(&devp->wq);ret = setup_cdev(devp);if(ret < 0){printk("setup cdev error!");goto fail_setup_cdev;}mydriver_class = class_create(THIS_MODULE, DEVICE_NAME);if(IS_ERR(mydriver_class)){printk("Err: failed in My Driver class. \n");goto fail_create_class;}device_create(mydriver_class, NULL, mydevno, NULL, DEVICE_NAME);printk(DEVICE_NAME " initialized\n");printk(KERN_INFO "Quit initfunc\n");return 0;fail_create_class:cdev_del(&devp->cdev);fail_setup_cdev:kfree(devp->buf);fail_malloc2:kfree(devp);fail_malloc1:unregister_chrdev_region(mydevno, 1);return ret;}staticvoid __exit mydriver_exit(void){printk(KERN_INFO "Enter exit func\n");unregister_chrdev_region(MKDEV(MYDRIVER_Major, 0), 1);cdev_del(&devp->cdev);kfree(devp->buf);kfree(devp);device_destroy(mydriver_class, MKDEV(MYDRIVER_Major, 0));class_destroy(mydriver_class);printk(KERN_INFO "Quit exit func\n");}module_init(mydriver_init);module_exit(mydriver_exit);MODULE_AUTHOR("Wzd");MODULE_DESCRIPTION("My Driver");MODULE_LICENSE("Dual BSD/GPL");/**上述驱动程序的配套应用程序*/#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<unistd.h>#include<fcntl.h>#include<string.h>#include<linux/ioctl.h>#include<sys/wait.h>#define MYDEV_MAGIC 'g'#define MYDEV_MAXNR 3#define MYDEV_FUNC1 _IO(MYDEV_MAGIC, 0)#define MYDEV_FUNC2 _IO(MYDEV_MAGIC, 1)#define MYDEV_FUNC3 _IO(MYDEV_MAGIC, 2)#define MYDEV_FUNC4 _IO(MYDEV_MAGIC, 3)char buff[100];char data[100]="1234";main(){int fd;unsignedlong count;char *p = buff;unsignedint num = 10;memset(buff, 0, 100);fd =open("/dev/mydriver",0666);if(fd< 0)printf("failed to open mydriver\n");printf("open dev_hello success\n");// count = read(fd,buff,sizeof(buff));//if(count < 0)// printf("failed to read mydriver\n");//printf("buff : %s\n",p);/* count = write(fd,data,strlen(data));if(count < 0)printf("failed to write mydriver\n");printf("write mydriver success\n");count = read(fd,buff,sizeof(buff));if(count < 0)printf("failed to read mydriver\n");printf("read mydriver success\n");if(strlen(buff) > 100)buff[99] = 0;printf("buff : %s\n",p);while(num--){ioctl(fd, MYDEV_FUNC1);sleep(1);ioctl(fd, MYDEV_FUNC2);sleep(1);ioctl(fd, MYDEV_FUNC3);sleep(1);ioctl(fd, MYDEV_FUNC4);sleep(1);}*/while(num--){write(fd, &data[0], 1);read(fd, p++, 1);sleep(1);write(fd, &data[1], 1);read(fd, p++, 1);sleep(1);write(fd, &data[2], 1);read(fd, p++, 1);sleep(1);write(fd, &data[3], 1);read(fd, p++,1);sleep(1);}if(strlen(buff) > 100)buff[99] = 0;printf("buff : %s\n",p);close(fd);return 0;}。

相关文档
最新文档