歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux設備驅動工程師之路——DM9000網卡驅動程序分析

DM9000是開發板經采用的網絡芯片,是一種高度集成而且功耗很低的高速網絡控制器,可以和CPU直連,支持10/100M以太網連接,芯片內部自帶16K SARM(3KB用來發送,13KB用來接收).

1.模塊初始化

  1. static struct platform_driver dm9000_driver = {  
  2.     .driver = {  
  3.         .name    = "dm9000",  
  4.         .owner   = THIS_MODULE,  
  5.     },  
  6.     .probe   = dm9000_probe,  
  7.     .remove  = __devexit_p(dm9000_drv_remove),  
  8.     .suspend = dm9000_drv_suspend,  
  9.     .resume  = dm9000_drv_resume,  
  10. };  
  11.   
  12. static int __init  
  13. dm9000_init(void)  
  14. {  
  15.     printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);  
  16.   
  17.     return platform_driver_register(&dm9000_driver);  
  18. }  

模塊初始化完成了基於platfrom平台的DM9000網卡驅動的注冊,當DM9000網卡找到其對應的能處理的platform設備後調用probe函數。

2.DM9000網卡初始化 

在probe函數中完成了對DM9000網卡的初始化

DM9000的特性:DM9000地址信號和數據信號復用使用CMD引腳區分它們(CMD為低是讀寫DM900地址寄存器,CMD為高時讀寫DM9000數據寄存器),訪問DM9000內部寄存器時,先將CMD置低,寫DM900地址寄存器,然後將CMD置高,讀寫DM9000數據寄存器。

  1. static int __devinit  
  2. dm9000_probe(struct platform_device *pdev)  
  3. {     
  4.     struct dm9000_plat_data *pdata = pdev->dev.platform_data;  
  5.     struct board_info *db;  /* Point a board information structure */  
  6.     struct net_device *ndev;  
  7.     const unsigned char *mac_src;  
  8.     int ret = 0;  
  9.     int iosize;  
  10.     int i;  
  11.     u32 id_val;  
  12.   
  13.     /* Init network device */  
  14.     //申請net_device結構  
  15.     ndev = alloc_etherdev(sizeof(struct board_info));  
  16.     if (!ndev) {  
  17.         dev_err(&pdev->dev, "could not allocate device.\n");  
  18.         return -ENOMEM;  
  19.     }  
  20.   
  21.   
  22. //將net_device的parent指針指向platform_device對象,表示該設備掛載platform設備上。  
  23.     SET_NETDEV_DEV(ndev, &pdev->dev);   
  24.   
  25.     dev_dbg(&pdev->dev, "dm9000_probe()\n");  
  26.   
  27.     /* setup board info structure */  
  28.     //獲取net_device私有數據結構指針  
  29.     db = netdev_priv(ndev);  
  30.     memset(db, 0, sizeof(*db));  
  31.   
  32.     //設置相關設備  
  33.     db->dev = &pdev->dev;  
  34.     db->ndevndev = ndev;  
  35.   
  36.     spin_lock_init(&db->lock);  
  37.     mutex_init(&db->addr_lock);  
  38.   
  39.     INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);  
  40.       
  41.     //獲取平台設備資源。包括DM9000地址寄存器地址,DM9000數據寄存器地址,和DM900所占用的中斷號  
  42.   
  43.     db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  44.     db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);  
  45.     db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  
  46.   
  47.     if (db->addr_res == NULL || db->data_res == NULL ||  
  48.         db->irq_res == NULL) {  
  49.         dev_err(db->dev, "insufficient resources\n");  
  50.         ret = -ENOENT;  
  51.         goto out;  
  52.     }  
  53.   
  54.     //申請地址寄存器IO內存區域並映射  
  55.     iosize = res_size(db->addr_res);  
  56.     db->addr_req = request_mem_region(db->addr_res->start, iosize,  
  57.                       pdev->name);  
  58.   
  59.     if (db->addr_req == NULL) {  
  60.         dev_err(db->dev, "cannot claim address reg area\n");  
  61.         ret = -EIO;  
  62.         goto out;  
  63.     }  
  64.   
  65.     db->io_addr = ioremap(db->addr_res->start, iosize);  
  66.   
  67.     if (db->io_addr == NULL) {  
  68.         dev_err(db->dev, "failed to ioremap address reg\n");  
  69.         ret = -EINVAL;  
  70.         goto out;  
  71.     }  
  72.   
  73.     //申請數據寄存器IO內存區域並映射  
  74.     iosize = res_size(db->data_res);  
  75.     db->data_req = request_mem_region(db->data_res->start, iosize,  
  76.                       pdev->name);  
  77.   
  78.     if (db->data_req == NULL) {  
  79.         dev_err(db->dev, "cannot claim data reg area\n");  
  80.         ret = -EIO;  
  81.         goto out;  
  82.     }  
  83.   
  84.     db->io_data = ioremap(db->data_res->start, iosize);  
  85.   
  86.     if (db->io_data == NULL) {  
  87.         dev_err(db->dev, "failed to ioremap data reg\n");  
  88.         ret = -EINVAL;  
  89.         goto out;  
  90.     }  
  91.   
  92.     /* fill in parameters for net-dev structure */  
  93.     ndev->base_addr = (unsigned long)db->io_addr;  
  94.     ndev->irq    = db->irq_res->start;  
  95.   
  96.     //設置數據位寬  
  97.     /* ensure at least we have a default set of IO routines */  
  98.     dm9000_set_io(db, iosize);  
  99.   
  100.     /* check to see if anything is being over-ridden */  
  101.     if (pdata != NULL) {  
  102.         /* check to see if the driver wants to over-ride the  
  103.          * default IO width */  
  104.   
  105.         if (pdata->flags & DM9000_PLATF_8BITONLY)  
  106.             dm9000_set_io(db, 1);  
  107.   
  108.         if (pdata->flags & DM9000_PLATF_16BITONLY)  
  109.             dm9000_set_io(db, 2);  
  110.   
  111.         if (pdata->flags & DM9000_PLATF_32BITONLY)  
  112.             dm9000_set_io(db, 4);  
  113.   
  114.         /* check to see if there are any IO routine  
  115.          * over-rides */  
  116.   
  117.         if (pdata->inblk != NULL)  
  118.             db->inblk = pdata->inblk;  
  119.   
  120.         if (pdata->outblk != NULL)  
  121.             db->outblk = pdata->outblk;  
  122.   
  123.         if (pdata->dumpblk != NULL)  
  124.             db->dumpblk = pdata->dumpblk;  
  125.   
  126.         db->flags = pdata->flags;  
  127.     }  
  128.   
  129. #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL  
  130.     db->flags |= DM9000_PLATF_SIMPLE_PHY;  
  131. #endif  
  132.   
  133.     //復位網卡芯片  
  134.     dm9000_reset(db);  
  135.   
  136.     //讀取設備ID,判斷是否是驅動能夠處理的網卡芯片  
  137.     /* try multiple times, DM9000 sometimes gets the read wrong */  
  138.     for (i = 0; i < 8; i++) {  
  139.         id_val  = ior(db, DM9000_VIDL);  
  140.         id_val |= (u32)ior(db, DM9000_VIDH) << 8;  
  141.         id_val |= (u32)ior(db, DM9000_PIDL) << 16;  
  142.         id_val |= (u32)ior(db, DM9000_PIDH) << 24;  
  143.   
  144.         if (id_val == DM9000_ID)  
  145.             break;  
  146.         dev_err(db->dev, "read wrong id 0x%08x\n", id_val);  
  147.     }  
  148.   
  149.     if (id_val != DM9000_ID) {  
  150.         dev_err(db->dev, "wrong id: 0x%08x\n", id_val);  
  151.         ret = -ENODEV;  
  152.         goto out;  
  153.     }  
  154.   
  155.     /* Identify what type of DM9000 we are working on */  
  156.   
  157.     id_val = ior(db, DM9000_CHIPR);  
  158.     dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);  
  159.   
  160.     switch (id_val) {  
  161.     case CHIPR_DM9000A:  
  162.         db->type = TYPE_DM9000A;  
  163.         break;  
  164.     case CHIPR_DM9000B:  
  165.         db->type = TYPE_DM9000B;  
  166.         break;  
  167.     default:  
  168.         dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);  
  169.         db->type = TYPE_DM9000E;  
  170.     }  
  171.   
  172.     /* from this point we assume that we have found a DM9000 */  
  173.   
  174.     /* driver system function */  
  175.     ether_setup(ndev);  
  176.   
  177.     //設置網卡芯片的接口函數  
  178.     ndev->open        = &dm9000_open;  
  179.     ndev->hard_start_xmit    = &dm9000_start_xmit;  
  180.     ndev->tx_timeout         = &dm9000_timeout;  
  181.     ndev->watchdog_timeo = msecs_to_jiffies(watchdog);  
  182.     ndev->stop        = &dm9000_stop;  
  183.     ndev->set_multicast_list = &dm9000_hash_table;  
  184.     ndev->ethtool_ops     = &dm9000_ethtool_ops;  
  185.     ndev->do_ioctl        = &dm9000_ioctl;  
  186.   
  187. #ifdef CONFIG_NET_POLL_CONTROLLER  
  188.     ndev->poll_controller     = &dm9000_poll_controller;  
  189. #endif  
  190.   
  191.     db->msg_enable       = NETIF_MSG_LINK;  
  192.     db->mii.phy_id_mask  = 0x1f;  
  193.     db->mii.reg_num_mask = 0x1f;  
  194.     db->mii.force_media  = 0;  
  195.     db->mii.full_duplex  = 0;  
  196.     db->mii.dev       = ndev;  
  197.     db->mii.mdio_read    = dm9000_phy_read;  
  198.     db->mii.mdio_write   = dm9000_phy_write;  
  199.   
  200.     mac_src = "eeprom";  
  201.   
  202.     //從EEPROM中讀取MAC地址填充dev_addr  
  203.     /* try reading the node address from the attached EEPROM */  
  204.     for (i = 0; i < 6; i += 2)  
  205.         dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);  
  206.   
  207.     if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {  
  208.         mac_src = "platform data";  
  209.         memcpy(ndev->dev_addr, pdata->dev_addr, 6);  
  210.     }  
  211.   
  212.     if (!is_valid_ether_addr(ndev->dev_addr)) {  
  213.         /* try reading from mac */  
  214.           
  215.         mac_src = "chip";  
  216.         for (i = 0; i < 6; i++)  
  217.             ndev->dev_addr[i] = ior(db, i+DM9000_PAR);  
  218.     }  
  219.   
  220.     if (!is_valid_ether_addr(ndev->dev_addr))  
  221.         dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "  
  222.              "set using ifconfig\n", ndev->name);  
  223.   
  224.     //設置平台設備驅動的dev成員為ndev。  
  225.     platform_set_drvdata(pdev, ndev);  
  226.   
  227.     //注冊網絡設備驅動  
  228.     ret = register_netdev(ndev);  
  229.   
  230.     if (ret == 0)  
  231.         printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",  
  232.                ndev->name, dm9000_type_to_char(db->type),  
  233.                db->io_addr, db->io_data, ndev->irq,  
  234.                ndev->dev_addr, mac_src);  
  235.     return 0;  
  236.   
  237. out:  
  238.     dev_err(db->dev, "not found (%d).\n", ret);  
  239.   
  240.     dm9000_release_board(pdev, db);  
  241.     free_netdev(ndev);  
  242.   
  243.     return ret;  
  244. }  

我們在來看看讀寫網卡寄存器所用的ior和iow

  1. static u8  
  2. ior(board_info_t * db, int reg)  
  3. {  
  4.     writeb(reg, db->io_addr);  
  5.     return readb(db->io_data);  
  6. }  
  7.   
  8. static void  
  9. iow(board_info_t * db, int reg, int value)  
  10. {  
  11.     writeb(reg, db->io_addr);  
  12.     writeb(value, db->io_data);  
  13. }  

可以看得出是先將要訪問的寄存器地址寫入到地址寄存器,然後在將數據寫入到數據寄存器。地址。             

Copyright © Linux教程網 All Rights Reserved