S3C2440驱动简析——DM9000网卡驱动(2)

     经过本系列第一篇博文对DM9000网卡驱动的框架解释之后,接下来就应该按模块来分析这个对新手来说的“庞然大物”了。本文先解释.driver 和.remove 这两条分支吧。什么?不知道那两个东东是干什么用的?请先看小弟这系列的第一篇博文吧(http://blog.csdn.net/jarvis_xian/archive/2011/06/10/6537446.aspx)。

 

在介绍那两条分支之前,我们最好还是遵循分析驱动程序的步骤吧,先找到“入口”和“出口”,方能进可攻退可守!

static int __init dm9000_init(void) { printk(KERN_INFO "%s Ethernet Driver, V%s/n", CARDNAME, DRV_VERSION); return platform_driver_register(&dm9000_driver); } static void __exit dm9000_cleanup(void) { platform_driver_unregister(&dm9000_driver); } module_init(dm9000_init); module_exit(dm9000_cleanup);

 

由此可看出DM9000是一个平台虚拟总线驱动。它的platform_driver 正是函数参数dm9000_driver

dm9000_driver:

static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, .pm = &dm9000_drv_pm_ops, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), };

这里就是我们上文所提及的三个分支:.driver  .probe  .remove  ,其中 .probe留待接下来的博文再做详细分析,本文先讨论.driver 和.remove 。我们看到.driver结构体内最重要的应当看成员.pm,其赋值dm9000_drv_pm_ops代码如下

static const struct dev_pm_ops dm9000_drv_pm_ops = { .suspend = dm9000_drv_suspend, .resume = dm9000_drv_resume, };

 

即提供两个功能函数dm9000_drv_suspend 和dm9000_drv_resume,逐一分析如下:

 

1.dm9000_drv_suspend:

static int dm9000_drv_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db; if (ndev) { db = netdev_priv(ndev); db->in_suspend = 1; if (!netif_running(ndev)) return 0; netif_device_detach(ndev); /* only shutdown if not using WoL */ if (!db->wake_state) dm9000_shutdown(ndev); } return 0; }

本函数作用是挂起网卡接口,其中最核心的动作在于netif_device_detach(ndev);

void netif_device_detach(struct net_device *dev) { if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)) { netif_tx_stop_all_queues(dev); } }

netif_device_detach函数顾名思义,完成临时删除设备的动作。函数首先判断设备是否属于连接状态和运行状态(缺一不可),然后就执行netif_tx_stop_all_queues函数,删除设备实则即为停止该设备所有工作队列,并非物理上的删除。

 

2.dm9000_drv_resume

static int dm9000_drv_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = platform_get_drvdata(pdev); board_info_t *db = netdev_priv(ndev); if (ndev) { if (netif_running(ndev)) { /* reset if we were not in wake mode to ensure if * the device was powered off it is in a known state */ if (!db->wake_state) { dm9000_reset(db); dm9000_init_dm9000(ndev); } netif_device_attach(ndev); } db->in_suspend = 0; } return 0; }

函数完成恢复接口的功能,主要来看netif_device_attach(ndev);
void netif_device_attach(struct net_device *dev) { if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && netif_running(dev)) { netif_tx_wake_all_queues(dev); __netdev_watchdog_up(dev); } }

跟netif_device_detach函数对应,本函数实际完成把工作队列重新唤醒,并唤醒网络接口的看门狗。

 

3.dm9000_drv_remove

static int __devexit dm9000_drv_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); //释放注册的网络接口 dm9000_release_board(pdev, netdev_priv(ndev)); //释放资源 free_netdev(ndev); // 释放结构体 dev_dbg(&pdev->dev, "released and freed device/n"); return 0; }

跟以往的remove函数相似,都是很有礼貌地把自己所占用的资源归还给内核。试想如果各个模块并不是这么有礼貌的话,一个系统长时间运行,系统资源总有耗竭之时,到时等待我们的就只有崩溃。所以礼让不仅“生存”在我们日常生活当中,在Linux系统里也能很好地把这个优良特质显现出来!

 

本文内容相对简单,权当热身,后面博文将会分析.probe那一系列的函数及其操作,敬请期待~

 

 

 

本系列课程链接地址

DM9000网卡驱动(1)http://blog.csdn.net/jarvis_xian/archive/2011/06/10/6537446.aspx
DM9000网卡驱动(2)http://blog.csdn.net/jarvis_xian/archive/2011/06/12/6539931.aspx
DM9000网卡驱动(3)http://blog.csdn.net/jarvis_xian/archive/2011/06/13/6542411.aspx
DM9000网卡驱动(4)http://blog.csdn.net/jarvis_xian/archive/2011/06/15/6545109.aspx
DM9000网卡驱动(5)http://blog.csdn.net/jarvis_xian/archive/2011/06/15/6547203.aspx

 

你可能感兴趣的:(S3C2440驱动简析——DM9000网卡驱动(2))