?? dm9601.c
字號:
/* Auto Sense Media Policy: Fast EtherNet NIC: don't need to do. Force media mode: don't need to do. HomeRun/LongRun NIC and AUTO_Mode: INT_MII not link, select EXT_MII EXT_MII not link, select INT_MII */ if ( !(d[0] & 0x40) && (dbi->nic_type != FASTETHER_NIC) && (dbi->op_mode == DM9601_AUTO) ) { dbi->net_ctrl_reg ^= 0x80; netif_stop_queue(net); dbi->flags |= NET_CTRL_CHANGE; ctrl_callback(&dbi->ctrl_urb); netif_wake_queue(net); } if ( (d[1] | d[2]) & 0xf4 ) { dbi->stats.tx_errors++; if ( (d[0] | d[1]) & 0x84) /* EXEC & JABBER */ dbi->stats.tx_aborted_errors++; if ( (d[0] | d[1]) & 0x10 ) /* LATE COL */ dbi->stats.tx_window_errors++; if ( (d[0] | d[1]) & 0x60 ) /* NO or LOST CARRIER */ dbi->stats.tx_carrier_errors++; }}#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)static void dm9601_tx_timeout( struct net_device *net ){ dm9601_board_info_t *dbi = net->priv; if ( !dbi ) return; warn("%s: Tx timed out.", net->name); dbi->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; usb_unlink_urb( &dbi->tx_urb ); dbi->stats.tx_errors++;}#endifstatic int dm9601_start_xmit( struct sk_buff *skb, struct net_device *net ){ dm9601_board_info_t *dbi = net->priv; int count = skb->len + 2; int res; __u16 l16 = skb->len; netif_stop_queue( net ); if (!(count & 0x3f)) { count++; l16++; } ((__u16 *)dbi->tx_buff)[0] = cpu_to_le16(l16); memcpy(dbi->tx_buff + 2, skb->data, skb->len); FILL_BULK_URB_TO( &dbi->tx_urb, dbi->usb, usb_sndbulkpipe(dbi->usb, 2), dbi->tx_buff, count, write_bulk_callback, dbi, jiffies + HZ ); if ((res = usb_submit_urb(&dbi->tx_urb))) { warn("failed tx_urb %d", res); dbi->stats.tx_errors++; netif_start_queue( net ); } else { dbi->stats.tx_packets++; dbi->stats.tx_bytes += skb->len; net->trans_start = jiffies; } dev_kfree_skb(skb); return 0;}static struct net_device_stats *dm9601_netdev_stats( struct net_device *dev ){ return &((dm9601_board_info_t *)dev->priv)->stats;}static inline void disable_net_traffic( dm9601_board_info_t *dbi ){ __u8 reg5; write_mii_word(dbi, 1, 0, 0x8000); /* RESET PHY */ get_registers(dbi, 0x5, 1, ®5); reg5 &= 0xfe; set_register(dbi, 0x5, reg5); /* RX disable */ set_register(dbi, 0x1f, 0x01); /* PHY power down */}static void set_phy_mode(dm9601_board_info_t *dbi){ __u16 phy_reg0 = 0x1000, phy_reg4 = 0x01e1; /* PHY media mode setting */ if ( !(dbi->op_mode & DM9601_AUTO) ) { switch(dbi->op_mode) { case DM9601_10MHF: phy_reg4 = 0x0021; break; case DM9601_10MFD: phy_reg4 = 0x0041; break; case DM9601_100MHF: phy_reg4 = 0x0081; break; case DM9601_100MFD: phy_reg4 = 0x0101; break; default: phy_reg0 = 0x8000; break; } write_mii_word(dbi, 1, 4, phy_reg4); /* Set PHY capability */ write_mii_word(dbi, 1, 0, phy_reg0); } /* Active PHY */ set_register( dbi, 0x1e, 0x01 ); /* Let GPIO0 output */ set_register( dbi, 0x1f, 0x00 ); /* Power_on PHY */}/* Init HomeRun DM9801*/static void program_dm9801(dm9601_board_info_t *dbi, u16 HPNA_rev){ __u16 reg16, reg17, reg24, reg25; if ( !nfloor ) nfloor = DM9801_NOISE_FLOOR; read_mii_word(dbi, 1, 16, ®16); read_mii_word(dbi, 1, 17, ®17); read_mii_word(dbi, 1, 24, ®24); read_mii_word(dbi, 1, 25, ®25); switch(HPNA_rev) { case 0xb900: /* DM9801 E3 */ reg16 |= 0x1000; reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xf000; break; case 0xb901: /* DM9801 E4 */ reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xc200; reg17 = (reg17 & 0xfff0) + nfloor + 3; break; case 0xb902: /* DM9801 E5 */ case 0xb903: /* DM9801 E6 */ default: reg16 |= 0x1000; reg25 = ( (reg24 + nfloor - 3) & 0x00ff) | 0xc200; reg17 = (reg17 & 0xfff0) + nfloor; break; } write_mii_word(dbi, 1, 16, reg16); write_mii_word(dbi, 1, 17, reg17); write_mii_word(dbi, 1, 25, reg25);}/* Init LongRun DM9802*/static void program_dm9802(dm9601_board_info_t *dbi){ __u16 reg25; if ( !nfloor ) nfloor = DM9802_NOISE_FLOOR; read_mii_word(dbi, 1, 25, ®25); reg25 = (reg25 & 0xff00) + nfloor; write_mii_word(dbi, 1, 25, reg25);}/* Identify NIC type*/static void identify_nic(dm9601_board_info_t *dbi){ __u16 phy_tmp; /* Select EXT_MII */ dbi->net_ctrl_reg |= 0x80; set_register(dbi, 0x00, dbi->net_ctrl_reg); /* EXT-MII */ read_mii_word(dbi, 1, 3, &phy_tmp); switch(phy_tmp & 0xfff0) { case 0xb900: read_mii_word(dbi, 1, 31, &phy_tmp); if (phy_tmp == 0x4404) { dbi->nic_type = HOMERUN_NIC; program_dm9801(dbi, phy_tmp); } else { dbi->nic_type = LONGRUN_NIC; program_dm9802(dbi); } break; default: dbi->nic_type = FASTETHER_NIC; } /* Select INT_MII */ dbi->net_ctrl_reg &= ~0x80; set_register(dbi, 0x00, dbi->net_ctrl_reg);}static void init_dm9601(struct net_device *net){ dm9601_board_info_t *dbi = (dm9601_board_info_t *)net->priv; /* User passed argument */ dbi->rx_ctrl_reg = reg5 | 0x01; dbi->net_ctrl_reg = 0x00; dbi->reg08 = reg8; dbi->reg09 = reg9; dbi->reg0a = rega; /* RESET device */ set_register(dbi, 0x00, 0x01); /* Reset */ wait_ms(100); /* NIC type: FASTETHER, HOMERUN, LONGRUN */ identify_nic(dbi); /* Set PHY */ dbi->op_mode = dm9601_mode; set_phy_mode(dbi); /* MII selection */ if ( (dbi->nic_type != FASTETHER_NIC) && (dbi->op_mode == DM9601_1M_HPNA) ) dbi->net_ctrl_reg |= 0x80; /* Program operating register */ set_register(dbi, 0x00, dbi->net_ctrl_reg); set_register(dbi, 0x08, dbi->reg08); set_register(dbi, 0x09, dbi->reg09); set_register(dbi, 0x0a, dbi->reg0a); set_register(dbi, 0xf4, 0x26); /* Reset EP1/EP2, INT always return */ set_registers(dbi, 0x10, 0x06, net->dev_addr); /* MAC addr */ dbi->hash_table[3] = 0x8000; /* Broadcast Address */ set_registers(dbi, 0x16, 0x08, dbi->hash_table); /* Hash Table */ set_register(dbi, 0x05, dbi->rx_ctrl_reg); /* Active RX */}static int dm9601_open(struct net_device *net){ dm9601_board_info_t *dbi = (dm9601_board_info_t *)net->priv; int res; down(&dbi->ctrl_sem); MOD_INC_USE_COUNT; FILL_BULK_URB( &dbi->rx_urb, dbi->usb, usb_rcvbulkpipe(dbi->usb, 1), dbi->rx_buff, DM9601_MAX_MTU, read_bulk_callback, dbi ); if ( (res = usb_submit_urb(&dbi->rx_urb)) ) warn("%s: failed rx_urb %d",__FUNCTION__, res ); dbi->rx_buf_flag = 1;#ifdef DM9601_USE_INTR FILL_INT_URB( &dbi->intr_urb, dbi->usb, usb_rcvintpipe(dbi->usb, 3), dbi->intr_buff, sizeof(dbi->intr_buff), intr_callback, dbi, dbi->intr_interval ); if ( (res = usb_submit_urb(&dbi->intr_urb)) ) warn("%s: failed intr_urb %d",__FUNCTION__, res);#endif init_dm9601(net); netif_start_queue( net ); dbi->flags |= DM9601_RUNNING; up(&dbi->ctrl_sem); return 0;}static int dm9601_close( struct net_device *net ){ dm9601_board_info_t *dbi = net->priv; dbi->flags &= ~DM9601_RUNNING; netif_stop_queue(net); if ( !(dbi->flags & DM9601_UNPLUG) ) disable_net_traffic(dbi); usb_unlink_urb(&dbi->rx_urb); usb_unlink_urb(&dbi->tx_urb); usb_unlink_urb(&dbi->ctrl_urb);#ifdef DM9601_USE_INTR usb_unlink_urb(&dbi->intr_urb);#endif MOD_DEC_USE_COUNT;#ifdef STS_DBUG printk("<DM9601> rx errors: %lx \n", dbi->stats.rx_errors); printk("<DM9601> fifo over errors: %lx \n", dbi->stats.rx_fifo_errors); printk("<DM9601> crc errors: %lx \n", dbi->stats.rx_crc_errors); printk("<DM9601> alignment errors: %lx \n", dbi->stats.rx_frame_errors); printk("<DM9601> physical layer errors: %lx \n", dbi->rx_ple_errors); printk("<DM9601> watchdog errors: %lx \n", dbi->rx_wdt_errors); printk("<DM9601> late collision errors: %lx \n", dbi->rx_lc_errors); printk("<DM9601> runt frame errors: %lx \n", dbi->rx_runtf_errors); printk("<DM9601> long frame errors: %lx \n", dbi->rx_longf_errors);#endif return 0;}static int dm9601_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){ __u16 *data = (__u16 *)&rq->ifr_data; dm9601_board_info_t *dbi = net->priv; switch(cmd) { case SIOCDEVPRIVATE: data[0] = dbi->phy; case SIOCDEVPRIVATE+1: read_mii_word(dbi, data[0], data[1]&0x1f, &data[3]); return 0; case SIOCDEVPRIVATE+2: if ( !capable(CAP_NET_ADMIN) ) return -EPERM; write_mii_word(dbi, dbi->phy, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; }}/* Calculate the CRC valude of the Rx packet flag = 1 : return the reverse CRC (for the received packet CRC) 0 : return the normal CRC (for Hash Table index)*/static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag){ u32 crc = ether_crc_le(Len,Data); if (flag) return ~crc; return crc;}static void dm9601_set_multicast( struct net_device *net ){ dm9601_board_info_t *dbi = net->priv; struct dev_mc_list *mcptr = net->mc_list; int count = net->mc_count, i, hash_val; netif_stop_queue(net); if (net->flags & IFF_PROMISC) { dbi->rx_ctrl_reg |= RX_PROMISCUOUS; info("%s: Promiscuous mode enabled", net->name); } else if (net->flags & IFF_ALLMULTI) { dbi->rx_ctrl_reg |= RX_PASS_MULTICAST; dbi->rx_ctrl_reg &= ~RX_PROMISCUOUS; info("%s set allmulti", net->name); } else { dbi->rx_ctrl_reg &= ~RX_PASS_MULTICAST; dbi->rx_ctrl_reg &= ~RX_PROMISCUOUS; /* Clear Hash Table */ for (i = 0; i < 4; i++) dbi->hash_table[i] = 0; /* Set Broadcast Address */ dbi->hash_table[3] = 0x8000; /* the multicast address in Hash Table : 64 bits */ for (i = 0; i < count; i++, mcptr = mcptr->next) { hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f; dbi->hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); } info("%s: set Rx mode", net->name); } dbi->flags |= HASH_REGS_CHANGE | RX_CTRL_CHANGE; ctrl_callback(&dbi->ctrl_urb); netif_wake_queue(net);}static void * dm9601_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct net_device *net; dm9601_board_info_t *dbi; int dev_index = id - dm9601_ids; if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { err("usb_set_configuration() failed"); return NULL; } if(!(dbi = kmalloc(sizeof(dm9601_board_info_t), GFP_KERNEL))) { err("out of memory allocating device structure"); return NULL; } usb_inc_dev_use( dev ); memset(dbi, 0, sizeof(dm9601_board_info_t)); dbi->dev_index = dev_index; init_waitqueue_head( &dbi->ctrl_wait ); net = init_etherdev( NULL, 0 ); if ( !net ) { kfree( dbi ); return NULL; } init_MUTEX(&dbi->ctrl_sem); down(&dbi->ctrl_sem); dbi->usb = dev; dbi->net = net; net->priv = dbi; net->open = dm9601_open; net->stop = dm9601_close; net->watchdog_timeo = DM9601_TX_TIMEOUT; net->tx_timeout = dm9601_tx_timeout; net->do_ioctl = dm9601_ioctl; net->hard_start_xmit = dm9601_start_xmit; net->set_multicast_list = dm9601_set_multicast; net->get_stats = dm9601_netdev_stats; net->mtu = DM9601_MTU; dbi->intr_interval = 0xff; /* Default is 0x80 */ /* Get Node Address */ read_eprom_word(dbi, 0, (__u16 *)net->dev_addr); read_eprom_word(dbi, 1, (__u16 *)(net->dev_addr + 2)); read_eprom_word(dbi, 2, (__u16 *)(net->dev_addr + 4)); dbi->features = usb_dev_id[dev_index].private; info( "%s: %s", net->name, usb_dev_id[dev_index].name ); up(&dbi->ctrl_sem); return dbi;}static void dm9601_disconnect( struct usb_device *dev, void *ptr ){ dm9601_board_info_t *dbi = ptr; if ( !dbi ) { warn("unregistering non-existant device"); return; } dbi->flags |= DM9601_UNPLUG; unregister_netdev( dbi->net ); usb_dec_dev_use( dev ); kfree( dbi ); dbi = NULL;}static struct usb_driver dm9601_driver = { name: "dm9601", probe: dm9601_probe, disconnect: dm9601_disconnect, id_table: dm9601_ids,};int __init dm9601_init(void){ info( "%s", version ); switch(mode) { case DM9601_10MHF: case DM9601_100MHF: case DM9601_10MFD: case DM9601_100MFD: case DM9601_1M_HPNA: dm9601_mode = mode; break; default: dm9601_mode = DM9601_AUTO; } nfloor = (nfloor > 15) ? 0:nfloor; return usb_register( &dm9601_driver );}void __exit dm9601_exit(void){ usb_deregister( &dm9601_driver );}module_init( dm9601_init );module_exit( dm9601_exit );
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -