前面讨论了probe函数和open函数,下面继续。
内核发送数据在底层是通过dmfe_start_xmit函数来实现的
static int dmfe_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
char * data_ptr;
int i, tmplen;
if(db->Speed == 10)
{if (db->tx_pkt_cnt >= 1) return 1;}
else
{if (db->tx_pkt_cnt >= 2) return 1;}
/* packet counting */
db->tx_pkt_cnt++;
db->stats.tx_packets++;
db->stats.tx_bytes+=skb->len;
if (db->Speed == 10)
{if (db->tx_pkt_cnt >= 1) netif_stop_queue(dev);}
else
{if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev);}
/* Disable all interrupt */
iow(db, DM9KS_IMR, DM9KS_DISINTR);
/* Set TX length to reg. 0xfc & 0xfd */
iow(db, DM9KS_TXPLL, (skb->len & 0xff));
iow(db, DM9KS_TXPLH, (skb->len >> 8) & 0xff);
/* Move data to TX SRAM */
data_ptr = (char *)skb->data;
PUTB(DM9KS_MWCMD, db->io_addr); // Write data into SRAM trigger
switch(db->io_mode)
{
case DM9KS_BYTE_MODE:
for (i = 0; i skb->len; i++)
PUTB((data_ptr & 0xff), db->io_data);
break;
case DM9KS_WORD_MODE:
tmplen = (skb->len + 1) / 2;
for (i = 0; i tmplen; i++)
PUTW(((u16 *)data_ptr), db->io_data);
break;
case DM9KS_DWORD_MODE:
tmplen = (skb->len + 3) / 4;
for (i = 0; i tmplen; i++)
PUTL(((u32 *)data_ptr), db->io_data);
break;
}
#if !defined(ETRANS)
/* Issue TX polling command */
iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/
#endif
/* Saved the time stamp */
dev->trans_start = jiffies;
db->cont_rx_pkt_cnt =0;
/* Free this SKB */
dev_kfree_skb(skb);
/* Re-enable interrupt */
iow(db, DM9KS_IMR, DM9KS_REGFF);
return 0;
}
该函数首先判断设备使用的模式,若speed为10,则发送的数据包个数最大为1,若speed为100,则最大个数为2.超过这两个值,函数立即返回。若不超过,则说明可以进行数据发送。然后是更新系统的统计信息。如果待发送包达到上限,则调用netif_stop_queue,告诉内核暂时停止内核与驱动程序间的数据传递。
这些完成后,就可以开始真正的数据传输了。先禁止dm9000a的所有中断,通过写它的Interrupt Mask Register来实现。然后将要传递的数据的长度信息写入TX Packet Length Register中。
需要注意的是char * data_ptr在这里不能理解为一个指向char变量的指针,而应该理解为一个char数组。根据芯片的硬件连接方式,选择字节、半字或者字的方式对数据进行发送。发送完成后,记录下时间戳,并释放skb的空间,然后允许dm9000a的中断,以便继续进行发送或者接收。
stop方法和open函数的方法作用相反,即停止网络设备
static int dmfe_stop(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
/* deleted timer */
del_timer(&db->timer);
netif_stop_queue(dev);
/* free interrupt */
free_irq(dev->irq, dev);
/* RESET devie */
phy_write(db, 0x00, 0x8000); /* PHY RESET */
iow(db, DM9KS_GPR, 0x01); /* Power-Down PHY */
iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Disable all interrupt */
iow(db, DM9KS_RXCR, 0x00); /* Disable RX */
/* Dump Statistic counter */
return 0;
}
完成的工作主要有删除定时器、释放中断、调用netif_stop_queue()告诉内核停止内核与驱动程序之间的数据交换,最后使dm9000a网卡处于power-down模式。
阅读(717) | 评论(0) | 转发(0) |