Mini2440 DM9000 驱动分析(四)

来源:互联网 发布:手机淘宝首页装修尺寸 编辑:程序博客网 时间:2024/06/02 02:32

Mini2440 DM9000 驱动分析(四)

net_device_ops中方法的相应说明

/* * This structure defines the management hooks for network devices. * The following hooks can be defined; unless noted otherwise, they are * optional and can be filled with a null pointer. * * int (*ndo_init)(struct net_device *dev); *     This function is called once when network device is registered. *     The network device can use this to any late stage initializaton *     or semantic validattion. It can fail with an error code which will *     be propogated back to register_netdev * * void (*ndo_uninit)(struct net_device *dev); *     This function is called when device is unregistered or when registration *     fails. It is not called if init fails. * * int (*ndo_open)(struct net_device *dev); *     This function is called when network device transistions to the up *     state. * * int (*ndo_stop)(struct net_device *dev); *     This function is called when network device transistions to the down *     state. * * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, *                               struct net_device *dev); *Called when a packet needs to be transmitted. *Must return NETDEV_TX_OK , NETDEV_TX_BUSY. *        (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX) *Required can not be NULL. * * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); *Called to decide which queue to when device supports multiple *transmit queues. * * void (*ndo_change_rx_flags)(struct net_device *dev, int flags); *This function is called to allow device receiver to make *changes to configuration when multicast or promiscious is enabled. * * void (*ndo_set_rx_mode)(struct net_device *dev); *This function is called device changes address list filtering. * * void (*ndo_set_multicast_list)(struct net_device *dev); *This function is called when the multicast address list changes. * * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); *This function  is called when the Media Access Control address *needs to be changed. If this interface is not defined, the *mac address can not be changed. * * int (*ndo_validate_addr)(struct net_device *dev); *Test if Media Access Control address is valid for the device. * * int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); *Called when a user request an ioctl which can't be handled by *the generic interface code. If not defined ioctl's return *not supported error code. * * int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); *Used to set network devices bus interface parameters. This interface *is retained for legacy reason, new devices should use the bus *interface (PCI) for low level management. * * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); *Called when a user wants to change the Maximum Transfer Unit *of a device. If not defined, any request to change MTU will *will return an error. * * void (*ndo_tx_timeout)(struct net_device *dev); *Callback uses when the transmitter has not made any progress *for dev->watchdog ticks. * * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); *Called when a user wants to get the network device usage *statistics. If not defined, the counters in dev->stats will *be used. * * void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp); *If device support VLAN receive accleration *(ie. dev->features & NETIF_F_HW_VLAN_RX), then this function is called *when vlan groups for the device changes.  Note: grp is NULL *if no vlan's groups are being used. * * void (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid); *If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) *this function is called when a VLAN id is registered. * * void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); *If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) *this function is called when a VLAN id is unregistered. * * void (*ndo_poll_controller)(struct net_device *dev); */#define HAVE_NET_DEVICE_OPSstruct net_device_ops {int(*ndo_init)(struct net_device *dev);void(*ndo_uninit)(struct net_device *dev);int(*ndo_open)(struct net_device *dev);int(*ndo_stop)(struct net_device *dev);netdev_tx_t(*ndo_start_xmit) (struct sk_buff *skb,   struct net_device *dev);u16(*ndo_select_queue)(struct net_device *dev,    struct sk_buff *skb);#define HAVE_CHANGE_RX_FLAGSvoid(*ndo_change_rx_flags)(struct net_device *dev,       int flags);#define HAVE_SET_RX_MODEvoid(*ndo_set_rx_mode)(struct net_device *dev);#define HAVE_MULTICASTvoid(*ndo_set_multicast_list)(struct net_device *dev);#define HAVE_SET_MAC_ADDRint(*ndo_set_mac_address)(struct net_device *dev,       void *addr);#define HAVE_VALIDATE_ADDRint(*ndo_validate_addr)(struct net_device *dev);#define HAVE_PRIVATE_IOCTLint(*ndo_do_ioctl)(struct net_device *dev,        struct ifreq *ifr, int cmd);#define HAVE_SET_CONFIGint(*ndo_set_config)(struct net_device *dev,          struct ifmap *map);#define HAVE_CHANGE_MTUint(*ndo_change_mtu)(struct net_device *dev,  int new_mtu);int(*ndo_neigh_setup)(struct net_device *dev,   struct neigh_parms *);#define HAVE_TX_TIMEOUTvoid(*ndo_tx_timeout) (struct net_device *dev);struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);void(*ndo_vlan_rx_register)(struct net_device *dev,        struct vlan_group *grp);void(*ndo_vlan_rx_add_vid)(struct net_device *dev,       unsigned short vid);void(*ndo_vlan_rx_kill_vid)(struct net_device *dev,        unsigned short vid);#ifdef CONFIG_NET_POLL_CONTROLLER#define HAVE_NETDEV_POLLvoid                    (*ndo_poll_controller)(struct net_device *dev);#endif#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)int(*ndo_fcoe_enable)(struct net_device *dev);int(*ndo_fcoe_disable)(struct net_device *dev);int(*ndo_fcoe_ddp_setup)(struct net_device *dev,      u16 xid,      struct scatterlist *sgl,      unsigned int sgc);int(*ndo_fcoe_ddp_done)(struct net_device *dev,     u16 xid);#endif};

ethtool_ops 中方法的相应说明

/** * ðtool_ops - Alter and report network device settings * get_settings: Get device-specific settings * set_settings: Set device-specific settings * get_drvinfo: Report driver information * get_regs: Get device registers * get_wol: Report whether Wake-on-Lan is enabled * set_wol: Turn Wake-on-Lan on or off * get_msglevel: Report driver message level * set_msglevel: Set driver message level * nway_reset: Restart autonegotiation * get_link: Get link status * get_eeprom: Read data from the device EEPROM * set_eeprom: Write data to the device EEPROM * get_coalesce: Get interrupt coalescing parameters * set_coalesce: Set interrupt coalescing parameters * get_ringparam: Report ring sizes * set_ringparam: Set ring sizes * get_pauseparam: Report pause parameters * set_pauseparam: Set pause parameters * get_rx_csum: Report whether receive checksums are turned on or off * set_rx_csum: Turn receive checksum on or off * get_tx_csum: Report whether transmit checksums are turned on or off * set_tx_csum: Turn transmit checksums on or off * get_sg: Report whether scatter-gather is enabled * set_sg: Turn scatter-gather on or off * get_tso: Report whether TCP segmentation offload is enabled * set_tso: Turn TCP segmentation offload on or off * get_ufo: Report whether UDP fragmentation offload is enabled * set_ufo: Turn UDP fragmentation offload on or off * self_test: Run specified self-tests * get_strings: Return a set of strings that describe the requested objects  * phys_id: Identify the device * get_stats: Return statistics about the device * get_flags: get 32-bit flags bitmap * set_flags: set 32-bit flags bitmap *  * Description: * * get_settings: *@get_settings is passed an ðtool_cmd to fill in.  It returns *an negative errno or zero. * * set_settings: *@set_settings is passed an ðtool_cmd and should attempt to set *all the settings this device supports.  It may return an error value *if something goes wrong (otherwise 0). * * get_eeprom: *Should fill in the magic field.  Don't need to check len for zero *or wraparound.  Fill in the data argument with the eeprom values *from offset to offset + len.  Update len to the amount read. *Returns an error or zero. * * set_eeprom: *Should validate the magic field.  Don't need to check len for zero *or wraparound.  Update len to the amount written.  Returns an error *or zero. */struct ethtool_ops {int(*get_settings)(struct net_device *, struct ethtool_cmd *);int(*set_settings)(struct net_device *, struct ethtool_cmd *);void(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);int(*get_regs_len)(struct net_device *);void(*get_regs)(struct net_device *, struct ethtool_regs *, void *);void(*get_wol)(struct net_device *, struct ethtool_wolinfo *);int(*set_wol)(struct net_device *, struct ethtool_wolinfo *);u32(*get_msglevel)(struct net_device *);void(*set_msglevel)(struct net_device *, u32);int(*nway_reset)(struct net_device *);u32(*get_link)(struct net_device *);int(*get_eeprom_len)(struct net_device *);int(*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);int(*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);int(*get_coalesce)(struct net_device *, struct ethtool_coalesce *);int(*set_coalesce)(struct net_device *, struct ethtool_coalesce *);void(*get_ringparam)(struct net_device *, struct ethtool_ringparam *);int(*set_ringparam)(struct net_device *, struct ethtool_ringparam *);void(*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*);int(*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*);u32(*get_rx_csum)(struct net_device *);int(*set_rx_csum)(struct net_device *, u32);u32(*get_tx_csum)(struct net_device *);int(*set_tx_csum)(struct net_device *, u32);u32(*get_sg)(struct net_device *);int(*set_sg)(struct net_device *, u32);u32(*get_tso)(struct net_device *);int(*set_tso)(struct net_device *, u32);void(*self_test)(struct net_device *, struct ethtool_test *, u64 *);void(*get_strings)(struct net_device *, u32 stringset, u8 *);int(*phys_id)(struct net_device *, u32);void(*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);int(*begin)(struct net_device *);void(*complete)(struct net_device *);u32     (*get_ufo)(struct net_device *);int     (*set_ufo)(struct net_device *, u32);u32     (*get_flags)(struct net_device *);int     (*set_flags)(struct net_device *, u32);u32     (*get_priv_flags)(struct net_device *);int     (*set_priv_flags)(struct net_device *, u32);int(*get_sset_count)(struct net_device *, int);/* the following hooks are obsolete */int(*self_test_count)(struct net_device *);/* use get_sset_count */int(*get_stats_count)(struct net_device *);/* use get_sset_count */int(*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *);int(*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);int     (*flash_device)(struct net_device *, struct ethtool_flash *);};
dm9000_open()

进行的工作有 向内核注册中断,复位并初始化dm9000,检查MII接口,使能传输等。

/* *  Open the interface. *  The interface is opened whenever "ifconfig" actives it. */static intdm9000_open(struct net_device *dev){board_info_t *db = netdev_priv(dev);unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;/* 使用netif_msg_ifup方法判断net是否出在up message level */if (netif_msg_ifup(db))dev_dbg(db->dev, "enabling %s\n", dev->name);/* 从这里开始检查IRQ flag,未设置则提示用户设置,正常则注册中断处理函数 *//* If there is no IRQ type specified, default to something that * may work, and tell the user that this is a problem */if (irqflags == IRQF_TRIGGER_NONE)dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");irqflags |= IRQF_SHARED;if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))return -EAGAIN;/* Initialize DM9000 board *//* 这里reset dm9000,前面已经分析过这个方法 */dm9000_reset(db);dm9000_init_dm9000(dev);/* Init driver variable */db->dbug_cnt = 0;mii_check_media(&db->mii, netif_msg_link(db), 1);netif_start_queue(dev);/*之前在probe函数中已经使用INIT_DELAYED_WORK来初始化一个延迟工作队列,并关联了一个操作函数dm9000_poll_work(), 此时运行schedule来调用这个函数*/dm9000_schedule_poll(db);return 0;}

有关message level的说明

enum {NETIF_MSG_DRV= 0x0001,NETIF_MSG_PROBE= 0x0002,NETIF_MSG_LINK= 0x0004,NETIF_MSG_TIMER= 0x0008,NETIF_MSG_IFDOWN= 0x0010,NETIF_MSG_IFUP= 0x0020,NETIF_MSG_RX_ERR= 0x0040,NETIF_MSG_TX_ERR= 0x0080,NETIF_MSG_TX_QUEUED= 0x0100,NETIF_MSG_INTR= 0x0200,NETIF_MSG_TX_DONE= 0x0400,NETIF_MSG_RX_STATUS= 0x0800,NETIF_MSG_PKTDATA= 0x1000,NETIF_MSG_HW= 0x2000,NETIF_MSG_WOL= 0x4000,};#define netif_msg_drv(p)((p)->msg_enable & NETIF_MSG_DRV)#define netif_msg_probe(p)((p)->msg_enable & NETIF_MSG_PROBE)#define netif_msg_link(p)((p)->msg_enable & NETIF_MSG_LINK)#define netif_msg_timer(p)((p)->msg_enable & NETIF_MSG_TIMER)#define netif_msg_ifdown(p)((p)->msg_enable & NETIF_MSG_IFDOWN)#define netif_msg_ifup(p)((p)->msg_enable & NETIF_MSG_IFUP)#define netif_msg_rx_err(p)((p)->msg_enable & NETIF_MSG_RX_ERR)#define netif_msg_tx_err(p)((p)->msg_enable & NETIF_MSG_TX_ERR)#define netif_msg_tx_queued(p)((p)->msg_enable & NETIF_MSG_TX_QUEUED)#define netif_msg_intr(p)((p)->msg_enable & NETIF_MSG_INTR)#define netif_msg_tx_done(p)((p)->msg_enable & NETIF_MSG_TX_DONE)#define netif_msg_rx_status(p)((p)->msg_enable & NETIF_MSG_RX_STATUS)#define netif_msg_pktdata(p)((p)->msg_enable & NETIF_MSG_PKTDATA)#define netif_msg_hw(p)((p)->msg_enable & NETIF_MSG_HW)#define netif_msg_wol(p)((p)->msg_enable & NETIF_MSG_WOL)

对dm9000_init_dm9000的分析

/* * Initilize dm9000 board */static voiddm9000_init_dm9000(struct net_device *dev){board_info_t *db = netdev_priv(dev);unsigned int imr;dm9000_dbg(db, 1, "entering %s\n", __func__);/* I/O mode *//* 这里读取ISR寄存器的数值,寄存器的7-6位用来指示I/0的读写模式00 16-bit-mode01 32-bit-mode10 8-bit-mode11 reserved*/db->io_mode = ior(db, DM9000_ISR) >> 6;/* ISR bit7:6 keeps I/O mode *//* Checksum mode */dm9000_set_rx_csum(dev, db->rx_csum);/* GPIO0 on pre-activate PHY */iow(db, DM9000_GPR, 0);/* REG_1F bit0 activate phyxcer */iow(db, DM9000_GPCR, GPCR_GEP_CNTL);/* Let GPIO0 output */iow(db, DM9000_GPR, 0);/* Enable PHY *//* 选择使用外部PHY */if (db->flags & DM9000_PLATF_EXT_PHY)iow(db, DM9000_NCR, NCR_EXT_PHY);/* Program operating register */iow(db, DM9000_TCR, 0);        /* TX Polling clear */iow(db, DM9000_BPTR, 0x3f);/* Less 3Kb, 200us */iow(db, DM9000_FCR, 0xff);/* Flow Control */iow(db, DM9000_SMCR, 0);        /* Special Mode *//* clear TX status */iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status *//* Set address filter table */dm9000_hash_table(dev);/* 设置中断允许寄存器 */imr = IMR_PAR | IMR_PTM | IMR_PRM;if (db->type != TYPE_DM9000E)imr |= IMR_LNKCHNG;db->imr_all = imr;/* Enable TX/RX interrupt mask */iow(db, DM9000_IMR, imr);/* Init Driver variable *//* 初始化状态,传输包数量为零,等待包的长度为零,start状态为零 */db->tx_pkt_cnt = 0;db->queue_pkt_len = 0;dev->trans_start = 0;}

最後看一下dm9000_stop方法

/* * Stop the interface. * The interface is stopped when it is brought. */static intdm9000_stop(struct net_device *ndev){board_info_t *db = netdev_priv(ndev);if (netif_msg_ifdown(db))dev_dbg(db->dev, "shutting down %s\n", ndev->name);/* 強制結束工作隊列 */cancel_delayed_work_sync(&db->phy_poll);/* 強制設備停止傳輸包 */netif_stop_queue(ndev);/* 強制清空carrier */netif_carrier_off(ndev);/* free interrupt */free_irq(ndev->irq, ndev);dm9000_shutdown(ndev);return 0;}

原创粉丝点击