dm9000 driver 1
生活随笔
收集整理的這篇文章主要介紹了
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
/* 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-operationconst 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_deviceregister_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;elseskb->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); }
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-operationconst 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_deviceregister_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;elseskb->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); }
轉載于:https://www.cnblogs.com/-song/archive/2011/12/17/3331898.html
總結
以上是生活随笔為你收集整理的dm9000 driver 1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: serial driver 2
- 下一篇: dm9000 driver 2