微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux串口上网的程序实现方法

Linux串口上网的程序实现方法

时间:05-10 来源:互联网 点击:

中定义的struct file_operations是不一样的。device_read()、device_write()、device_ioctl()、device_open()、device_release()就是需要用户自己定义的函数操作了,这几个函数是最基本的操作,如果需要设备驱动程序完成更复杂的任务,还必须编写其他struct file_operations中定义的操作。eddev_module_init()除了注册设备及其操作外,它还有初始化字符设备结构struct ed_device,分配内核缓存区所需要的空间的作用。在内核空间,分配内存空间的API函数是kmalloc()。 下面介绍一下字符设备的主要操作例程device_open()、device_release()、device_read()、devie_write()。字符设备文件操作结构ed_ops中定义的指向以上函数的函数指针的原形: device_open: int(*open)(struct inode *,struct file *)

device_release: int (*release) (struct inode *, struct file *);

device_read: ssize_t (*read) (struct file *, char *, size_t, loff_t *);

device_write: ssize_t (*write) (struct file *, const char *, size_t, loff_t *);操作int device_open(struct inode *inode,struct file *file)是设备节点上的第一个操作,如果多个设备共享这一个操作函数,必须区分设备的设备号。我们使用inode->i_rdev >> 8 语句获得设备的主设备号,本文中的接收设备主设备号是200,发送设备号是201。每个字符设备的file>private_data指向打开设备时候使用的file结构,private_data实际上可以指向用户定义的任何结构,这里只指向我们自己定义的struct ed_device,用来保存字符设备的一些基本信息,比如设备名、内核缓存区等。 操作ssize_t device_read(struct file *file,char *buffer,size_t length, loff_t *offset)是读取设备数据的操作。device_read()结构如图4所示。 图4 从设备中读取数据(用户空间调用read()系统调用)的时候,需要从内核空间把数据拷贝到用户空间,copy_to_user()可完成此功能,它和memcpy()此类函数有本质的区别,memcpy()不能完成不同用户空间数据的交换。如果需要数据临界区的保护,使用spin_lock()内核API负责加锁,spin_unlock()负责解锁,防止数据污染。由于串口守候进程server需要不断轮询设备,以查询是否有数据可读,如果用户进程不处于休眠状态,在用户空间查看进程使用资源情况,发现server占用了很多CPU资源。所以我们改进device_read(),使之在内核中轮询,当发现当前设备没有数据可读取,那么就阻塞用户进程,使用内核API add_wait_queue()可完成此功能,这时候用户进程并没有占用很多CPU资源,而是处于休眠状态。当内核发现有数据可读的时候,调用remove_wait_queue()即可唤醒等待进程,这段 代码如下: DECLARE_WAITQUEUE(wait,current);

add_wait_queue(edp->rwait,wait);

for(;;){

set_current_state(TASK_INTERRUPTIBLE);

if ( file->f_flags O_NONBLOCK)

break;

/*其他代码 */

if ( signal_pending(current))

break;

schedule();

}

set_current_state(TASK_RUNNING);

remove_wait_queue(edp->rwait,wait);

操作ssize_t device_write(struct file *file,const char *buffer, size_t length,loff_t *offset)向设备写入数据。拷贝数据的copy_from_user()和copy_to_user()的功能恰恰相反,它是从用户空间拷贝数据到内核空间,如图5所示。

图 5

编写伪网络设备驱动程序

伪网络驱动程序和字符设备驱动程序一样,也必须初始化和注册。网络驱动需记录其发送和接收数据量的统计信息,所以我们定义一个记录这些信息的数据结构。

struct ednet_priv {

#ifdef LINUX_24

struct net_device_stats stats;

#else

struct enet_statistics stats;

#endif

struct sk_buff *skb;

spinlock_t lock;

};

struct ednet_priv只有3个数据成员。Linux2.4.x 使用的网络数据状态统计结构是struct net_device_stats,而Linux 2.2.x则使用的是struct enet_statistics。同样,对控制网络接口设备的设备结构也有不同的定义:Linux2.4.x使用的是struct net_device,而Linux2.2.x却是struct device。

#ifdef LINUX_24

struct net_device ednet_dev;

#else

struct device ednet_dev;

#endif

伪网络驱动程序的也需要初始化和注册。和字符设备的注册不同之处是,它使用的是register_netdev(net_device *) kernel API。

int ednet_module_init(void)

{

int err;

strcpy(ednet_dev.name, ed0);

ednet_dev.init = ednet_init;

if ( (err = register_netdev(ednet_dev)) )

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top