??? 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)計(jì)信息,所以我們定義一個(gè)記錄這些信息的數(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個(gè)數(shù)據(jù)成員。Linux2.4.x 使用的網(wǎng)絡(luò)數(shù)據(jù)狀態(tài)統(tǒng)計(jì)結(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 "%s"\n",
?????????????????? 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,這是因?yàn)檫@個(gè)偽網(wǎng)絡(luò)接口不和硬件打交道,也沒有分配中斷號和IO基址。否則,如果你看一個(gè)實(shí)實(shí)在在的網(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域是一個(gè)函數(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;
}
??????
評論
查看更多