📄 st268.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 == ST268_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 ST268_tx_timeout( struct net_device *net ){ ST268_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 ST268_start_xmit( struct sk_buff *skb, struct net_device *net ){ ST268_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 *ST268_netdev_stats( struct net_device *dev ){ return &((ST268_board_info_t *)dev->priv)->stats;}static inline void disable_net_traffic( ST268_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(ST268_board_info_t *dbi){ __u16 phy_reg0 = 0x1000, phy_reg4 = 0x01e1; /* PHY media mode setting */ if ( !(dbi->op_mode & ST268_AUTO) ) { switch(dbi->op_mode) { case ST268_10MHF: phy_reg4 = 0x0021; break; case ST268_10MFD: phy_reg4 = 0x0041; break; case ST268_100MHF: phy_reg4 = 0x0081; break; case ST268_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(ST268_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(ST268_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(ST268_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_ST268(struct net_device *net){ ST268_board_info_t *dbi = (ST268_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 = ST268_mode; set_phy_mode(dbi); /* MII selection */ if ( (dbi->nic_type != FASTETHER_NIC) && (dbi->op_mode == ST268_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 ST268_open(struct net_device *net){ ST268_board_info_t *dbi = (ST268_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, ST268_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 ST268_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_ST268(net); netif_start_queue( net ); dbi->flags |= ST268_RUNNING; up(&dbi->ctrl_sem); return 0;}static int ST268_close( struct net_device *net ){ ST268_board_info_t *dbi = net->priv; dbi->flags &= ~ST268_RUNNING; netif_stop_queue(net); if ( !(dbi->flags & ST268_UNPLUG) ) disable_net_traffic(dbi); usb_unlink_urb(&dbi->rx_urb); usb_unlink_urb(&dbi->tx_urb); usb_unlink_urb(&dbi->ctrl_urb);#ifdef ST268_USE_INTR usb_unlink_urb(&dbi->intr_urb);#endif MOD_DEC_USE_COUNT;#ifdef STS_DBUG printk("<ST268> rx errors: %lx \n", dbi->stats.rx_errors); printk("<ST268> fifo over errors: %lx \n", dbi->stats.rx_fifo_errors); printk("<ST268> crc errors: %lx \n", dbi->stats.rx_crc_errors); printk("<ST268> alignment errors: %lx \n", dbi->stats.rx_frame_errors); printk("<ST268> physical layer errors: %lx \n", dbi->rx_ple_errors); printk("<ST268> watchdog errors: %lx \n", dbi->rx_wdt_errors); printk("<ST268> late collision errors: %lx \n", dbi->rx_lc_errors); printk("<ST268> runt frame errors: %lx \n", dbi->rx_runtf_errors); printk("<ST268> long frame errors: %lx \n", dbi->rx_longf_errors);#endif return 0;}static int ST268_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){ __u16 *data = (__u16 *)&rq->ifr_data; ST268_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 ST268_set_multicast( struct net_device *net ){ ST268_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 * ST268_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct net_device *net; ST268_board_info_t *dbi; int dev_index = id - ST268_ids; if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { err("usb_set_configuration() failed"); return NULL; } if(!(dbi = kmalloc(sizeof(ST268_board_info_t), GFP_KERNEL))) { err("out of memory allocating device structure"); return NULL; } usb_inc_dev_use( dev ); memset(dbi, 0, sizeof(ST268_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 = ST268_open; net->stop = ST268_close; net->watchdog_timeo = ST268_TX_TIMEOUT; net->tx_timeout = ST268_tx_timeout; net->do_ioctl = ST268_ioctl; net->hard_start_xmit = ST268_start_xmit; net->set_multicast_list = ST268_set_multicast; net->get_stats = ST268_netdev_stats; net->mtu = ST268_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 ST268_disconnect( struct usb_device *dev, void *ptr ){ ST268_board_info_t *dbi = ptr; if ( !dbi ) { warn("unregistering non-existant device"); return; } dbi->flags |= ST268_UNPLUG; unregister_netdev( dbi->net ); usb_dec_dev_use( dev ); kfree( dbi ); dbi = NULL;}static struct usb_driver ST268_driver = { name: "ST268", probe: ST268_probe, disconnect: ST268_disconnect, id_table: ST268_ids,};int __init ST268_init(void){ info( "%s", version ); switch(mode) { case ST268_10MHF: case ST268_100MHF: case ST268_10MFD: case ST268_100MFD: case ST268_1M_HPNA: ST268_mode = mode; break; default: ST268_mode = ST268_AUTO; } nfloor = (nfloor > 15) ? 0:nfloor; return usb_register( &ST268_driver );}void __exit ST268_exit(void){ usb_deregister( &ST268_driver );}module_init( ST268_init );module_exit( ST268_exit );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -