日本a√视频在线,久久青青亚洲国产,亚洲一区欧美二区,免费g片在线观看网站

        <style id="k3y6c"><u id="k3y6c"></u></style>
        <s id="k3y6c"></s>
        <mark id="k3y6c"></mark>
          
          

          <mark id="k3y6c"></mark>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > Linux串口上網(wǎng)的程序實現(xiàn)方法

          Linux串口上網(wǎng)的程序實現(xiàn)方法

          作者: 時間:2011-05-10 來源:網(wǎng)絡 收藏
          操作int device_open(struct inode *inode,struct file *file)是設備節(jié)點上的第一個操作,如果多個設備共享這一個操作函數(shù),必須區(qū)分設備的設備號。我們使用inode->i_rdev >> 8 語句獲得設備的主設備號,本文中的接收設備主設備號是200,發(fā)送設備號是201。每個字符設備的file>private_data指向打開設備時候使用的file結構,private_data實際上可以指向用戶定義的任何結構,這里只指向我們自己定義的struct ed_device,用來保存字符設備的一些基本信息,比如設備名、內(nèi)核緩存區(qū)等。 操作ssize_t device_read(struct file *file,char *buffer,size_t length, loff_t *offset)是讀取設備數(shù)據(jù)的操作。device_read()結構如圖4所示。 圖4 從設備中讀取數(shù)據(jù)(用戶空間調用read()系統(tǒng)調用)的時候,需要從內(nèi)核空間把數(shù)據(jù)拷貝到用戶空間,copy_to_user()可完成此功能,它和memcpy()此類函數(shù)有本質的區(qū)別,memcpy()不能完成不同用戶空間數(shù)據(jù)的交換。如果需要數(shù)據(jù)臨界區(qū)的保護,使用spin_lock()內(nèi)核API負責加鎖,spin_unlock()負責解鎖,防止數(shù)據(jù)污染。由于守候進程server需要不斷輪詢設備,以查詢是否有數(shù)據(jù)可讀,如果用戶進程不處于休眠狀態(tài),在用戶空間查看進程使用資源情況,發(fā)現(xiàn)server占用了很多CPU資源。所以我們改進device_read(),使之在內(nèi)核中輪詢,當發(fā)現(xiàn)當前設備沒有數(shù)據(jù)可讀取,那么就阻塞用戶進程,使用內(nèi)核API add_wait_queue()可完成此功能,這時候用戶進程并沒有占用很多CPU資源,而是處于休眠狀態(tài)。當內(nèi)核發(fā)現(xiàn)有數(shù)據(jù)可讀的時候,調用remove_wait_queue()即可喚醒等待進程,這段 代碼如下: DECLARE_WAITQUEUE(wait,current);

          本文引用地址:http://yuyingmama.com.cn/article/150775.htm

          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ù)據(jù)。拷貝數(shù)據(jù)的copy_from_user()和copy_to_user()的功能恰恰相反,它是從用戶空間拷貝數(shù)據(jù)到內(nèi)核空間,如圖5所示。

          圖 5

          編寫偽網(wǎng)絡設備驅動

          偽網(wǎng)絡驅動和字符設備驅動一樣,也必須初始化和注冊。網(wǎng)絡驅動需記錄其發(fā)送和接收數(shù)據(jù)量的統(tǒng)計信息,所以我們定義一個記錄這些信息的數(shù)據(jù)結構。

          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ù)成員。2.4.x 使用的網(wǎng)絡數(shù)據(jù)狀態(tài)統(tǒng)計結構是struct net_device_stats,而 2.2.x則使用的是struct enet_statistics。同樣,對控制網(wǎng)絡接口設備的設備結構也有不同的定義:2.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)絡驅動程序的也需要初始化和注冊。和字符設備的注冊不同之處是,它使用的是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)絡接口的名字為ed0,如果本網(wǎng)絡設備被加載,使用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)絡接口沒有Interrupt和Base address,這是因為這個偽網(wǎng)絡接口不和硬件打交道,也沒有分配中斷號和IO基址。否則,如果你看一個實實在在的網(wǎng)絡接口(如下面的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結構,只有ednet_init()初始化成功后,系統(tǒng)才被加入到設備鏈表中。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相關文章:linux教程




          評論


          相關推薦

          技術專區(qū)

          關閉