Linux串口上网的程序实现方法
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)) )
printk(ednet: error %i registering pseudo network device %sn,
err, ednet_dev.name);
return err;
}
ednet_dev的name域是接口名,ednet_module_init()中赋予网络接口的名字为ed0,如果本网络设备被加载,使用ifconfig命令可以看到ed0。
[root@localhost pku]# /sbin/ifconfig
ed0 Link encap:Ethernet HWaddr 00:45:44:30:30:30
inet addr:192.168.3.9 Bcast:192.168.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
我们看到我们的伪网络接口没有Interrupt和Base address,这是因为这个伪网络接口不和硬件打交道,也没有分配中断号和IO基址。否则,如果你看一个实实在在的网络接口(如下面的eth1),可以看到它的Interrupt号是11和IO Base address是0xa000。
eth1 Link encap:Ethernet HWaddr 50:78:4C:43:1D:01
inet addr:192.168.21.202 Bcast:192.168.21.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:356523 errors:0 dropped:0 overruns:0 frame:0
TX packets:266 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:21542043 (20.5 Mb) TX bytes:19510 (19.0 Kb)
Interrupt:11 Base address:0xa000
ednet_dev的init域是一个函数指针,指向用户定义的ednet_init()例程。ednet_init()添充net_device结构,只有ednet_init()初始化成功后,系统才被加入到设备链表中。ednet_dev的初始化例程ednet_init()如下:
#ifdef LINUX_24
int ednet_init(struct net_device *dev)
#else
int ednet_init(struct device *dev)
#endif
{
ether_setup(dev);
dev->open = ednet_open;
dev->stop = ednet_release;
dev->hard_start_xmit = ednet_tx;
dev->get_stats = ednet_stats;
dev->change_mtu = ednet_change_mtu;
#ifdef LINUX_24
dev->hard_header = ednet_header;
#endif
dev->rebuild_header = ednet_rebuild_header;
#ifdef LINUX_24
dev->tx_timeout = ednet_tx_timeout;
dev->watchdog_timeo = timeout;
#endif
/* We do not need the ARP protocol. */
dev->flags |= IFF_NOARP;
#ifndef LINUX_20
dev->hard_header_cache = NULL;
#endif
#ifdef LINUX_24
SET_MODULE_OWNER(dev);
#endif
dev->priv = kmalloc(sizeof(struct ednet_priv), GFP_KERNEL);
if (dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct ednet_priv));
spin_lock_init( ((struct ednet_priv *) dev->priv)->lock);
return 0;
}
linux操作系统文章专题:linux操作系统详解(linux不再难懂)linux相关文章:linux教程
评论