【Linux高级驱动】如何分析并移植网卡驱动
dm9000的驅動分析
m9000_init?platform_driver_register(&dm9000_driver);
dm9000_probe
?/*獲取平臺數據*/
?struct dm9000_plat_data *pdata = pdev->dev.platform_data;
?/*表示一個網絡設備*/
?struct net_device *ndev;
?/*為網絡設備分配空間*/
?ndev = alloc_etherdev(sizeof(struct board_info));
?/*獲取資源*/
?db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
?db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
?db->irq_res??= platform_get_resource(pdev, IORESOURCE_IRQ, 0);
?/*映射地址端口*/
?db->io_addr = ioremap(db->addr_res->start, iosize);
?/*映射數據端口*/
?db->io_data = ioremap(db->data_res->start, iosize);
?/*硬件相關的操作*/
?/*1.設置讀寫操作函數*/
?dm9000_set_io(db, 2);
??case 2:
??db->dumpblk = dm9000_dumpblk_16bit;
??db->outblk??= dm9000_outblk_16bit;
??db->inblk???= dm9000_inblk_16bit;
??break;
?
?/*2.復位 */
?dm9000_reset(db);
?/*3.讀dm9000的ID號 */
?id_val??= ior(db, DM9000_VIDL);
?id_val |= (u32)ior(db, DM9000_VIDH) << 8;
?id_val |= (u32)ior(db, DM9000_PIDL) << 16;
?id_val |= (u32)ior(db, DM9000_PIDH) << 24;
?/* 獲取芯片型號 */
?id_val = ior(db, DM9000_CHIPR);
?ether_setup(ndev);
?/*設置操作方法*/
?ndev->netdev_ops??= &dm9000_netdev_ops;
?/*注冊網絡設備*/
?register_netdev(ndev);???//register_chrdev
?
cs8900a網卡驅動分析
/*分配一個網絡設備*/struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
dev->irq = irq;
dev->base_addr = io;
cs89x0_probe1(dev, io, 1);
?/*識別芯片*/
?/*操作方法的設置*/
?dev->netdev_ops = &net_ops;
?/*注冊網絡設備*/
?register_netdev(dev);
static const struct net_device_ops dm9000_netdev_ops = {
?.ndo_open????= dm9000_open,???//必須的
?.ndo_stop????= dm9000_stop,???//必須的
?.ndo_start_xmit???= dm9000_start_xmit, //必須的
?.ndo_tx_timeout???= dm9000_timeout,??//必須的
?.ndo_set_multicast_list = dm9000_hash_table,
?.ndo_do_ioctl???= dm9000_ioctl,
?.ndo_change_mtu???= eth_change_mtu,
?.ndo_validate_addr??= eth_validate_addr,
?.ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
?.ndo_poll_controller = dm9000_poll_controller,
#endif
};
?
網卡驅動的數據接收發送流程?
初始化設備
dm9000_open(struct net_device *dev){
??if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
??return -EAGAIN;
??/* Initialize DM9000 board */
??dm9000_reset(db);
????/* RESET device */
????writeb(DM9000_NCR, db->io_addr);
????udelay(200);
????writeb(NCR_RST, db->io_data);
????udelay(200);
??/* dm9000的初始化,芯片廠商會支持 */
??dm9000_init_dm9000(dev);
??
??/* 啟動發送隊列 */
??netif_start_queue(dev);
}
數據接收流程
dm9000_interrupt(int irq, void *dev_id)?/* Save previous register address */
?reg_save = readb(db->io_addr);
?/* Disable all interrupts */
?iow(db, DM9000_IMR, IMR_PAR);
?/* Got DM9000 interrupt status */
?int_status = ior(db, DM9000_ISR); /* Got ISR */
?iow(db, DM9000_ISR, int_status); /* Clear ISR status */
?/* Received the coming packet 讀中斷*/
?if (int_status & ISR_PRS)
??dm9000_rx(dev);
???
???ior(db, DM9000_MRCMDX); /* Dummy read 地址不自動增加*/
???rxbyte = readb(db->io_data);
???if (rxbyte & DM9000_PKT_ERR) {
????dev_warn(db->dev, "status check fail: %d\n", rxbyte);
????iow(db, DM9000_RCR, 0x00);??/* Stop Device */
????iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
????return;
???}
???
???writeb(DM9000_MRCMD, db->io_addr);??/*地址自動增加的*/
???/* 讀取狀態信息 */
???(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); //dm9000_inblk_16bit
???RxLen = le16_to_cpu(rxhdr.RxLen);
???/*數據的狀態判斷*/
???if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
??????????RSR_PLE | RSR_RWTO |
??????????RSR_LCS | RSR_RF)) {
???struct sk_buff *skb;
???skb = dev_alloc_skb(RxLen + 4))???/*分配一個sk_buff數據包*/
???skb_reserve(skb, 2);??//data指針和tail指針同時下移??
???rdptr = (u8 *) skb_put(skb, RxLen - 4);
???(db->inblk)(db->io_data, rdptr, RxLen);??//dm9000_inblk_16bit???//讀真正的有效數據(MAC頭,TCP頭,IP頭,網絡數據)
???dev->stats.rx_bytes += RxLen;
???/* Pass to upper layer,去掉MAC頭 */
???skb->protocol = eth_type_trans(skb, dev);
???/* 將數據上報到上層 */
???netif_rx(skb);
???dev->stats.rx_packets++;
數據發送流程
sk_buffdm9000_start_xmit
?/* 將數據寫入到DM9000的SRAM中 */
?/* Move data to DM9000 TX RAM */
?writeb(DM9000_MWCMD, db->io_addr);????//設置為自動增加
?//dm9000_outblk_16bit
?(db->outblk)(db->io_data, skb->data, skb->len);???//dm9000_outblk_16bit
?dev->stats.tx_bytes += skb->len;
?db->tx_pkt_cnt++;
?/*設置發送屬性*/
?dm9000_send_packet(struct net_device *dev,
??????????int ip_summed,
??????????u16 pkt_len)
??/*指定數據包的長度*/
??iow(dm, DM9000_TXPLL, pkt_len);
??iow(dm, DM9000_TXPLH, pkt_len >> 8);
??/*啟動發送:數據發送完成,產生中斷*/
??iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
?netif_stop_queue(dev);
?
dm9000_interrupt(int irq, void *dev_id)
?/* Save previous register address */
?reg_save = readb(db->io_addr);???//讓他不自動增加
?/* 關中斷 */
?iow(db, DM9000_IMR, IMR_PAR);
?
?/*獲取中斷狀態*/
?int_status = ior(db, DM9000_ISR); /* Got ISR */
?iow(db, DM9000_ISR, int_status); /* Clear ISR status */
?/* Trnasmit Interrupt check,數據發送完成 */
?if (int_status & ISR_PTS)
??dm9000_tx_done(dev, db);
???db->tx_pkt_cnt--;
???dev->stats.tx_packets++;
???if (db->tx_pkt_cnt > 0)
????dm9000_send_packet(dev, db->queue_ip_summed,db->queue_pkt_len);
?????/*指定數據包的長度*/
?????iow(dm, DM9000_TXPLL, pkt_len);
?????iow(dm, DM9000_TXPLH, pkt_len >> 8);
?????/*啟動發送:數據發送完成,產生中斷*/
?????iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
???netif_wake_queue(dev);
?/* Re-enable interrupt mask */
?iow(db, DM9000_IMR, db->imr_all);
?/* Restore previous register address */
?writeb(reg_save, db->io_addr);??//恢復為自動增加
?
怎么寫網卡驅動
1.cs89x0.c
1.1 分配一個net_device結構體
?????alloc_etherdev
1.2 設置
dev->open???????= net_open;????dev->stop???????= net_close;
????dev->tx_timeout?????= net_timeout;
????dev->watchdog_timeo = HZ;
????dev->hard_start_xmit????= net_send_packet;
????dev->get_stats??????= net_get_stats;
????dev->set_multicast_list = set_multicast_list;
????dev->set_mac_address????= set_mac_address;
1.3 注冊
????register_netdev
2. DM9000.c
2.1 分配一個net_device結構體
??? ndev = alloc_etherdev(sizeof (struct board_info));
2.2 設置
???
????ndev->open???????= &dm9000_open;
????ndev->hard_start_xmit????= &dm9000_start_xmit;
????ndev->tx_timeout?????????= &dm9000_timeout;
????ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
????ndev->stop???????= &dm9000_stop;
????ndev->get_stats??????= &dm9000_get_stats;
????ndev->set_multicast_list = &dm9000_hash_table;
2.3 注冊
??? ret = register_netdev(ndev);
任何設備的核心都是收發數據
1. 發數據:
?? 上層要發送數據時,構造一個sk_buff,然后調用net_device的hard_start_xmit來發送
2. 收數據:
?? 網卡收到數據后,發生中斷
?? 在中斷服務程序里:
?? 從硬件上讀出數據,然后構造一個sk_buff,上報:
a. 分配一個sk_buff結構體:
??? dev_alloc_skb
b. 使用硬件上得到數據填充這個結構體
c. 上報:netif_rx
測試方法
1. 編譯/安裝驅動 farsight_net_1.c
ifconfig fs_net0 up???ifconfig fs_net0 192.188.1.1
???ping 192.188.1.1 成功,證明ping自己的話,不經過硬件
???ping 192.188.1.2 多次調用fsnet_hard_start_tx?
???PING 192.188.1.2 (192.188.1.2): 56 data bytes
???fsnet_hard_start_tx?
???fsnet_hard_start_tx????
?? 再次ifconfig發現fs_net0的rx/tx都是0
2. 編譯/安裝驅動 farsight_net_2.c: 添加統計信息
3. 編譯/安裝驅動 farsight_net_3.c: 設MAC地址
?? ifconfig fs_net0
?? ifconfig???????? 可以看到MAC地址
4. 編譯/安裝驅動 farsight_net_4.c: 構造ping的返回包
?? ifconfig fs_net0 up
?? ifconfig fs_net0 192.188.1.1
?? ping 192.188.1.2??????????????? 成功
?
怎么移植網卡驅動
????網卡基本上都是內存接口(ram-like)
????1. 根據原理圖確定訪問地址, 在驅動里修改相應項
????2. 為了能通過這些地址訪問網卡,對于2410還要設置memory controller
?? 比如設置位寬、時間參數
????3. 根據原理圖確定中斷號, 在驅動里修改相應項(包括中斷號、中斷觸發方式(高/低有效))
?
?@成鵬致遠
(blogs:http://lcw.cnblogs.com)
(email:wwwlllll@126.com)
(qq:552158509)
轉載于:https://www.cnblogs.com/lcw/p/3802633.html
總結
以上是生活随笔為你收集整理的【Linux高级驱动】如何分析并移植网卡驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 汉字转html实体符号js_js转htm
- 下一篇: AngularJS基础01 从Hell