当前位置:首页 > 范文大全 > 接收函 > 正文
 

linux驱动数据接收函数

发布时间:2024-03-29 13:20:13 影响了:

博文学习网小编为您收集整理的linux驱动数据接收函数,提供全面的linux驱动数据接收函数信息,希望对您有用!

linux驱动数据接收函数篇一:Linux驱动试题

笔试题:

1、 Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类设备。

答:字符设备:字符设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程序来实现这种特性。字符设备驱动程序通常至少实现open,close,read和write系统调用。字符终端、串口、鼠标、键盘、摄像头、声卡和显卡等就是典型的字符设备。

块设备:和字符设备类似,块设备也是通过/dev目录下的文件系统节点来访问。块设备上能够容纳文件系统,如:u盘,SD卡,磁盘等。

字符设备和块设备的区别仅仅在于内核内部管理数据的方式,也就是内核及驱动程序之间的软件接口,而这些不同对用户来讲是透明的。在内核中,和字符驱动程序相比,块驱动程序具有完全不同的接口

2、查看驱动模块中打印信息应该使用什么命令?如何查看内核中已有的字符设备的信息?如何查看正在使用的有哪些中断号?

答:1) 查看驱动模块中打印信息的命令:dmesg

2) 查看字符设备信息可以用lsmod 和modprobe,lsmod可以查看模块的依赖关系,modprobe在加载模块时会加载其他依赖的模块。

3)显示当前使用的中断号cat /proc/interrupt

3、Linux中引入模块机制有什么好处?

答:首先,模块是预先注册自己以便服务于将来的某个请求,然后他的初始化函数就立即结束。换句话说,模块初始化函数的任务就是为以后调用函数预先作准备。

好处:

1) 应用程序在退出时,可以不管资源的释放或者其他的清除工作,但是模块的退出函数却必须仔细此撤销初始化函数所作的一切。

2) 该机制有助于缩短模块的开发周期。即:注册和卸载都很灵活方便。

4、copy_to_user()和copy_from_user()主要用于实现什么功能?一般用于file_operations结构的哪些函数里面?

答:由于内核空间和用户空间是不能互相访问的,如果需要访问就必须借助内核函数进行数据读写。copy_to_user():完成内核空间到用户空间的复制,copy_from_user():是完成用户空间到内核空间的复制。一般用于file_operations结构里的read,write,ioctl等内存数据交换作用的函数。当然,如果ioctl没有用到内存数据复制,那么就不会用到这两个函数。

5、请简述主设备号和次设备号的用途。如果执行mknod chartest c 4 64,创建chartest 设备。请分析chartest使用的是那一类设备驱动程序。

答:

1)主设备号:主设备号标识设备对应的驱动程序。虽然现代的linux内核允许多个驱动程序共享主设备号,但我们看待的大多数设备仍然按照“一个主设备对应一个驱动程序”的原则组织。

次设备号:次设备号由内核使用,用于正确确定设备文件所指的设备。依赖于驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可将此设备号当作设备本地数组的索引。

2)chartest 由驱动程序4管理,该文件所指的设备是64号设备。(感觉类似于串口终端或者字符设备终端)。

6、设备驱动程序中如何注册一个字符设备?分别解释一下它的几个参数的含义。

答:注册一个字符设备驱动有两种方法:

1) void cdev_init(struct cdev *cdev, struct file_operations *fops)

该注册函数可以将cdev结构嵌入到自己的设备特定的结构中。cdev是一个指向结构体cdev的指针,而fops是指向一个类似于file_operations结构(可以是file_operations结构,但不限于该结构)的指针.

2) int register_chrdev(unsigned int major, const char *namem , struct file)operations *fopen);

该注册函数是早期的注册函数,major是设备的主设备号,name是驱动程序的名称,而fops是默认的file_operations结构(这是只限于file_operations结构)。对于register_chrdev的调用将为给定的主设备号注册0-255作为次设备号,并为每个设备建立一个对应的默认cdev结构。

7、请简述中断于DMA的区别。Linux设备驱动程序中,使用哪个函数注册和注销中断处理程序?

答:1)DMA:是一种无须CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制,使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐率。

中断:是指CPU在执行程序的过程中,出现了某些突发事件时CPU必须暂停执行当前的程序,转去处理突发事件,处理完毕后CPU又返回源程序被中断的位置并继续执行。 所以中断和MDA的区别就是MDA不需CPU参与而中断是需要CPU参与的。

2)中断注册函数和中断注销函数

注册中断:

int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);

参数意义依次是:中断号,中断处理函数,中断管理有关的掩码,中断请求设备名,中断信号线。

过程是:dev_name设备请求中断->cpu分配中断号->设置中断管理的掩码->分配中断信号线->处理中断函数->完成之后再根据设置情况返回原处理程序处继续处理程序。 注销中断;

Void free_irq(unsigned int irq, void *dev_id);

释放中断和中断信号线

8、中断和轮询哪个效率高?怎样决定是采用中断方式还是采用轮询方式去实现驱动? 答:中断是CPU处于被动状态下来接受设备的信号,而轮询是CPU主动去查询该设备是否有请求。凡事都是两面性,所以,看效率不能简单的说那个效率高。如果是请求设备是一个频繁请求cpu的设备,或者有大量数据请求的网络设备,那么轮询的效率是比中断高。如果是一般设备,并且该设备请求cpu的频率比较底,则用中断效率要高一些。

9、下图是CS8900的内部芯片结构:

简单描述在这个图中802.3 MAC Engine, Encoder/Decoder, 10Base-T RX/RX filter & Receiver/ Transmitter 这三个部件的主要功能。

答:802.3 MAC Engine:以太网广播地址控制器,他控制所有以太网发送和接受的数据,其中包括,冲突检测、线路监听、报头,和冗余校验等

Encoder/Decoder:译码解码器。封装/拆卸报头或者协议头。

10Base-T RX/RX filter & Receiver/ Transmitter:数据发送/接收缓冲池。当数据写入发送缓冲池时,在线路畅通的情况下会发送出去。

10、简单描述在cs8900的驱动设计中, 发送数据frame和接收数据frame的过程。 答:1)发送流程如下:

(1) 网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。

(2) 对于以太网,如果有效数据的长度小于以太网冲突检测所要求的数据桢的最小长度,则给临时缓冲区的末尾填充0

(3) 设置硬件寄存器,驱使网络设备进行数据发送操作。

2)接收流程

网络设备接收数据主要是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接受到的数据,分配sk_buff数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buff传递给上层协议。

11、Cs8900.c的驱动中,发送数据frame的过程为什么需要关中断?接收数据frame的过程为什么不需要关中断?

答:在发送过程中是不能被打断的,在发送的过程中,不关中断,这时候如果有一个中断到来,那么cpu有可能会去相应该中断,如果该中断需要改写的数据是发送数据的缓冲区,那么缓冲区将被改写,这样即使cpu相应完毕该中断,再发送数据,接收方也不认识该数据不能接收。

在接收数据的时候,需要打开中断,是因为要及时的相应接收到的数据。如果关闭该中断,那么接收方有可能因为相应优先级高的中断而接收不到该数据。

12、简单描述skbuff这个数据结构在网络结构中所起到的作用,为什么需要一个skbuff,它的分配和释放主要都在什么部位

答:sk_buff结构非常重要,它的含义为“套接字缓冲区”,用于在linux网络子系统中的盖层之间传递数据。

当发送数据包时,linux内核的网络处理模块必须建立一个包含要传输的数据包的sk_buff,然后将sk_buff递交给下层,各层在sk_buff中添加不同的协议头直至交给网络设备发送。同样的,当网络设备从网络媒介上接受到数据包后,它必须将接受到的数据转换为sk_buff数据结构并传递给上层,盖层不抛去相应的协议头直至交给用户。

分配sk_buff在接受一开始就应该分配,在发送完毕数据之后可以释放sk_buff

上机题:

1、用中断方式实现一个串口的字符设备驱动程序。

嵌入式Linux内核与驱动面试要点:

1. 实际经验:所开发驱动程序或内核模块的来龙去脉(需求、设计思想、实现方法、要点难点,特别是硬件调试过程中所遇到的特殊情况),所修复BUG的现象、调试手段、原因分析和解决方案。

2. 驱动调试:内核的调试手段、应用程序的调试手段(内核Panic所dump的信息以及Panic的分析、应用程序core dump的分析)。

3. 驱动基础:mknod与udev,module相关API,内核Makefile的编写,设备编号的申请,设备的注册,简单驱动的fops(open/read/write/ioctl/release),用户空间和内核空间的数据交换,阻塞操作的实现、select/poll的支持,mmap的实现,DMA机制及其注意事项。

4. 中断机制:Linux中断机制的内在逻辑,中断处理程序的实现要点,中断共享机制,中断上下文与进程上下文的区别(为什么在中断上下文中(出自:WwW.HNNscy.Com 博 文学习 网:linux驱动数据接收函数)不能执行导致进程调度的函数),中断与异常的区别,中断的管理(开中断与关中断)。

5. 下半部:Linux下半部机制的必要性,三种类型下半部(softirq/tasklet/work

queue)的区别与应用场景,三种下半部机制的API,中断处理程序、下半部以及进程上下文之间的同步问题。

6. 内核同步:内核中竞争与同步机制的内在逻辑,内核同步方法(原子操作/spin lock/信号量/读写锁/完成变量completion

variable/Seq_lock/Read-copy-update/Per-CPU变量/禁止内核抢占、中断和下半部/内存屏障)的内在逻辑、区别与应用场景。

7. 内存分配:Linux内存管理及分配机制(buddy system和slab等),

kmalloc的原理、应用场景及参数,alloc_pages物理页面分配,高端内存映射,Per-CPU数据,alloc_bootmem启动时的内存分配。

8. 定时延时:内核定时、延时及等待机制(忙等待,内核定时器,schedule_timeout,等待队列、进程的阻塞与唤醒)

9. 电源管理:Linux内核的电源管理机制,驱动程序中电源管理的实现。

10. 驱动子系统:嵌入式系统中常用简单总线接口(I2C/SPI/UART/SDIO)驱动子系统,重点外设模块(MTD及其文件系统/MicroSD/LCD/Camera/Audio/网卡/WIFI/BT/USB/键盘与触屏)驱动子系统。

11. 硬件基础:ARM体系结构的基础知识(寄存器、运行模式、MMU、Cache、常用汇编指令),中断控制器,DMA控制器等,重点外设的硬件逻辑。

12. 进程管理:O(1)调度算法和CFS调度算法的思想与实现方法,优先级反转及其解决方法,内核抢占(禁止抢占、抢占时机),进程的管理(阻塞与唤醒、等待队列、调度、放弃CPU

等),进程与线程的区别、内核线程与普通进程的区别。

13. 系统启动:内核启动详细顺序(上电 -> Bootloader -> start_kernel() -> 各内核子系统的启动 ->

启动新线程Init用于启动系统[...] -> 启动新线程用于创建各内核线程 ->

IDLE),模块INIT的实现机制(各种INIT宏所标识的函数的调用时机)。

14. 文件系统:Linux虚拟文件系统VFS的架构,文件open的过程(普通文件、字符设备、块设备)、系统调用open和字符设备驱动open函数的参数差异。

15. 其他知识:Makefile的编写/Shell编程/Busybox/GCC编译过程及其优化/GDB命令/动态链接库的链接方式/NPTL之线程管理接口/ELF/Linux的Log机制/变量在内存中的存储/Daemon进程/孤儿进程...

linux驱动数据接收函数篇二:网络数据包收发流程(一):从驱动到协议栈

网络数据包收发流程(一)

:从驱动到协议栈 2011-06-27 11:28:20 分类: LINUX

早就想整理网络数据包收发流程了,一直太懒没动笔。今天下决心写了

一、硬件环境

intel82546:PHY与MAC集成在一起的PCI网卡芯片,很强大

bcm5461:PHY芯片,与之对应的MAC是TSEC

TSEC:Three Speed Ethernet Controller,三速以太网控制器,PowerPc 架构CPU里面的MAC模块 注意,TSEC内部有DMA子模块

话说现在的CPU越来越牛叉了,什么功能都往里面加,最常见的如MAC功能。

TSEC只是MAC功能模块的一种,其他架构的cpu也有和TSEC类似的MAC功能模块。

这些集成到CPU芯片上的功能模块有个学名,叫平台设备,即 platform device。

二、网络收包原理

网络驱动收包大致有3种情况:

no NAPI:mac每收到一个以太网包,都会产生一个接收中断给cpu,即完全靠中断方式来收包

缺点是当网络流量很大时,cpu大部分时间都耗在了处理mac的中断。

netpoll:在网络和I/O子系统尚不能完整可用时,模拟了来自指定设备的中断,即轮询收包。 缺点是实时性差

NAPI: 采用 中断 + 轮询 的方式:mac收到一个包来后会产生接收中断,但是马上关闭。

直到收够了netdev_max_backlog个包(默认300),或者收完mac上所有包后,才再打开接收中断

通过sysctl来修改 net.core.netdev_max_backlog

或者通过proc修改 /proc/sys/net/core/netdev_max_backlog

下面只写内核配置成使用NAPI的情况,只写TSEC驱动。(非NAPI的情况和PCI网卡驱动 以后再说) 内核版本 linux 2.6.24

三、NAPI 相关数据结构

每个网络设备(MAC层)都有自己的net_device数据结构,这个结构上有napi_struct。

每当收到数据包时,网络设备驱动会把自己的napi_struct挂到CPU私有变量上。

这样在软中断时,net_rx_action会遍历cpu私有变量的poll_list,

执行上面所挂的napi_struct结构的poll钩子函数,将数据包从驱动传到网络协议栈。

四、内核启动时的准备工作

4.1 初始化网络相关的全局数据结构,并挂载处理网络相关软中断的钩子函数

start_kernel()

--> rest_init()

--> do_basic_setup()

--> do_initcall

-->net_dev_init

__init net_dev_init()

{

//每个CPU都有一个CPU私有变量 _get_cpu_var(softnet_data)

//_get_cpu_var(softnet_data).poll_list很重要,软中断中需要遍历它的

for_each_possible_cpu(i) {

struct softnet_data *queue;

queue = &per_cpu(softnet_data, i);

skb_queue_head_init(&queue->input_pkt_queue);

queue->completion_queue = NULL;

INIT_LIST_HEAD(&queue->poll_list);

queue->backlog.poll = process_backlog;

queue->backlog.weight = weight_p;

}

open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); //在软中断上挂网络发送handler open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); //在软中断上挂网络接收handler }

4.2 加载网络设备的驱动

NOTE:这里的网络设备是指MAC层的网络设备,即TSEC和PCI网卡(bcm5461是phy)

在网络设备驱动中创建net_device数据结构,并初始化其钩子函数 open(),close() 等

挂载TSEC的驱动的入口函数是 gfar_probe

// 平台设备 TSEC 的数据结构

static struct platform_driver gfar_driver = {

.probe = gfar_probe,

.remove = gfar_remove,

.driver = {

.name = "fsl-gianfar",

},

};

int gfar_probe(struct platform_device *pdev)

{

dev = alloc_etherdev(sizeof (*priv)); // 创建net_device数据结构

dev->open = gfar_enet_open;

dev->hard_start_xmit = gfar_start_xmit;

dev->tx_timeout = gfar_timeout;

dev->watchdog_timeo = TX_TIMEOUT;

#ifdef CONFIG_GFAR_NAPI

netif_napi_add(dev, &priv->napi,gfar_poll,GFAR_DEV_WEIGHT); //软中断里会调用poll钩子函数 #endif

#ifdef CONFIG_NET_POLL_CONTROLLER

dev->poll_controller = gfar_netpoll;

#endif

dev->stop = gfar_close;

dev->change_mtu = gfar_change_mtu;

dev->mtu = 1500;

dev->set_multicast_list = gfar_set_multi;

dev->set_mac_address = gfar_set_mac_address;

dev->ethtool_ops = &gfar_ethtool_ops;

}

五、启用网络设备

5.1 用户调用ifconfig等程序,然后通过ioctl系统调用进入内核

socket的ioctl()系统调用

--> sock_ioctl()

--> dev_ioctl()//判断SIOCSIFFLAGS

--> __dev_get_by_name(net, ifr->ifr_name) //根据名字选net_device

--> dev_change_flags()//判断IFF_UP

--> dev_open(net_device) //调用open钩子函数

对于TSEC来说,挂的钩子函数是 gfar_enet_open(net_device)

5.2 在网络设备的open钩子函数里,分配接收bd,挂中断ISR(包括rx、tx、err),对于TSEC来说 gfar_enet_open

--> 给Rx Tx Bd 分配一致性DMA内存

--> 把Rx Bd的“EA地址”赋给数据结构,物理地址赋给TSEC寄存器

--> 把Tx Bd的“EA地址”赋给数据结构,物理地址赋给TSEC寄存器

--> 给 tx_skbuff 指针数组 分配内存,并初始化为NULL

--> 给 rx_skbuff 指针数组 分配内存,并初始化为NULL

--> 初始化Tx Bd

--> 初始化Rx Bd,提前分配存储以太网包的skb,这里使用的是一次性dma映射

(注意:#define DEFAULT_RX_BUFFER_SIZE 1536保证了skb能存一个以太网包)rxbdp = priv->rx_bd_base;

for (i = 0; i < priv->rx_ring_size; i++) {

struct sk_buff *skb = NULL;

rxbdp->status = 0;

//这里真正分配skb,并且初始化rxbpd->bufPtr, rxbdpd->length

skb = gfar_new_skb(dev, rxbdp);

priv->rx_skbuff[i] = skb;

rxbdp++;

}

rxbdp--;

rxbdp->status |= RXBD_WRAP; // 给最后一个bd设置标记WRAP标记

--> 注册TSEC相关的中断handler: 错误,接收,发送

request_irq(priv->interruptError, gfar_error, 0, "enet_error", dev)

request_irq(priv->interruptTransmit, gfar_transmit, 0, "enet_tx", dev)//包发送完request_irq(priv->interruptReceive, gfar_receive, 0, "enet_rx", dev) //包接收完

-->gfar_start(net_device)

// 使能Rx、Tx

// 开启TSEC的 DMA 寄存器

// Mask 掉我们不关心的中断event

最终,TSEC相关的Bd等数据结构应该是下面这个样子的

linux驱动数据接收函数篇三:Linux驱动程序实例

1、 最简单的设备驱动程序hello.c

#include <linux/init.h>

#include <linux/module.h>

MODULE_LICENSE("GPL");

static int hello_init(void)

{

printk(KERN_ALERT "Hello, Hello,Linux Driver !\n");

return 0;

}

static void hello_exit(void)

{

}

module_init(hello_init);

module_exit(hello_exit);

printk(KERN_ALERT "Goodbye, Hello,Linux Driver !\n");

说明:

(1)前两行为所包含的头文件,位于内核源码的目录下include文件夹下的。

(2)程序中的MODULE_LICENSE("GPL");用于声明模块的许可证。

(3) module_init()为注册加载时执行的函数,module_exit()为/注册卸载时执行的函数。传递给这两个函数的的参数为所要进行初始化的函数的地址(函数名)。

(4)模块的编译:使用gcc编译器,与编译普通程序不同的是要在参数-I后指定内核源代码的目录,2.4的内核模块编译后将生成.o格式的文件。命令行下的编译格式如下: gcc -DMODULE -D__KERNEL__ -I /usr/src/linux-2.4.20/include -c hello.c 其中-DMODULE -D__KERNEL__为两个宏定义,如果文件中包含这两个的宏定义,可以在gcc编译时不用再指定。文件中宏定义的内容如下:

#ifndef __KERNEL__

#define __KERNEL__

#endif

#ifndef MODULE

#define MODULE

#endif

(5)模块的加载与卸载

模块加载:在命令行下执行:insmod hello.o。如果成功加载到内核将在终端上显示:Hello, Hello,Linux Driver ! 。

查看加载的模块:通过lsmod命令可以查看内核中已经加载的模块。

模块的卸载:rmmod hello.o。卸载成功的话将终端显示:Goodbye, Hello,Linux Driver !

(6) 驱动模块运行在内核空间,运行时不能依赖于任何函数库和模块连接,所以在写驱动时所调用的函数只能是作为内核一部分的函数。内核代码不能实现浮点书运算。

2、一般驱动程序都会实现一个file_operation结构中的函数。如test.c程序中所实现的file_operation结构如下:

struct file_operations test_fops={

read:read_test,

write:write_test,

open:open_test,

release:release_test,

};

该驱动程序所实现的功能是在内存中开辟一段空间,write实现了往这段内中写数据,read正好相反,是从这段内存中读出数据。

(1)头文件和全局变量定义如下:

#include<linux/types.h>

#include<linux/fs.h>

#include<linux/mm.h>

#include<linux/errno.h>

#include<asm/segment.h>

#include<asm/uaccess.h>

#include<linux/module.h>

#include<linux/version.h>

#include<linux/config.h>

MODULE_LICENSE("GPL");

unsigned int test_major = 254;

char *str_test;

unsigned int count_driver; //设备号 //存放内存空间的指针 //当前内存中拥有的数据的字节数

//容量的最大值 const unsigned int count_driver_max=255;

(2)模块初始化函数为:

static int test_init_module(void)

{

int result;

result = register_chrdev(test_major,"test",&test_fops);

if(result < 0)

{

printk(KERN_INFO"test:can't get major number\n");

return result;

}

printk("register ok\n");

if((str_test=(char*)kmalloc(256,GFP_KERNEL))==NULL) //申请256字节的内存空间 {

printk("kmalloc error\n");

return -1;

}

Else

{

printk("kamlloc success!\n");

count_driver = 0;

}

return 0;

}

完成了两个工作:一、通过register_chrdev()向系统注册了一个设备名为test的设备,设备号由test_major 指定。应用层对设备的操作方法由结构test_fops中的指针所指向。

二、通过函数kmalloc() 申请了一段256字节的内存,用来存放应用层用户所写的数据。

(3)open和close的实现, 只是一个计数功能:

static int open_test(struct inode *inode,struct file *file)

{

MOD_INC_USE_COUNT;

return 0;

}

static int release_test(struct inode *inode,struct file *file)

{

MOD_DEC_USE_COUNT;

return 0;

}

(4)Write函数的实现:

static ssize_t write_test(struct file *file,const char *buf,size_t count,loff_t *t)

{

int result; if(count<count_driver_max) { } else { } return count_driver; if((result=copy_from_user(str_test,buf,count_driver_max))==0)count_driver=count_driver_max; count_driver=0; else if((result=copy_from_user(str_test,buf,count))==0)count_driver=count; count_driver=0; else

}

它的功能是把用户空间的数据复制到str_test所指的内存空间中,复制数据前首先判断数据的个数是不是内存空间所能容纳的,若是则直接复制,如果超出了count_driver_max,则只能复制count_driver_max个字节的数据。函数的返回值为成功复制数据的个数。

(5)Read函数的实现

static ssize_t read_test(struct file *file,char *buf, size_t count,loff_t *t ) {

int result,read_num;

} if(count_driver>0) {} else read_num=0; return read_num; if(count_driver>=count) { } else { } if((result=copy_to_user(buf,str_test,count_driver))==0)read_num=count_driver; read_num=0; else if((result=copy_to_user(buf,str_test,count))==0)read_num=count; read_num=0; else printk("read start!\n"); if(access_ok(VERIFY_WRITE,buf,count) == -EFAULT) return -EFAULT;

该函数的功能正好与write相反,从这段内存空间中读取数据,当读取的数据个数不超过内存中已存的数据个数时就直接复制,但当超过时,则只能复制内存中已有的数据。函数返回值为成功读取的数据的个数。

(6)将test.c文件通过gcc编译后生成test.o模块,通过insmod命令将其加载到内核中。然后通过mknod命令在/dev目录下创建设备节点,如下所示的命令:

gcc -DMODULE -D__KERNEL__ -I /usr/src/linux-2.4.20/include -c test.c

insmod test.o

mknod /dev/test c 254 0

c表示字符设备,254为主设备号,0为次设备号。

为了测试驱动程序是否正常运行,编写了如下两个程序:test_w.c和test_r.c. Test_w.c为:

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

int main(void)

{

}

Test_r.c为:

#include<stdio.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

int main(void) close(testdev); return 0; printf("write into driver success\esult=%d,and the buf = %s\n",result,buf); if((result=write(testdev,buf,26)) < -1) {} printf("write failed\n"); return -1; int i; int testdev; int result=2,resultr; char buf[27]={'\0'}; testdev = open("/dev/test",O_RDWR); if(testdev < 0) {} printf("open ok\n"); buf[0]='a'; for(i=1;i<26;i++) buf[i]=buf[0]+i; printf("Cann't open file\n"); return 1;

相关热词搜索:函数 接收 驱动 数据 linux linux驱动 remove函数 linux下串口接收数据

相关文章
最新文章

Copyright © 2008 - 2017 版权所有 博文学习网

工业和信息化部 湘ICP备09005888号-2