Linux串口上網(wǎng)的程序?qū)崿F(xiàn)方法
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)向設(shè)備寫入數(shù)據(jù)??截悢?shù)據(jù)的copy_from_user()和copy_to_user()的功能恰恰相反,它是從用戶空間拷貝數(shù)據(jù)到內(nèi)核空間,如圖5所示。
圖 5
編寫偽網(wǎng)絡(luò)設(shè)備驅(qū)動程序
偽網(wǎng)絡(luò)驅(qū)動程序和字符設(shè)備驅(qū)動程序一樣,也必須初始化和注冊。網(wǎng)絡(luò)驅(qū)動需記錄其發(fā)送和接收數(shù)據(jù)量的統(tǒng)計信息,所以我們定義一個記錄這些信息的數(shù)據(jù)結(jié)構(gòu)。
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個數(shù)據(jù)成員。Linux2.4.x 使用的網(wǎng)絡(luò)數(shù)據(jù)狀態(tài)統(tǒng)計結(jié)構(gòu)是struct net_device_stats,而Linux 2.2.x則使用的是struct enet_statistics。同樣,對控制網(wǎng)絡(luò)接口設(shè)備的設(shè)備結(jié)構(gòu)也有不同的定義: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
偽網(wǎng)絡(luò)驅(qū)動程序的也需要初始化和注冊。和字符設(shè)備的注冊不同之處是,它使用的是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()中賦予網(wǎng)絡(luò)接口的名字為ed0,如果本網(wǎng)絡(luò)設(shè)備被加載,使用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)
我們看到我們的偽網(wǎng)絡(luò)接口沒有Interrupt和Base address,這是因為這個偽網(wǎng)絡(luò)接口不和硬件打交道,也沒有分配中斷號和IO基址。否則,如果你看一個實實在在的網(wǎng)絡(luò)接口(如下面的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域是一個函數(shù)指針,指向用戶定義的ednet_init()例程。ednet_init()添充net_device結(jié)構(gòu),只有ednet_init()初始化成功后,系統(tǒng)才被加入到設(shè)備鏈表中。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操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
評論