360 likes | 507 Views
在 Linux 安裝 U SB 無線網卡. Proposal Background. 動機. 有一張號稱支援 Linux 的 USB 無線網卡 雖然有附驅動程式但總是不能成功編譯 網路上有搜尋到幾種修改 driver 的方法但有待驗證. USB 無線網卡. PLANEX GW-US54GZL IEEE802.11g USB2.0 攜帶型無線網路卡 http://www.planex.com.tw/product/soho/wireless/gw-us54gzl.htm 使用 ZD1211 晶片
E N D
在Linux安裝USB無線網卡 Proposal Background
動機 • 有一張號稱支援Linux的USB無線網卡 • 雖然有附驅動程式但總是不能成功編譯 • 網路上有搜尋到幾種修改driver的方法但有待驗證
USB無線網卡 • PLANEX GW-US54GZL IEEE802.11g USB2.0 攜帶型無線網路卡 • http://www.planex.com.tw/product/soho/wireless/gw-us54gzl.htm • 使用ZD1211晶片 • http://www.zydas.com.tw/product/ZD1211.asp • 支援kernel 2.4.x與2.6.x
選用哪個driver好呢? • 驅動程式來源 • From Planex (http://www.planex.com.tw) • http://www.planex.com.tw/download/wireless/gw-us54gzl.htm • Driver version : 2.4.0.0 • From ZyDas (http://www.zydas.com.tw) • http://www.zydas.com.tw/downloads/download-1211.asp • Driver version : 2.8.0.0 • 由於ZyDas公司提供的driver比較新,所以就選用它了
沒有kernel source怎麼辦? • http://rpmfind.net/linux/RPM/ • 安裝kernel devel即可
ZyDas的driver • 第一步:當然是把它的tarball給解開啦 • 第二步:必須要修改它的Makefile,將kernel source的位址寫上去 • 第三步:make 與 make install !! • 它含有兩個晶片的driver:zd1211與zd1211b。使用make ZD1211REV_B=0就只會編譯zd1211 • 但是在hotplug時似乎不會自動載入,必須手動modprobe
ZD1211的driver載入 • > modprobe –v zd1211 • > lsmod • Module Size Used by • zd1211 263504 0 • > tail /var/log/messages
Debug工具 • 附有兩個debug工具 • apdbg • menudbg • 安裝方法 • > make debug
目標 • 將USB無線網卡在Linux上成功安裝運作 • hotplug • 了解USB無線網卡在Linux的driver架構 • src/zdusb.c
在Linux安裝USB無線網卡 Final Project
hotplug問題出在哪? • 由於網路上有人抱怨使用此晶片的廠商與產品太多,driver常來不及更新 • 因此假設問題出在Vendor ID與Device ID
取得USB裝置的基本資料 (1/2) • USB裝置在連接到電腦時, /var/log/messages 會有訊息提示,如下 • usb 4-3: new high speed USB device using ehci_hcd and address 9 • ehci_hcd : USB 2.0 Enhanced Host Controller • 4 : bus number • 9 : device number
取得USB裝置的基本資料 (2/2) • USB裝置在連接到電腦後,資訊會更新在 /proc/bus/usb/devices 這個檔案 • T: Bus=04 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 9 Spd=480 MxCh= 0 • D: Ver= 2.00 Cls=ff(vend.) Sub=ff Prot=ff MxPS=64 #Cfgs= 1 • P: Vendor=2019ProdID=c007 Rev=47.21 • S: Manufacturer=PLANEX • S: Product=PLANEX GW-US54GZL • C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=500mA • I: If#= 0 Alt= 0 #EPs= 4 Cls=ff(vend.) Sub=00 Prot=00 Driver=zd1211 • E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms • E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms • E: Ad=83(I) Atr=03(Int.) MxPS= 64 Ivl=125us • E: Ad=04(O) Atr=03(Int.) MxPS= 64 Ivl=125us
HotPlug修復 – zdusb.c (1/3) static struct usb_device_id zd1211_ids [] = { ……(省略)…… { USB_DEVICE(VENDOR_3COM, PRODUCT_A727) }, { USB_DEVICE(0x2019, 0xc007) }, //加入這項 { USB_DEVICE(0x2019, 0xc008) }, ……(省略)……
HotPlug修復 – zdusb.c (2/3) • 將zdusb.c修改完成後重新編譯出模組 • 測試結果…… 成功!!!!
HotPlug修復 – zdusb.c (3/3) [root@Tony ~]# tail -17 /var/log/messages kernel: usb 4-3: new high speed USB device using ehci_hcd and address 11 kernel: usb 4-3: configuration #1 chosen from 1 choice kernel: kernel: _____ ____ _ ____ kernel: |__ / _| _ \ / \ / ___| kernel: / / | | | | | |/ _ \ \___ \ kernel: / /| |_| | |_| / ___ \ ___) | kernel: /____\__, |____/_/ \_\____/ kernel: |___/ kernel: zd1211 - version 2.8.0.0 kernel: Release Ver = 4721 kernel: EEPORM Ver = 4330 kernel: PA type: 0 kernel: AiroHa AL2230RF kernel: AllowedChannel = 000107ff kernel: Region:48 kernel: usbcore: registered new driver zd1211
無線網卡運作情形 (1/2) [root@Tony ~]# ifconfig eth2 eth2 Link encap:Ethernet HWaddr 00:90:CC:CC:CE:84 inet addr:192.168.1.50 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::290:ccff:fecc:ce84/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:6 errors:0 dropped:0 overruns:0 frame:0 TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:491 (491.0 b) TX bytes:458 (458.0 b)
無線網卡運作情形 (2/2) [root@Tony ~]# iwconfig eth2 essid CD0 [root@Tony ~]# iwconfig eth2 eth2 802.11b/g NIC ESSID:"CD0" Mode:Managed Frequency=2.462 GHz Access Point: 00:80:C8:37:BF:77 Bit Rate:11 Mb/s Retry:off RTS thr=2432 B Fragment thr:off Encryption key:off Power Management:off Link Quality:75/100 Signal level:72/100 Noise level:7/100 Rx invalid nwid:0 Rx invalid crypt:0 Rx invalid frag:0 Tx excessive retries:261 Invalid misc:3 Missed beacon:0
usbnet.c /drivers/usb/net/usbnet.c Author : David Brownell USB Network Driver Framework
usbnet.c (1/13) • int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) • 判斷endpoint • 方向(bEndpointAddress) (in/out) • 種類(bmAttributes) (USB_ENDPOINT_XFER_INT/BULK)
usbnet.c (2/13) • static int init_status (struct usbnet *dev, struct usb_interface *intf) • 初始化 • 讀取並設定設定最大封包、速度 • 包含kmalloc • void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) • 收到封包後更新統計資料
usbnet.c (3/13) • static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list) • Delaying (spinlock) • void usbnet_defer_kevent (struct usbnet *dev, int work) • Delaying (kevent)
usbnet.c (4/13) • static int usbnet_change_mtu (struct net_device *net, int new_mtu) • 改變MTU • static struct net_device_stats *usbnet_get_stats (struct net_device *net) • 回傳usbnet結構中stat部分
usbnet.c (5/13) • static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) • 準備urb(USB Request Block) • 使用usb_submit_urb()將bulk urb送出至USB core或掛到queue尾端 • static void rx_complete (struct urb *urb, struct pt_regs *regs) • 根據urb結構的status變數得知狀態並做各種處理,最後用rx_submit()將urb送出
usbnet.c (6/13) • static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) • 使用usb_unlink_urb() • static int usbnet_stop (struct net_device *net) • usbnet結束時的處理 • 使用remove_wait_queue()與usb_kill_urb()將urb清乾淨
usbnet.c (7/13) • static int usbnet_open (struct net_device *net) • usbnet的開啟與初始 • void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) • modinfo
usbnet.c (8/13) • static void kevent (void *data) • 判斷usbnet結構的flag得到狀態 • 對以下event狀態進行動作 • #define EVENT_TX_HALT 0 • #define EVENT_RX_HALT 1 • #define EVENT_RX_MEMORY 2 • #define EVENT_LINK_RESET 4
usbnet.c (9/13) • static void tx_complete (struct urb *urb, struct pt_regs *regs) • 根據urb結構status變數得狀態並做各種處理 • 沒有將urb送出 • static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) • usb_fill_bulk_urb()準備bulk urb • usb_submit_urb()送出urb
usbnet.c (10/13) • Int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) • 呼叫usbnet_get_endpoints()進行初始動作 • usb_set_intfdata()儲存data pointer • netif_device_attach()
usbnet.c (11/13) • void usbnet_disconnect (struct usb_interface *intf) • usb_get_intfdata()查閱資料 • usb_set_intfdata()將device部份設為NULL • unregister_netdev()
usbnet.c (12/13) • int usbnet_suspend (struct usb_interface *intf, pm_message_t message) • usb_get_intfdata()查閱資料 • netif_device_detach() • unlink_urbs()移除rx/tx的urb
usbnet.c (13/13) • int usbnet_resume (struct usb_interface *intf) • usb_get_intfdata()查閱資料 • netif_device_attach()
linux/netdevice.h static inline void netif_device_attach(struct net_device *dev) { if(!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)){ netif_wake_queue(dev); netdev_watchdog_up(dev); } }
linux/netdevice.h static inline void netif_device_detach(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)) { netif_stop_queue(dev); } }