📄 dm9000.txt
字号:
}
printk("%02x\n", ndev->dev_addr[5]);
}
return 0;
release:
printk("%s: not found (%d).\n", CARDNAME, ret);
dm9000_release_board(pdev, db);
kfree(ndev);
return ret;
}
/**
* Open the interface.
* The interface is opened whenever "ifconfig" actives it.
**/
static int
dm9000_open(struct net_device *dev)
{
board_info_t *db = (board_info_t *) dev->priv;
PRINTK2("entering dm9000_open\n");
/* Using the RISING EDGE for this interrupt */
if (request_irq(dev->irq, dm9000_interrupt, IRQF_SHARED | IRQF_TRIGGER_RISING, dev->name, dev))
return -EAGAIN;
/* Initialize DM9000 board */
dm9000_reset(db);
dm9000_init_dm9000(dev);
/* Init driver variable */
db->runt_length_counter = 0;
db->long_length_counter = 0;
db->reset_counter = 0;
/* set and active a timer process */
init_timer(&db->timer);
db->timer.expires = DM9000_TIMER_WUT;
db->timer.data = (unsigned long)dev;
db->timer.function = &dm9000_timer;
add_timer(&db->timer);
netif_start_queue(dev);
return 0;
}
/*
* 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)
{
board_info_t *db = (board_info_t *) dev->priv;
PRINTK3("dm9000_start_xmit\n");
if (db->tx_pkt_cnt > 1) return 1;
netif_stop_queue(dev);
/* Disable all interrupt */
iow(db, DM9000_IMR, 0x80);
/* Move data to DM9000 TX RAM */
writeb(0xf8, db->io_addr);
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
writesb(db->io_data,skb->data,skb->len);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
writesw(db->io_data, skb->data, (skb->len+1) >> 1);
} else {
/* DWord mode */
writesl(db->io_data,skb->data, (skb->len+3) >> 2);
}
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 0) {
/* First Packet */
db->tx_pkt_cnt++;
/* Set TX length to DM9000 */
iow(db, DM9000_TXPLL, skb->len & 0xff);
iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
/* Issue TX polling command */
iow(db, DM9000_TCR, 0x1);/* Cleared after TX complete */
dev->trans_start = jiffies;/* saved the time stamp */
} else {
/* Second packet */
db->tx_pkt_cnt++;
db->queue_pkt_len = skb->len;
}
/* free this SKB */
dev_kfree_skb(skb);
/* Re-enable resource check */
if (db->tx_pkt_cnt == 1) {
netif_wake_queue(dev);
}
/* Re-enable interrupt*/
iow(db,DM9000_IMR,0x83);
polling_times=0;
return 0;
}
/*
* Stop the interface.
* The interface is stopped when it is brought.
*/
static int
dm9000_stop(struct net_device *ndev)
{
board_info_t *db = (board_info_t *) ndev->priv;
PRINTK1("entering %s\n",__FUNCTION__);
/* deleted timer */
del_timer(&db->timer);
netif_stop_queue(ndev);
/* free interrupt */
free_irq(ndev->irq, ndev);
/* RESET devie */
dm9000_shutdown(ndev);
//MOD_DEC_USE_COUNT;
return 0;
}
/**
*Process the upper socket ioctl command
**/
static int dm9000_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
return 0;
}
/**
* Get statistics from driver.
**/
static struct net_device_stats *
dm9000_get_stats(struct net_device *dev)
{
board_info_t *db = (board_info_t *) dev->priv;
return &db->stats;
}
/*
DM9102 insterrupt handler
receive the packet to upper layer, free the transmitted packet
*/
static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
int tx_status = ior(db, 0x01); /* Got TX status */
if (tx_status & 0xc) {
/* One packet sent complete */
db->tx_pkt_cnt--;
dev->trans_start = 0;
db->stats.tx_packets++;
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0) {
iow(db, 0xfc, db->queue_pkt_len & 0xff);
iow(db, 0xfd, (db->queue_pkt_len >> 8) & 0xff);
iow(db, 0x2, 0x1);
dev->trans_start = jiffies;
}
netif_wake_queue(dev);
}
}
static irqreturn_t dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
board_info_t *db;
int int_status;
u8 reg_save;
//printk("SBZ: entering %s\n",__FUNCTION__);
if (!dev) {
PRINTK1("dm9000_interrupt() without DEVICE arg\n");
return IRQ_HANDLED;
}
/* A real interrupt coming */
db = (board_info_t *)dev->priv;
spin_lock(&db->lock);
reg_save = readb(db->io_addr);
/* Disable all interrupt */
iow(db, DM9000_IMR, 0x80);
/* Got DM9000 interrupt status */
int_status = ior(db, 0xfe); /* Got ISR */
iow(db, DM9000_ISR, int_status); /* Clear ISR status */
/* Received the coming packet */
if (int_status & DM9000_RX_INTR) {
#if 0
tasklet_schedule(&dmfe_rx_tasklet);
#else
dm9000_rx(dev);
#endif
}
/* Trnasmit Interrupt check */
if (int_status & DM9000_TX_INTR)
dm9000_tx_done(dev,db);
/* Re-enable interrupt mask */
iow(db, DM9000_IMR, 0x83);
/* Restore previous register address */
writeb(reg_save, db->io_addr);
spin_unlock(&db->lock);
return IRQ_HANDLED;
}
/*
* A periodic timer routine
* Dynamic media sense, allocated Rx buffer...
*/
static void
dm9000_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
board_info_t *db = (board_info_t *) dev->priv;
u8 reg_save, tmp_reg;
PRINTK3("dm9000_timer()\n");
/* Save previous register address */
reg_save = readb(db->io_addr);
/* TX timeout check */
if (dev->trans_start&&((jiffies-dev->trans_start)>DMFE_TX_TIMEOUT)) {
db->device_wait_reset = 1;
db->reset_tx_timeout++;
}
/* DM9000 dynamic RESET check and do */
if (db->device_wait_reset) {
netif_stop_queue(dev);
db->reset_counter++;
db->device_wait_reset = 0;
dev->trans_start = 0;
dm9000_init_dm9000(dev);
netif_wake_queue(dev);
}
/* Auto Sense Media mode policy:
FastEthernet NIC: don't need to do anything.
Media Force mode: don't need to do anything.
HomeRun/LongRun NIC and AUTO_Mode:
INT_MII not link, select EXT_MII
EXT_MII not link, select INT_MII
*/
if ( (db->nic_type != FASTETHER_NIC) && (db->op_mode & DM9000_AUTO) ) {
tmp_reg = ior(db, 0x01); /* Got link status */
if ( !(tmp_reg & 0x40) ) { /* not link */
db->reg0 ^= 0x80;
iow(db, 0x00, db->reg0);
}
}
/* Restore previous register address */
writeb(reg_save, db->io_addr);
/* Set timer again */
db->timer.expires = DM9000_TIMER_WUT;
add_timer(&db->timer);
}
/*
Received a packet and pass to upper layer
*/
static void
dm9000_rx(struct net_device *dev)
{
board_info_t *db = (board_info_t *) dev->priv;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
u16 i, RxStatus, RxLen, GoodPacket, tmplen;
u32 tmpdata;
polling_times++;
/* Check packet ready or not */
do {
ior(db,0xf4);
ior(db,0xf5);
ior(db, 0xf0); /* Dummy read */
rxbyte = readb(db->io_data);
rxbyte = readb(db->io_data);
rxbyte = readb(db->io_data);
rxbyte = readb(db->io_data);
rxbyte = readb(db->io_data);
rxbyte = readb(db->io_data);/* Got most updated data */
/* Status check: this byte must be 0 or 1 */
if (rxbyte > DM9000_PKT_RDY) {
iow(db, 0x05, 0x00); /* Stop Device */
iow(db, 0xfe, 0x80); /* Stop INT request */
db->device_wait_reset = TRUE;
db->reset_rx_status++;
}
/* packet ready to receive check */
if (rxbyte == DM9000_PKT_RDY) {
/* A packet ready now & Get status/length */
GoodPacket = TRUE;
writeb(0xf2, db->io_addr);
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
RxStatus = readb(db->io_data)+(readb(db->io_data) << 8);
RxLen = readb(db->io_data)+(readb(db->io_data) << 8);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
RxStatus = readw(db->io_data);
RxLen = readw(db->io_data);
} else {
/* DWord mode */
tmpdata = readl(db->io_data);
RxStatus = tmpdata;
RxLen = tmpdata >> 16;
}
/* Packet Status check */
if (RxLen < 0x40) {
GoodPacket = FALSE;
db->runt_length_counter++;
}
if (RxLen > DM9000_PKT_MAX) {
printk("<DM9000> RST: RX Len:%x\n", RxLen);
db->device_wait_reset = TRUE;
db->long_length_counter++;
}
if (RxStatus & 0xbf00) {
GoodPacket = FALSE;
if (RxStatus & 0x100)
db->stats.rx_fifo_errors++;
if (RxStatus & 0x200)
db->stats.rx_crc_errors++;
if (RxStatus & 0x8000)
db->stats.rx_length_errors++;
}
/* Move data from DM9000 */
if (!db->device_wait_reset) {
if ( GoodPacket && ((skb = dev_alloc_skb(RxLen + 4)) != NULL ) ) {
skb->dev = dev;
skb_reserve(skb, 2);
rdptr = (u8 *) skb_put(skb, RxLen-4);
/* Read received packet from RX SARM */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i=0; i<RxLen; i++)
rdptr[i]=readb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
((u16 *)rdptr)[i] = readw(db->io_data);
} else {
/* DWord mode */
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
((u32 *)rdptr)[i] = readl(db->io_data);
}
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
db->stats.rx_packets++;
} else {
/* Without buffer or error packet */
if (db->io_mode == DM9000_BYTE_MODE) {
/* Byte mode */
for (i = 0; i < RxLen; i++)
readb(db->io_data);
} else if (db->io_mode == DM9000_WORD_MODE) {
/* Word mode */
printk("0");
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
readw(db->io_data);
} else {
/* DWord mode */
tmplen = (RxLen + 3) / 4;
for (i = 0; i < tmplen; i++)
readl(db->io_data);
}
}
}
}
}while(rxbyte == DM9000_PKT_RDY && !db->device_wait_reset);
}
/*
* Set DM9000 multicast address
*/
static void
dm9000_hash_table(struct net_device *dev)
{
board_info_t *db = (board_info_t *)dev->priv;
struct dev_mc_list *mcptr = dev->mc_list;
int mc_cnt = dev->mc_count;
u32 hash_val;
u16 i, oft, hash_table[4];
PRINTK1("dm9000_hash_table()");
/* Set Node address */
for (i = 0, oft = 0x10; 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;
/* the multicast address in Hash Table : 64 bits */
for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
hash_val = crc32(0, (char *)mcptr->dmi_addr, 6) & 0x3f;
hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
}
/* Write the hash table to MAC MD table */
for (i = 0, oft = 0x16; i < 4; i++) {
iow(db, oft++, hash_table[i] & 0xff);
iow(db, oft++, (hash_table[i] >> 8) & 0xff);
}
}
static int
dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
struct net_device *ndev = platform_get_drvdata(dev);
if (ndev) {
if (netif_running(ndev)) {
netif_device_detach(ndev);
dm9000_shutdown(ndev);
}
}
return 0;
}
static int
dm9000_drv_resume(struct platform_device *dev)
{
struct net_device *ndev = platform_get_drvdata(dev);
board_info_t *db = (board_info_t *) ndev->priv;
if (ndev) {
if (netif_running(ndev)) {
dm9000_reset(db);
dm9000_init_dm9000(ndev);
netif_device_attach(ndev);
}
}
return 0;
}
static int
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 *) ndev->priv);
kfree(ndev); /* free device structure */
PRINTK1("clean_module() exit\n");
return 0;
}
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
},
.probe = dm9000_probe,
.remove = dm9000_drv_remove,
.suspend = dm9000_drv_suspend,
.resume = dm9000_drv_resume,
};
static int __init
dm9000_init(void)
{
printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME);
return platform_driver_register(&dm9000_driver); /* search board and register */
}
static void __exit
dm9000_cleanup(void)
{
platform_driver_unregister(&dm9000_driver);
}
module_init(dm9000_init);
module_exit(dm9000_cleanup);
MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -