/* Stop the interface. The interface is stopped when it is brought. */ static int dmfe_stop(struct net_device *dev) { board_info_t *db = (board_info_t *)dev->priv; DMFE_DBUG(0, "dmfe_stop", 0); /* 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 */ #if FALSE printk("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors); printk("RX CRC %lx\n", db->stats.rx_crc_errors); printk("RX LEN Err %lx\n", db->stats.rx_length_errors); printk("RESET %x\n", db->reset_counter); printk("RESET: TX Timeout %x\n", db->reset_tx_timeout); printk("g_TX_nsr %x\n", g_TX_nsr); #endif return 0; }
void __attribute__((interrupt("IRQ")))dm9000_isr(void) { unsigned char int_status,Rx_ready; unsigned short Rx_status,Rx_len; int i; if(EINT0PEND & (1 << 7)){ //dm9000 int_status = ior(0xfe); if(int_status & 1){ //rx Rx_ready = ior(0xf0); Rx_ready = ior(0xf0); if(Rx_ready == 1){ DM9000_INDEX = 0xf2; Rx_status = DM9000_DATA16; Rx_len = DM9000_DATA16; for(i = 0;i < (Rx_len + 1) / 2;i++){ ((unsigned short*)Net_Rxbuf)[i] = DM9000_DATA16; } /// uart_puts(Net_Rxbuf + 42); } iow(0xfe,1); } if(int_status & 2){//tx if(ior(0x01) & (4 | 8)){ uart_printf("dm9000 send complete\n"); } iow(0xfe,2); } EINT0PEND = (1 << 7); } VIC0ADDRESS = 0; VIC1ADDRESS = 0; }
/* Identify NIC type */ static void identify_nic(board_info_t * db) { u16 phy_reg3; iow(db, 0, DM9000_EXT_MII); phy_reg3 = phy_read(db, 3); switch (phy_reg3 & 0xfff0) { case 0xb900: if (phy_read(db, 31) == 0x4404) { db->nic_type = HOMERUN_NIC; program_dm9801(db, phy_reg3); } else { db->nic_type = LONGRUN_NIC; program_dm9802(db); } break; default: db->nic_type = FASTETHER_NIC; break; } iow(db, 0, DM9000_INT_MII); }
//----DM9000A复位--------------------------------------------------------------- //功能:软件复位DM9000A。某些寄存器的值不受软件复位的影响。 //参数:无 //返回:无 //----------------------------------------------------------------------------- void dm9000a_reset(void) { iow(DM9000A_NCR, 0x01); // RESET do { Djy_DelayUs(30); // 延时30us,应用手册上说至少20us } while (ior(DM9000A_NCR) & 0x01); iow(DM9000A_NCR, 0x00); }
/* Read a word data from SROM */ static u16 read_srom_word(board_info_t *db, int offset) { iow(db, DM9KS_EPAR, offset); iow(db, DM9KS_EPCR, 0x4); while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */ iow(db, DM9KS_EPCR, 0x0); return (ior(db, DM9KS_EPDRL) + (ior(db, DM9KS_EPDRH) << 8) ); }
void dm9000_send(unsigned long addr,int size) { int i; irq_disable(1); DM9000_INDEX = 0xf8; for(i = 0;i < (size + 1)/2; i++) DM9000_DATA16 = ((short *)addr)[i]; iow(0xfd,(size >> 8) & 0xff); iow(0xfc,size & 0xff); iow(0x02,1); irq_enable(1); }
/* Read a word from phyxcer */ static u16 phy_read(board_info_t *db, int reg) { /* Fill the phyxcer register into REG_0C */ iow(db, DM9KS_EPAR, DM9KS_PHY | reg); iow(db, DM9KS_EPCR, 0xc); /* Issue phyxcer read command */ while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */ iow(db, DM9KS_EPCR, 0x0); /* Clear phyxcer read command */ /* The read data keeps on REG_0D & REG_0E */ return ( ior(db, DM9KS_EPDRH) << 8 ) | ior(db, DM9KS_EPDRL); }
/* Write a word to phyxcer */ static void phy_write(board_info_t *db, int reg, u16 value) { /* Fill the phyxcer register into REG_0C */ iow(db, DM9KS_EPAR, DM9KS_PHY | reg); /* Fill the written data into REG_0D & REG_0E */ iow(db, DM9KS_EPDRL, (value & 0xff)); iow(db, DM9KS_EPDRH, ( (value >> 8) & 0xff)); iow(db, DM9KS_EPCR, 0xa); /* Issue phyxcer write command */ while(ior(db, DM9KS_EPCR)&0x1); /* Wait read complete */ iow(db, DM9KS_EPCR, 0x0); /* Clear phyxcer write command */ }
//----写PHY(半字)-------------------------------------------------------------- //功能:向PHY中写入16位的数据 //参数:reg,寄存器偏移地址 // value,要写入的值 //返回:无 //----------------------------------------------------------------------------- static void phyw_h(u8 reg, u16 value) { iow(DM9000A_EPAR, reg|0x40);// 使用内部PHY时bit[7:6]要为01b iow(DM9000A_EPDRL, value&0xFF); iow(DM9000A_EPDRH, (value&0xFF00)>>8); iow(DM9000A_EPCR, 0x0A); // 选择PHY功能,写功能 while (ior(DM9000A_EPCR) & 0x01) { Djy_DelayUs(10); } Djy_DelayUs(150); iow(DM9000A_EPCR, 0x00); // 由程序清零 }
//----复位DM9000A到某一特定的原始状态--------------------------------------------- //功能:让DM9000A回到这样一个状态:除了中断未打开之外,其它有关于DM9000A的所有初始化工作 // 均已完成的地步。DM9000A芯片在从内部RAM中读数据时,如果读到的标志位不是1也不是0 // 时,会调用本函数,本函数需要清空RAM中的数据及使读写指针复位。 //参数:无 //返回:无 //----------------------------------------------------------------------------- void dm9000a_reset_to_new(void) { u8 flags; iow(DM9000A_IMR, 0x00); // 禁止发送、接收中断 ior(DM9000A_ISR); // 清除所有中断状态 flags = 0x80; // 读地址复位到0xC000,写地址复位到0x0000 flags |= 0x01; // 使能接收中断 iow(DM9000A_IMR, flags); iow(DM9000A_TCR, 0); iow(DM9000A_RCR, 0x3d); // 使能接收(广播、Runt包,不使用混杂模式) }
/* Hardware start transmission. * Send a packet to media from the upper layer. */ 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; DMFE_DBUG(0, "dmfe_start_xmit", 0); if (db->tx_pkt_cnt > 1) return 1; netif_stop_queue(dev); /* Disable all interrupt */ iow(db, 0xff, 0x80); /* Move data to DM9000 TX RAM */ data_ptr = (char *) skb->data; outb(0xf8, db->ioaddr); db->sent_pkt_len = skb->len; if (db->io_mode == DM9000_BYTE_MODE) { /* Byte mode */ for (i = 0; i < skb->len; i++) outb((data_ptr[i] & 0xff), db->io_data); } else if (db->io_mode == DM9000_WORD_MODE) { /* Word mode */ tmplen = (skb->len + 1) / 2; for (i = 0; i < tmplen; i++) outw(((u16 *) data_ptr)[i], db->io_data); } else { /* DWord mode */ tmplen = (skb->len + 3) / 4; for (i = 0; i < tmplen; i++) outl(((u32 *) data_ptr)[i], db->io_data); } /* 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, 0xfc, skb->len & 0xff); iow(db, 0xfd, (skb->len >> 8) & 0xff); /* Issue TX polling command */ iow(db, 0x2, 0x1); /* Cleared after TX complete */ /* saved the time stamp */ dev->trans_start = jiffies; } else { /* Second packet */
bool_t debug_dm9000a_write_reg(char *param) { char *word, *next_param; u32 reg = 0; u32 value = 0; // 提取为SOCKET号 if (param) { next_param = param; word = Sh_GetWord(next_param, &next_param); reg = __sh_atol(word); word = Sh_GetWord(next_param, &next_param); value = __sh_atol(word); word = Sh_GetWord(next_param, &next_param); if(word != NULL) { printf("\r\n参数错误\r\n"); return false; } } if (Lock_SempPend(semp_dm9000, 10000*mS) == true) { Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 printf("\r\n写入DM9000A的【%4x】寄存器:%4x", reg, value); iow(reg, value); printf("\r\n"); Int_RestoreAsynLine(cn_int_line_enet); // 打开DM9000A的外部中断 Lock_SempPost(semp_dm9000); } return true; }
/* * Set DM9000 multicast address */ static void dm9000_hash_table_unlocked(struct net_device *dev) { board_info_t *db = netdev_priv(dev); struct netdev_hw_addr *ha; int i, oft; u32 hash_val; u16 hash_table[4]; u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN; //dm9000_dbg(db, 1, "entering %s\n", __func__); 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 */ netdev_for_each_mc_addr(ha, dev) { hash_val = ether_crc_le(6, ha->addr) & 0x3f; hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); }
//----DM9000A初始化------------------------------------------------------------- //功能:初始化DM9000A //参数:无 //返回:正常时返回0,错误时返回错误号 //----------------------------------------------------------------------------- u32 dm9000a_init(void) { u16 i; dm9000a_reset(); // 软件复位 if (dm9000a_probe() != 0) // 探查当前操作的芯片是否为DM9000A(读出ID进行对比) return -1; iow(DM9000A_GPR, 0x00); // PHYPD=0时使能PHY,默认为1表示不使能内部PHY Djy_DelayUs(20*mS); iow(DM9000A_NCR, 0x03); // 选择内部PHY Djy_DelayUs(20); iow(DM9000A_NCR, 0x03); // 选择内部PHY(重复一次) Djy_DelayUs(20); ior(DM9000A_NSR); // 清除发送状态(读取即可清除) dm9000a_set_macaddr(MyMAC); // 设置MAC地址 dm9000a_set_multicastaddr(); // 设置多播地址 set_phy_mode(); // 自动协商 while (!(phyr_h(1) & 0x20)) // 自动协商完成标志位 { Djy_EventDelay(5*mS); // 50mS } // 读回IO、Base模式 ehi.io = (ior(DM9000A_ISR)>>6) & 0x3; ehi.base = (phyr_h(17)>>12) & 0xF; semp_dm9000 = Lock_SempCreate(1, 1, NULL); if (semp_dm9000 == NULL) { return -1; } dm9000a_reset_to_new(); // TODO DM9000A具有IP、UDP、TCP的检验和自动计算功能 //... i = ior(DM9000A_NSR); // xxx del 需要等于0x40才表示连接成功 return 0; }
//----读PHY(半字)-------------------------------------------------------------- //功能:从PHY中读取16位的数据 //参数:reg,寄存器偏移地址 //返回:读得的寄存器值 //----------------------------------------------------------------------------- static u16 phyr_h(u8 reg) { u16 tmp; iow(DM9000A_EPAR, reg|0x40); // 使用内部PHY时bit[7:6]要为01b iow(DM9000A_EPCR, 0x0C); // 选择PHY功能,读取功能 while (ior(DM9000A_EPCR) & 0x01) { Djy_DelayUs(10); } Djy_DelayUs(150); iow(DM9000A_EPCR, 0x00); // 由程序清零 tmp = ior(DM9000A_EPDRL); tmp |= ior(DM9000A_EPDRH)<<8; return tmp; }
static void dm9000_reset(struct board_info *db) { dev_dbg(db->dev, "resetting device\n"); /* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 * The essential point is that we have to do a double reset, and the * instruction is to set LBK into MAC internal loopback mode. */ iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); udelay(100); /* Application note says at least 20 us */ if (ior(db, DM9000_NCR) & 1) dev_err(db->dev, "dm9000 did not respond to first reset\n"); iow(db, DM9000_NCR, 0); iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); udelay(100); if (ior(db, DM9000_NCR) & 1) dev_err(db->dev, "dm9000 did not respond to second reset\n"); }
//#if defined(CONFIG_DM9000_16BIT) static void dm9000_reset(board_info_t *db) { dev_dbg(db->dev, "resetting device\n"); iow(db, DM9000_GPCR, 0x0f); iow(db, DM9000_GPR, 0); iow(db, DM9000_NCR, 3); do { udelay(100); } while (ior(db, DM9000_NCR) & 0x1); iow(db, DM9000_NCR, 0); iow(db, DM9000_NCR, 3); do { udelay(100); } while (ior(db, DM9000_NCR) & 0x1); if ((ior(db, DM9000_PIDL) != 0) || (ior(db, DM9000_PIDH) != 0x90)) printk(KERN_INFO "ERROR : resetting "); }
/* A periodic timer routine */ static void dmfe_timer(unsigned long data) { struct net_device * dev = (struct net_device *)data; board_info_t *db = (board_info_t *)dev->priv; DMFE_DBUG(0, "dmfe_timer()", 0); if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT) { db->cont_rx_pkt_cnt=0; iow(db, DM9KS_IMR, DM9KS_REGFF); } /* Set timer again */ db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer); return; }
/* Set DM9000/DM9010 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]; DMFE_DBUG(0, "dm9000_hash_table()", 0); /* enable promiscuous mode */ if (dev->flags & IFF_PROMISC){ //printk(KERN_INFO "DM9KS:enable promiscuous mode\n"); iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<1)); return; }else{ //printk(KERN_INFO "DM9KS:disable promiscuous mode\n"); iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<1))); } /* Receive all multicast packets */ if (dev->flags & IFF_ALLMULTI){ //printk(KERN_INFO "DM9KS:Pass all multicast\n"); iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)|(1<<3)); }else{ //printk(KERN_INFO "DM9KS:Disable pass all multicast\n"); iow(db, DM9KS_RXCR, ior(db,DM9KS_RXCR)&(~(1<<3))); } /* 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 = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 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); } }
/* Received a packet and pass to upper layer */ static void dmfe_packet_receive(struct net_device *dev) { board_info_t *db = (board_info_t *)dev->priv; struct sk_buff *skb; u8 rxbyte; u16 i, GoodPacket, tmplen = 0, MDRAH, MDRAL; u32 tmpdata; rx_t rx; u16 * ptr = (u16*)℞ u8* rdptr; DMFE_DBUG(0, "dmfe_packet_receive()", 0); db->cont_rx_pkt_cnt=0; do { /*store the value of Memory Data Read address register*/ MDRAH=ior(db, DM9KS_MDRAH); MDRAL=ior(db, DM9KS_MDRAL); ior(db, DM9KS_MRCMDX); /* Dummy read */ rxbyte = inb(db->io_data); /* Got most updated data */ #ifdef CHECKSUM if (rxbyte&0x2) /* check RX byte */ { printk("dm9ks: abnormal!\n"); dmfe_reset(dev); break; }else { if (!(rxbyte&0x1)) break; } #else if (rxbyte==0) break; if (rxbyte>1) { printk("dm9ks: Rxbyte error!\n"); dmfe_reset(dev); break; } #endif /* A packet ready now & Get status/length */ GoodPacket = TRUE; outb(DM9KS_MRCMD, db->io_addr); /* Read packet status & length */ switch (db->io_mode) { case DM9KS_BYTE_MODE: *ptr = inb(db->io_data) + (inb(db->io_data) << 8); *(ptr+1) = inb(db->io_data) + (inb(db->io_data) << 8); break; case DM9KS_WORD_MODE: *ptr = inw(db->io_data); *(ptr+1) = inw(db->io_data); break; case DM9KS_DWORD_MODE: tmpdata = inl(db->io_data); *ptr = tmpdata; *(ptr+1) = tmpdata >> 16; break; default: break; } /* Packet status check */ if (rx.desc.status & 0xbf) { GoodPacket = FALSE; if (rx.desc.status & 0x01) { db->stats.rx_fifo_errors++; printk(KERN_INFO"<RX FIFO error>\n"); } if (rx.desc.status & 0x02) { db->stats.rx_crc_errors++; printk(KERN_INFO"<RX CRC error>\n"); } if (rx.desc.status & 0x80) { db->stats.rx_length_errors++; printk(KERN_INFO"<RX Length error>\n"); } if (rx.desc.status & 0x08) printk(KERN_INFO"<Physical Layer error>\n"); } if (!GoodPacket) { // drop this packet!!! switch (db->io_mode) { case DM9KS_BYTE_MODE: for (i=0; i<rx.desc.length; i++) inb(db->io_data); break; case DM9KS_WORD_MODE: tmplen = (rx.desc.length + 1) / 2; for (i = 0; i < tmplen; i++) inw(db->io_data); break; case DM9KS_DWORD_MODE: tmplen = (rx.desc.length + 3) / 4; for (i = 0; i < tmplen; i++) inl(db->io_data); break; } continue;/*next the packet*/ } skb = dev_alloc_skb(rx.desc.length+4); if (skb == NULL ) { printk(KERN_INFO "%s: Memory squeeze.\n", dev->name); /*re-load the value into Memory data read address register*/ iow(db,DM9KS_MDRAH,MDRAH); iow(db,DM9KS_MDRAL,MDRAL); return; } else { /* Move data from DM9000 */ skb->dev = dev; skb_reserve(skb, 2); rdptr = (u8*)skb_put(skb, rx.desc.length - 4); /* Read received packet from RX SARM */ switch (db->io_mode) { case DM9KS_BYTE_MODE: for (i=0; i<rx.desc.length; i++) rdptr[i]=inb(db->io_data); break; case DM9KS_WORD_MODE: tmplen = (rx.desc.length + 1) / 2; for (i = 0; i < tmplen; i++) ((u16 *)rdptr)[i] = inw(db->io_data); break; case DM9KS_DWORD_MODE: tmplen = (rx.desc.length + 3) / 4; for (i = 0; i < tmplen; i++) ((u32 *)rdptr)[i] = inl(db->io_data); break; } /* Pass to upper layer */ skb->protocol = eth_type_trans(skb,dev); #ifdef CHECKSUM if((rxbyte&0xe0)==0) /* receive packet no checksum fail */ skb->ip_summed = CHECKSUM_UNNECESSARY; #endif netif_rx(skb); dev->last_rx=jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rx.desc.length; db->cont_rx_pkt_cnt++; #ifdef RDBG /* check RX FIFO pointer */ u16 MDRAH1, MDRAL1; u16 tmp_ptr; MDRAH1 = ior(db,DM9KS_MDRAH); MDRAL1 = ior(db,DM9KS_MDRAL); tmp_ptr = (MDRAH<<8)|MDRAL; switch (db->io_mode) { case DM9KS_BYTE_MODE: tmp_ptr += rx.desc.length+4; break; case DM9KS_WORD_MODE: tmp_ptr += ((rx.desc.length+1)/2)*2+4; break; case DM9KS_DWORD_MODE: tmp_ptr += ((rx.desc.length+3)/4)*4+4; break; } if (tmp_ptr >=0x4000) tmp_ptr = (tmp_ptr - 0x4000) + 0xc00; if (tmp_ptr != ((MDRAH1<<8)|MDRAL1)) printk("[dm9ks:RX FIFO ERROR\n"); #endif if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT) { dmfe_tx_done(0); break; } } }while((rxbyte & 0x01) == DM9KS_PKT_RDY); DMFE_DBUG(0, "[END]dmfe_packet_receive()", 0); }
void dm9000_init(void) { SROM_BW |= (1 << 4); GPNCON &= ~(0x3 << 14); GPNCON |= (2 << 14); EINT0CON0 &= ~(7 << 12); EINT0CON0 |= (1 << 12); EINT0MASK &= ~(1 << 7); vic_request(1,dm9000_isr); //dm9000 iow(0x1f,0x00); iow(0x00,1); delay(10); iow(0x00,0); iow(0xff,(1 << 7)); iow(0x10,0x00); iow(0x11,0x11); iow(0x12,0x22); iow(0x13,0x33); iow(0x14,0x44); iow(0x15,0x55); iow(0x01,(1 << 2)|(1 << 3)|(1 << 5)); iow(0xfe,0xff); iow(0xff,(1 << 7)|(1 << 1)|(1 << 0)); iow(0x05,1); }
/* Initilize dm9000 board */ static void dmfe_init_dm9000(struct net_device *dev) { board_info_t *db = (board_info_t *) dev->priv; DMFE_DBUG(0, "dmfe_init_dm9000()", 0); /* set the internal PHY power-on, GPIOs normal, and wait 2ms */ iow(db, 0x1F, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */ udelay(20); /* wait 2ms for PHY power-on ready */ /* do a software reset and wait 20us */ iow(db, DM9000_NCR, 3); udelay(20); /* wait 20us at least for software reset ok */ iow(db, 0, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, * reset on. Added by SPenser */ udelay(20); /* wait 20us at least for software reset ok */ // Marked by Spenser /* set GPIO0=1 then GPIO0=0 to turn off and on the internal PHY */ iow(db, 0x1F, 1); /* GPR (reg_1Fh) bit[0] GPIO0=1 turn-off PHY */ iow(db, 0x1F, 0); /* GPR (reg_1Fh) bit[0] GPIO0=0 activate PHY */ udelay(1000); /* wait 4ms linking PHY (AUTO sense) if RX/TX */ udelay(1000); udelay(1000); udelay(1000); /* I/O mode */ db->io_mode = ior(db, 0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */ /* NIC Type: FASTETHER, HOMERUN, LONGRUN */ identify_nic(db); /* Set PHY */ db->op_mode = media_mode; set_PHY_mode(db); /* Init needed register value */ db->reg0 = DM9000_NCR; if ((db->nic_type != FASTETHER_NIC) && (db->op_mode & DM9000_1M_HPNA)) db->reg0 |= DM9000_EXT_MII; /* User passed argument */ db->reg5 = reg5; db->reg8 = reg8; db->reg9 = reg9; db->rega = rega; /* Program operating register */ iow(db, 0x00, 0x08); iow(db, 0x02, 0); /* TX Polling clear */ iow(db, 0x2f, 0); /* Special Mode */ iow(db, 0x01, 0x2c); /* clear TX status */ iow(db, 0xfe, 0x0f); /* Clear interrupt status */ iow(db, 0x08, 0x37); iow(db, 0x09, 0x38); /* Flow control: High/Low water */ iow(db, 0x0a, 0x29); /* flow control */ /* Set address filter table */ dm9000_hash_table(dev); /* Activate DM9000 */ iow(db, 0x05, db->reg5 | 1); /* RX enable */ iow(db, 0xff, DM9000_REGFF); /* Enable TX/RX interrupt mask */ /* Init Driver variable */ db->link_failed = 1; db->tx_pkt_cnt = 0; db->queue_pkt_len = 0; dev->trans_start = 0; netif_carrier_on(dev); spin_lock_init(&db->lock); }
//----设置MAC地址--------------------------------------------------------------- //功能:设置MAC地址 //参数:mac,以太网的地址数组(6个字节) //返回:无 //----------------------------------------------------------------------------- void dm9000a_set_macaddr(u8 mac[]) { for (int i=0; i<6; i++) iow(DM9000A_PAR0+i, mac[i]); }
//----设置多播地址--------------------------------------------------------------- //功能:设置多播地址 //参数:mulicast,多播地址数组(8个字节) //返回:无 //----------------------------------------------------------------------------- void dm9000a_set_multicastaddr(void) { // 设置多播地址 for (int i=0; i<8; i++) iow(DM9000A_MAR0+i, 0xFF); }
/** * Reciving singlas from ethernet controller - * TX - transmited packet * RX - recived packet * LinkChange - Connected/Diconncted Ethernet Cable * */ void ethernet_interrupts_simple() { frame *curr_frame = 0; int filtered; uint8_t interruption =ior(ISR); //which interruption packet_num++; iow(IMR, 0); // iow(IMR, PAR_set); // printf("ISR 0x%2X \n",interruption); if( interruption & 0x01 ) //RX { iow(ISR,0x01); curr_frame = get_free_frame(); if(curr_frame == 0) { return; //ERROR no more free frames } aaa=ReceivePacket(curr_frame->f_data,&curr_frame->f_len); if(aaa == 0) { filtered = filter_packiets(curr_frame->f_data,curr_frame->f_len); if (filtered == 0) { printf(" RX:UDP \n"); add_rx_frame(curr_frame); } else if (filtered == 10) //arp { printf(" RX:ARP \n"); add_rx_frame(curr_frame); } else { release_frame(curr_frame); } curr_frame = 0; } else { printf("%s Recived Bad Frame \n",__FUNCTION__); release_frame(curr_frame); curr_frame = 0; } /* ethernet_header *tmp = (ethernet_header *) RXT; ether_addr adres = { 0x01, 0x60, 0x6E, 0x11, 0x01, 0x1F }; tmp->eth_src_addr = adres; TransmitPacket(RXT,rx_len);*/ } if(interruption & 0x02) //TX { iow(ISR,0x02); tx_control = 0; } if(interruption & 0x20) //LinkChange { iow(ISR,0x20); /* iow(0x00,0x01); // software reset usleep(10); enable interrupts to activate DM9000 ~on iow(IMR, INTR_set2); IMR REG. FFH PAR=1 only, or + PTM=1& PRM=1 enable RxTx interrupts iow(0xFF, 0x80); enable RX (Broadcast/ ALL_MULTICAST) ~go iow(RCR , RCR_set | RX_ENABLE | PASS_MULTICAST); RCR REG. 05 RXEN Bit [0] = 1 to enable the RX machine/ filter */ //printf(" LinkCHange \n"); if(link_control == 0) link_control = 1; else link_control = 0; } iow(IMR, INTR_set2); }
static irqreturn_t dmfe_interrupt(int irq, void *dev_id) /* for kernel 2.6.20*/ #endif #endif { struct net_device *dev = dev_id; board_info_t *db; int int_status,i; u8 reg_save; DMFE_DBUG(0, "dmfe_interrupt()", 0); /* A real interrupt coming */ db = (board_info_t *)dev->priv; spin_lock(&db->lock); /* Save previous register address */ reg_save = inb(db->io_addr); /* Disable all interrupt */ iow(db, DM9KS_IMR, DM9KS_DISINTR); /* Got DM9000/DM9010 interrupt status */ int_status = ior(db, DM9KS_ISR); /* Got ISR */ iow(db, DM9KS_ISR, int_status); /* Clear ISR status */ /* Link status change */ if (int_status & DM9KS_LINK_INTR) { netif_stop_queue(dev); for(i=0; i<500; i++) /*wait link OK, waiting time =0.5s */ { phy_read(db,0x1); if(phy_read(db,0x1) & 0x4) /*Link OK*/ { /* wait for detected Speed */ for(i=0; i<200;i++) udelay(1000); /* set media speed */ if(phy_read(db,0)&0x2000) db->Speed =100; else db->Speed =10; break; } udelay(1000); } netif_wake_queue(dev); //printk("[INTR]i=%d speed=%d\n",i, (int)(db->Speed)); } /* Received the coming packet */ if (int_status & DM9KS_RX_INTR) dmfe_packet_receive(dev); /* Trnasmit Interrupt check */ if (int_status & DM9KS_TX_INTR) dmfe_tx_done(0); if (db->cont_rx_pkt_cnt>=CONT_RX_PKT_CNT) { iow(db, DM9KS_IMR, 0xa2); } else { /* Re-enable interrupt mask */ iow(db, DM9KS_IMR, DM9KS_REGFF); } /* Restore previous register address */ outb(reg_save, db->io_addr); spin_unlock(&db->lock); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) return IRQ_HANDLED; #endif }
//----发送一帧数据--------------------------------------------------------------- //功能:发送一个数据包到以太网上 //参数:upsec,上层数据包(一个链表结构)的头指针 //返回:正常时为发送的字节数;错误时为-1 //----------------------------------------------------------------------------- s32 __hw_write_out(struct enet_send_section *upsec) { u16 dat; u32 i, len, times, totlen; struct enet_send_section* pt_ssec; // 请求DM9000A硬件操作的信号量,如果没有发出去,则返回 if (Lock_SempPend(semp_dm9000, 0) == true) { Int_SaveAsynLine(cn_int_line_enet); // 关闭DM9000A的外部中断 totlen = 0; pt_ssec = upsec; ADDRW8(DM9000A_MWCMD); if (ehi.io == 0) // 16-bit { u8* pt_data; // 定义字节为8位的,下面进行强制转换 while (pt_ssec != NULL) { pt_data = (u8*)pt_ssec->data; len = pt_ssec->count; totlen += len; if ((ptu32_t)pt_data & 0x01) //判断指针是否双字节对齐 { for (i=0; i<len; i+=2) { dat = pt_data[i] + (pt_data[i+1]<<8); DATAW16(dat); } } else { times = (len+1)/2; for (i=0; i<times; i++) DATAW16(((u16*)pt_data)[i]); } pt_ssec = pt_ssec->next_data_ssection; } } else if (ehi.io == 1) // 32-bit { } else if (ehi.io == 2) // 8-bit { } if (totlen > 0) { iow(DM9000A_TXPLH, (totlen>>8) & 0xff); iow(DM9000A_TXPLL, totlen & 0xff); iow(DM9000A_NSR, 0x2c); // 清除状态寄存器 iow(DM9000A_TCR, ior(DM9000A_TCR) | 0x01); //发送数据到以太网上 // 等待发送完成 // NSR中TX1END及TX2END(发送完成) // ISR中PTM(发送完成) times = 100; // 相当等待于3S while (!(ior(DM9000A_NSR) & 0x0C) || !(ior(DM9000A_ISR) & 0x02)) { if (times == 0) { dm9000a_reset_to_new(); break ; } times--; Djy_DelayUs(10); } }
/* Hardware start transmission. Send a packet to media from the upper layer. */ 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; u16 MDWAH, MDWAL; #ifdef TDBUG /* check TX FIFO pointer */ u16 MDWAH1, MDWAL1; u16 tx_ptr; #endif DMFE_DBUG(0, "dmfe_start_xmit", 0); if (db->chip_revision != 0x1A) { if(db->Speed == 10) {if (db->tx_pkt_cnt >= 1) return 1;} else {if (db->tx_pkt_cnt >= 2) 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->chip_revision != 0x1A) { 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);} }else if (db->tx_pkt_cnt >= 2) netif_stop_queue(dev); /* Disable all interrupt */ iow(db, DM9KS_IMR, DM9KS_DISINTR); MDWAH = ior(db,DM9KS_MDWAH); MDWAL = ior(db,DM9KS_MDWAL); /* 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; outb(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++) outb((data_ptr[i] & 0xff), db->io_data); break; case DM9KS_WORD_MODE: tmplen = (skb->len + 1) / 2; for (i = 0; i < tmplen; i++) outw(((u16 *)data_ptr)[i], db->io_data); break; case DM9KS_DWORD_MODE: tmplen = (skb->len + 3) / 4; for (i = 0; i< tmplen; i++) outl(((u32 *)data_ptr)[i], db->io_data); break; } #ifndef ETRANS /* Issue TX polling command */ iow(db, DM9KS_TCR, 0x1); /* Cleared after TX complete*/ #endif #ifdef TDBUG /* check TX FIFO pointer */ MDWAH1 = ior(db,DM9KS_MDWAH); MDWAL1 = ior(db,DM9KS_MDWAL); tx_ptr = (MDWAH<<8)|MDWAL; switch (db->io_mode) { case DM9KS_BYTE_MODE: tx_ptr += skb->len; break; case DM9KS_WORD_MODE: tx_ptr += ((skb->len + 1) / 2)*2; break; case DM9KS_DWORD_MODE: tx_ptr += ((skb->len+3)/4)*4; break; } if (tx_ptr > 0x0bff) tx_ptr -= 0x0c00; if (tx_ptr != ((MDWAH1<<8)|MDWAL1)) printk("[dm9ks:TX FIFO ERROR\n"); #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; }
/* Initilize dm9000 board */ static void dmfe_init_dm9000(struct net_device *dev) { board_info_t *db = (board_info_t *)dev->priv; DMFE_DBUG(0, "dmfe_init_dm9000()", 0); spin_lock_init(&db->lock); iow(db, DM9KS_GPR, 0); /* GPR (reg_1Fh)bit GPIO0=0 pre-activate PHY */ mdelay(20); /* wait for PHY power-on ready */ /* do a software reset and wait 20us */ iow(db, DM9KS_NCR, 3); udelay(20); /* wait 20us at least for software reset ok */ iow(db, DM9KS_NCR, 3); /* NCR (reg_00h) bit[0] RST=1 & Loopback=1, reset on */ udelay(20); /* wait 20us at least for software reset ok */ /* I/O mode */ db->io_mode = ior(db, DM9KS_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ /* Set PHY */ db->op_mode = media_mode; set_PHY_mode(db); /* Program operating register */ iow(db, DM9KS_NCR, 0); iow(db, DM9KS_TCR, 0); /* TX Polling clear */ iow(db, DM9KS_BPTR, 0x3f); /* Less 3kb, 600us */ iow(db, DM9KS_SMCR, 0); /* Special Mode */ iow(db, DM9KS_NSR, 0x2c); /* clear TX status */ iow(db, DM9KS_ISR, 0x0f); /* Clear interrupt status */ iow(db, DM9KS_TCR2, 0x80); /* Set LED mode 1 */ if (db->chip_revision == 0x1A){ /* Data bus current driving/sinking capability */ iow(db, DM9KS_BUSCR, 0x01); /* default: 2mA */ } #ifdef FLOW_CONTROL iow(db, DM9KS_BPTR, 0x37); iow(db, DM9KS_FCTR, 0x38); iow(db, DM9KS_FCR, 0x29); #endif #ifdef DM8606 iow(db,0x34,1); #endif if (dev->features & NETIF_F_HW_CSUM){ printk(KERN_INFO "DM9KS:enable TX checksum\n"); iow(db, DM9KS_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */ } if (db->rx_csum){ printk(KERN_INFO "DM9KS:enable RX checksum\n"); iow(db, DM9KS_RCSR, 0x02); /* RX checksum enable */ } #ifdef ETRANS /*If TX loading is heavy, the driver can try to anbel "early transmit". The programmer can tune the "Early Transmit Threshold" to get the optimization. (DM9KS_ETXCSR.[1-0]) Side Effect: It will happen "Transmit under-run". When TX under-run always happens, the programmer can increase the value of "Early Transmit Threshold". */ iow(db, DM9KS_ETXCSR, 0x83); #endif /* Set address filter table */ dm9000_hash_table(dev); /* Activate DM9000/DM9010 */ iow(db, DM9KS_IMR, DM9KS_REGFF); /* Enable TX/RX interrupt mask */ iow(db, DM9KS_RXCR, DM9KS_REG05 | 1); /* RX enable */ /* Init Driver variable */ db->tx_pkt_cnt = 0; netif_carrier_on(dev); }
void handle_rx_snif(simrf_rx_info_t *rxinfo, uint8_t *rx_buffer) { int i; iow(magic[0]); iow(magic[1]); iow(magic[2]); iow(magic[3]); iow(1); // version iow(0); // CMD_FRAME iow(rxinfo->frame_length + 3 + 2); iow(rxinfo->fc_raw & 0xff); iow(rxinfo->fc_raw >> 8); iow(rxinfo->sequence_number); for (i = 0; i < rxinfo->frame_length; ++i) { iow(rx_buffer[i]); } iow(rxinfo->rssi); // This is TI cc25xx FCS format, with FCS valid hardcoded iow(rxinfo->lqi | 0x80); }