dm9000 driver 1
资料
dm9000-中文
dm9000--ae
make menuconfig
Device Drivers ---> [*] Network device support ---> [*] Ethernet (10 or 100Mbit) ---> <*> DM9000 support
dm9000的结构图比较清晰,外层是platform,内层是net_device。
平台设备在mach-mini2440.c注册,平台驱动在dm9000.c的init注册。
net_device在平台的probe注册。
*************************************************************************
平台设备信息,
mach-smdk6410.c
dm9000.c中
有两个结构体很重要
*************************************************************************
在init函数中注册平台驱动dm9000_driver
发送流程:
在m9000_start_xmit函数中直接发送。未使用工作队列。
怎么接收呢?当然是在中断处理函数中接收,有中断产生时,在中断处理函数中(即上半部)直接接收。并将接收到的数据保存,以供应用层使用read socket等来读取。未使用工作队列。
接收流程:
1.分配skb
2.从硬件即通过总线从dm9000 rx ram中读取数据到skb
3.调用netif_rx将skb交给设备无关接口(它再交给协议栈处理skb中数据)
dm9000-中文
dm9000--ae
make menuconfig
Device Drivers ---> [*] Network device support ---> [*] Ethernet (10 or 100Mbit) ---> <*> DM9000 support
dm9000的结构图比较清晰,外层是platform,内层是net_device。
平台设备在mach-mini2440.c注册,平台驱动在dm9000.c的init注册。
net_device在平台的probe注册。
*************************************************************************
平台设备信息,
mach-smdk6410.c
/* Ethernet */ #ifdef CONFIG_DM9000 #define S3C64XX_PA_DM9000 (0x18000000) #define S3C64XX_SZ_DM9000 SZ_1M #define S3C64XX_VA_DM9000 S3C_ADDR(0x03b00300) static struct resource dm9000_resources[] = {//平台设备的资源 [0] = { .start = S3C64XX_PA_DM9000,//0x18000000 .end = S3C64XX_PA_DM9000 + 3,//0x18000003 .flags = IORESOURCE_MEM, }, [1] = { .start = S3C64XX_PA_DM9000 + 4,//0x18000004 .end = S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,//180fffff .flags = IORESOURCE_MEM, }, [2] = { .start = IRQ_EINT(7),//网卡的中断引脚连到6410的eint7 .end = IRQ_EINT(7), .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,//高电平触发中断 }, }; /*从打印信息可以验证 [root@FORLINX6410]# cat /proc/iomem 18000000-18000003 : dm9000.0 //dm9000 18000000-18000003 : dm9000 18000004-180fffff : dm9000.0 18000004-180fffff : dm9000 */ static struct dm9000_plat_data dm9000_setup = {//平台设备de私有数据 .flags = DM9000_PLATF_16BITONLY,//dm9000a的16位模式 .dev_addr = { 0x08, 0x90, 0x00, 0xa0, 0x90, 0x90 },//默认mac,当网卡没接eeprom来存放mac时,使用这个当做默认mac }; static struct platform_device s3c_device_dm9000 = {//平台设备 .name = "dm9000", .id = 0, .num_resources = ARRAY_SIZE(dm9000_resources), .resource = dm9000_resources, .dev = { .platform_data = &dm9000_setup, } }; #endif //#ifdef CONFIG_DM9000 //然后是注册平台设备 ...*************************************************************************
dm9000.c中
有两个结构体很重要
/* Structure/enum declaration ------------------------------- */ 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 queue_ip_summed; u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; u8 imr_all; unsigned int flags; unsigned int in_suspend :1; unsigned int wake_supported :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; int irq_wake; 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; u32 wake_state; int rx_csum; int can_csum; int ip_summed; } board_info_t;
/* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O * data with strictly "high-level" data, and it has to know about * almost every data structure used in the INET module. * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ struct net_device { /* * This is the first field of the "visible" part of this structure * (i.e. as seen by users in the "Space.c" file). It is the name * of the interface. */ char name[IFNAMSIZ]; struct pm_qos_request_list pm_qos_req; /* device name hash chain */ struct hlist_node name_hlist; /* snmp alias */ char *ifalias; /* * I/O specific fields * FIXME: Merge these and struct ifmap into one */ unsigned long mem_end; /* shared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ /* * Some hardware also needs these fields, but they are not * part of the usual set specified in Space.c. */ unsigned char if_port; /* Selectable AUI, TP,..*/ unsigned char dma; /* DMA channel */ unsigned long state; struct list_head dev_list; struct list_head napi_list; struct list_head unreg_list; /* Management operations */ const struct net_device_ops *netdev_ops;//dm9000的net_device的file-operation const struct ethtool_ops *ethtool_ops; const struct header_ops *header_ops; unsigned int flags; /* interface flags (a la BSD) */ unsigned short gflags; unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */ unsigned short padded; /* How much padding added by alloc_netdev() */ unsigned char operstate; /* RFC2863 operstate */ unsigned char link_mode; /* mapping policy to operstate */ unsigned int mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ unsigned short hard_header_len; /* hardware hdr length */ /* extra head- and tailroom the hardware may need, but not in all cases * can this be guaranteed, especially tailroom. Some cases also use * LL_MAX_HEADER instead to allocate the skb. */ unsigned short needed_headroom; unsigned short needed_tailroom; struct net_device *master; /* Pointer to master device of a group, * which this device is member of. */ /* Interface address info. */ unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */ unsigned char addr_assign_type; /* hw address assignment type */ unsigned char addr_len; /* hardware address length */ unsigned short dev_id; /* for shared network cards */ spinlock_t addr_list_lock; struct netdev_hw_addr_list uc; /* Unicast mac addresses */ struct netdev_hw_addr_list mc; /* Multicast mac addresses */ int uc_promisc; unsigned int promiscuity; unsigned int allmulti; };
static const struct net_device_ops dm9000_netdev_ops = { .ndo_open = dm9000_open,//执行ifconfig eth0 up时调用 .ndo_stop = dm9000_stop,//执行ifconfig eth0 down时调用 .ndo_start_xmit = dm9000_start_xmit,//上层应用执行write socket等时调用 .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 };
*************************************************************************
在init函数中注册平台驱动dm9000_driver
static int __init dm9000_init(void) { printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); return platform_driver_register(&dm9000_driver); }在平台驱动dm9000_driver的probe函数中分配net_device
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), }; static int __devinit dm9000_probe(struct platform_device *pdev) { ndev = alloc_etherdev(sizeof(struct board_info)); if (!ndev) { dev_err(&pdev->dev, "could not allocate device.\n"); return -ENOMEM; } // INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //注册net_device register_netdev(ndev); } //net_device的operation结构体指定了操作函数集合 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 };应用层执行ifconfig eth0 up时会调用到dm9000_open
在mcp251x_open函数中 //申请中断 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; //开启协议栈下传skb给驱动 netif_start_queue(dev); //启动 dm9000_schedule_poll(db);应用层执行write socket时会调用到m9000_start_xmit来发送数据。
发送流程:
在m9000_start_xmit函数中直接发送。未使用工作队列。
/* * Hardware start transmission. * Send a packet to media from the upper layer. */ 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); 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) { dm9000_send_packet(dev, skb->ip_summed, skb->len); } else { /* Second packet */ db->queue_pkt_len = skb->len; db->queue_ip_summed = skb->ip_summed; netif_stop_queue(dev); } spin_unlock_irqrestore(&db->lock, flags); /* free this SKB */ dev_kfree_skb(skb); return NETDEV_TX_OK; }
怎么接收呢?当然是在中断处理函数中接收,有中断产生时,在中断处理函数中(即上半部)直接接收。并将接收到的数据保存,以供应用层使用read socket等来读取。未使用工作队列。
1.分配skb
2.从硬件即通过总线从dm9000 rx ram中读取数据到skb
3.调用netif_rx将skb交给设备无关接口(它再交给协议栈处理skb中数据)
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); if (db->type != TYPE_DM9000E) {//如果不是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()完成,
/* * Received a packet and pass to upper layer */ 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_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; } 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)); 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 */ 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); if (db->rx_csum) { if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; } 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); }