平台:MINI2440
系统:Linux-2.6.36.2
mach-s3c2410/include/mach/map.h:
#define S3C2410_CS4 (0x20000000) //AEN接nGCS4,BANK4
mach-mini2440.c:
#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300) //TXD[2:0]悬空 static struct resource mini2440_dm9k_resource[] = { [0] = { .start = MACH_MINI2440_DM9K_BASE, .end = MACH_MINI2440_DM9K_BASE + 3, .flags = IORESOURCE_MEM }, [1] = { .start = MACH_MINI2440_DM9K_BASE + 4, .end = MACH_MINI2440_DM9K_BASE + 7, .flags = IORESOURCE_MEM }, [2] = { .start = IRQ_EINT7, //中断使用了EINT7. .end = IRQ_EINT7, .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, } };DM9000平台设备的定义:
static struct dm9000_plat_data mini2440_dm9k_pdata = { .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), }; static struct platform_device mini2440_device_eth = { .name = "dm9000", .id = -1, .num_resources = ARRAY_SIZE(mini2440_dm9k_resource), .resource = mini2440_dm9k_resource, .dev = { .platform_data = &mini2440_dm9k_pdata, }, };板子初始化时将平台设备驱动加载到总线上:
static struct platform_device *mini2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_rtc, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &mini2440_device_eth, &s3c24xx_uda134x, &s3c_device_nand, &s3c_device_sdi, &s3c_device_usbgadget, };dm9000.c:platform_driver与重要操作函数:
static struct platform_driver dm9000_driver = { .driver = { .name = "dm9000", .owner = THIS_MODULE, }, .probe = dm9000_probe, .remove = __devexit_p(dm9000_drv_remove), .suspend = dm9000_drv_suspend, .resume = dm9000_drv_resume, };net_device_ops与重要操作函数:
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 };ethtool_ops:
static const struct ethtool_ops dm9000_ethtool_ops = { //查询与设置网卡的参数 .get_drvinfo = dm9000_get_drvinfo, .get_settings = dm9000_get_settings, .set_settings = dm9000_set_settings, .get_msglevel = dm9000_get_msglevel, .set_msglevel = dm9000_set_msglevel, .nway_reset = dm9000_nway_reset, .get_link = dm9000_get_link, .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, };board_info结构体,内容是与芯片相关的信息:
typedef struct board_info { void __iomem *io_addr; /* Register I/O base address */ void __iomem *io_data; /* Data I/O address */ u16 irq; /* IRQ */ u16 tx_pkt_cnt; u16 queue_pkt_len; u16 queue_start_addr; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; u8 imr_all; unsigned int flags; unsigned int in_suspend :1; int debug_level; enum dm9000_type type; void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); void (*dumpblk)(void __iomem *port, int length); struct device *dev; /* parent device */ struct resource *addr_res; /* resources found */ struct resource *data_res; struct resource *addr_req; /* resources requested */ struct resource *data_req; struct resource *irq_res; struct mutex addr_lock; /* phy and eeprom access lock */ struct delayed_work phy_poll; struct net_device *ndev; spinlock_t lock; struct mii_if_info mii; u32 msg_enable; } board_info_t;注册平台驱动:
static int __init dm9000_init(void) { printk(KERN_INFO "%s Ethernet Driver, V%s/n", CARDNAME, DRV_VERSION); return platform_driver_register(&dm9000_driver); }完成match之后执行Probe函数,获得资源信息,最终注册网络设备。
dm9000_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, (board_info_t *) netdev_priv(ndev)); free_netdev(ndev); /* free device structure */ dev_dbg(&pdev->dev, "released and freed device/n"); return 0; }dm9000_suspend:并没有将网络设备从内核移除,只是标志设备为removed状态,并设置挂起标志位,最后关闭设备:
static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) { struct net_device *ndev = platform_get_drvdata(dev); board_info_t *db; if (ndev) { db = netdev_priv(ndev); db->in_suspend = 1; if (netif_running(ndev)) { netif_device_detach(ndev); dm9000_shutdown(ndev); } } return 0; }dm9000_resume:
static int dm9000_drv_resume(struct platform_device *dev) { struct net_device *ndev = platform_get_drvdata(dev); board_info_t *db = netdev_priv(ndev); if (ndev) { if (netif_running(ndev)) { dm9000_reset(db); dm9000_init_dm9000(ndev); netif_device_attach(ndev);//标志为attach状态。 } db->in_suspend = 0; } return 0; }dm9000_open:向内核注册中断:
static int dm9000_open(struct net_device *dev) { board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; if (netif_msg_ifup(db)) dev_dbg(db->dev, "enabling %s\n", dev->name); /* 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 */ 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); dm9000_schedule_poll(db); return 0; }dm9000_stop:
static int dm9000_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); netif_carrier_off(ndev); free_irq(ndev->irq, ndev); dm9000_shutdown(ndev); return 0; }dm9000_start_xmit():发送数据包函数:
static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; board_info_t *db = netdev_priv(dev); dm9000_dbg(db, 3, "%s:/n", __func__); if (db->tx_pkt_cnt > 1) return NETDEV_TX_BUSY; /*获得自旋锁*/ spin_lock_irqsave(&db->lock, flags); /* Move data to DM9000 TX RAM */ writeb(DM9000_MWCMD, db->io_addr); (db->outblk)(db->io_data, skb->data, skb->len);//将skbuffer中的data写入DM9000的TX RAM,并计数 dev->stats.tx_bytes += skb->len; db->tx_pkt_cnt++; /* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) { //如果是第一个包 /* Set TX length to DM9000 */ iow(db, DM9000_TXPLL, skb->len); iow(db, DM9000_TXPLH, skb->len >> 8); /* Issue TX polling command */ iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ dev->trans_start = jiffies; /* save the time stamp */ } else { //不是第一个包 /* Second packet */ db->queue_pkt_len = skb->len; netif_stop_queue(dev); } /*释放自旋锁*/ spin_unlock_irqrestore(&db->lock, flags); /* free this SKB */ dev_kfree_skb(skb); return 0; }dm9000_timeout():超时调用:
static void dm9000_timeout(struct net_device *dev) { board_info_t *db = netdev_priv(dev); u8 reg_save; unsigned long flags; /* Save previous register address */ //保存寄存器地址 reg_save = readb(db->io_addr); spin_lock_irqsave(&db->lock, flags); netif_stop_queue(dev); //停止队列 dm9000_reset(db); dm9000_init_dm9000(dev); //重启并初始化DM9000 /* We can accept TX packets again */ dev->trans_start = jiffies; netif_wake_queue(dev); //唤醒队列 /* Restore previous register address */ //恢复寄存器地址 writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); }dm9000_hash_table():设置组播地址:
static void dm9000_hash_table(struct net_device *dev) { board_info_t *db = netdev_priv(dev); struct dev_mc_list *mcptr = dev->mc_list; int mc_cnt = dev->mc_count; int i, oft; u32 hash_val; u16 hash_table[4]; u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; unsigned long flags; dm9000_dbg(db, 1, "entering %s/n", __func__); spin_lock_irqsave(&db->lock, flags); for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) iow(db, oft, dev->dev_addr[i]); /* Clear Hash Table */ for (i = 0; i < 4; i++) hash_table[i] = 0x0; /* broadcast address */ hash_table[3] = 0x8000; if (dev->flags & IFF_PROMISC) rcr |= RCR_PRMSC; if (dev->flags & IFF_ALLMULTI) rcr |= RCR_ALL; /* the multicast address in Hash Table : 64 bits */ for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); } /* Write the hash table to MAC MD table */ for (i = 0, oft = DM9000_MAR; i < 4; i++) { iow(db, oft++, hash_table[i]); iow(db, oft++, hash_table[i] >> 8); } iow(db, DM9000_RCR, rcr); spin_unlock_irqrestore(&db->lock, flags); }dm9000_rx():接收函数:
static void dm9000_rx(struct net_device *dev) { board_info_t *db = netdev_priv(dev); struct dm9000_rxhdr rxhdr; struct sk_buff *skb; u8 rxbyte, *rdptr; bool GoodPacket; int RxLen; /* Check packet ready or not */ do { ior(db, DM9000_MRCMDX); /* Dummy read */ /* Get most updated data */ rxbyte = readb(db->io_data); /* Status check: this byte must be 0 or 1 */ if (rxbyte > DM9000_PKT_RDY) { 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; } if (rxbyte != DM9000_PKT_RDY) return; /* A packet ready now & Get status/length */ GoodPacket = true; writeb(DM9000_MRCMD, db->io_addr); (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));//读四个字节到rxhdr变量 RxLen = le16_to_cpu(rxhdr.RxLen); if (netif_msg_rx_status(db)) dev_dbg(db->dev, "RX: status %02x, length %04x/n", rxhdr.RxStatus, RxLen); /* Packet Status check */ if (RxLen < 0x40) { GoodPacket = false; if (netif_msg_rx_err(db)) dev_dbg(db->dev, "RX: Bad Packet (runt)/n"); } if (RxLen > DM9000_PKT_MAX) { dev_dbg(db->dev, "RST: RX Len:%x/n", RxLen); } /* rxhdr.RxStatus is identical to RSR register. */ if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | RSR_PLE | RSR_RWTO | RSR_LCS | RSR_RF)) { GoodPacket = false; if (rxhdr.RxStatus & RSR_FOE) { if (netif_msg_rx_err(db)) dev_dbg(db->dev, "fifo error/n"); dev->stats.rx_fifo_errors++; } if (rxhdr.RxStatus & RSR_CE) { if (netif_msg_rx_err(db)) dev_dbg(db->dev, "crc error/n"); dev->stats.rx_crc_errors++; } if (rxhdr.RxStatus & RSR_RF) { if (netif_msg_rx_err(db)) dev_dbg(db->dev, "length error/n"); dev->stats.rx_length_errors++; } } /* Move data from DM9000 */ //将RX SRAM中的data放到sk_buffer。 if (GoodPacket && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { skb_reserve(skb, 2); rdptr = (u8 *) skb_put(skb, RxLen - 4); /* Read received packet from RX SRAM */ (db->inblk)(db->io_data, rdptr, RxLen); dev->stats.rx_bytes += RxLen; /* Pass to upper layer */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; } else { /* need to dump the packet's data */ (db->dumpblk)(db->io_data, RxLen); } } while (rxbyte == DM9000_PKT_RDY); }dm9000_interrupt:
static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; board_info_t *db = netdev_priv(dev); int int_status; unsigned long flags; u8 reg_save; dm9000_dbg(db, 3, "entering %s/n", __func__); /* A real interrupt coming */ /* holders of db->lock must always block IRQs */ spin_lock_irqsave(&db->lock, flags); /* 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 */ if (netif_msg_intr(db)) dev_dbg(db->dev, "interrupt status %02x/n", int_status); /* Received the coming packet */ if (int_status & ISR_PRS) dm9000_rx(dev); //取数据 /* Trnasmit Interrupt check */ if (int_status & ISR_PTS) dm9000_tx_done(dev, db); //调用done函数 if (db->type != TYPE_DM9000E) { if (int_status & ISR_LNKCHNG) { /* fire a link-change request */ schedule_delayed_work(&db->phy_poll, 1); } } /* Re-enable interrupt mask */ iow(db, DM9000_IMR, db->imr_all); /* Restore previous register address */ writeb(reg_save, db->io_addr); spin_unlock_irqrestore(&db->lock, flags); return IRQ_HANDLED; }dm9000_tx_done:
static void dm9000_tx_done(struct net_device *dev, board_info_t *db) { int tx_status = ior(db, DM9000_NSR); /* Got TX status */ //读取NSR的状态,得知发送的状态 if (tx_status & (NSR_TX2END | NSR_TX1END)) { /* One packet sent complete */ db->tx_pkt_cnt--; dev->stats.tx_packets++; if (netif_msg_tx_done(db)) dev_dbg(db->dev, "tx done, NSR %02x/n", tx_status); /* Queue packet check & send */ if (db->tx_pkt_cnt > 0) { iow(db, DM9000_TXPLL, db->queue_pkt_len); iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); iow(db, DM9000_TCR, TCR_TXREQ); dev->trans_start = jiffies; } //通知内核可以将待发送的数据包进入发送队列 netif_wake_queue(dev); } }