tlan.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,212 行 · 第 1/5 页
C
2,212 行
err = 0; for ( i = 0; i < 6 ; i++ ) err |= TLan_EeReadByte( dev, (u8) priv->adapter->addrOfs + i, (u8 *) &dev->dev_addr[i] ); if ( err ) { printk(KERN_ERR "TLAN: %s: Error reading MAC from eeprom: %d\n", dev->name, err ); } dev->addr_len = 6; netif_carrier_off(dev); /* Device methods */ dev->open = &TLan_Open; dev->hard_start_xmit = &TLan_StartTx; dev->stop = &TLan_Close; dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl;#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &TLan_Poll;#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; return 0;} /* TLan_Init */ /*************************************************************** * TLan_Open * * Returns: * 0 on success, error code otherwise. * Parms: * dev Structure of device to be opened. * * This routine puts the driver and TLAN adapter in a * state where it is ready to send and receive packets. * It allocates the IRQ, resets and brings the adapter * out of reset, and allows interrupts. It also delays * the startup for autonegotiation or sends a Rx GO * command to the adapter, as appropriate. * **************************************************************/static int TLan_Open( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); if ( err ) { printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); return err; } init_timer(&priv->timer); netif_start_queue(dev); /* NOTE: It might not be necessary to read the stats before a reset if you don't care what the values are. */ TLan_ResetLists( dev ); TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); return 0;} /* TLan_Open */ /************************************************************** * TLan_ioctl * * Returns: * 0 on success, error code otherwise * Params: * dev structure of device to receive ioctl. * * rq ifreq structure to hold userspace data. * * cmd ioctl command. * * *************************************************************/static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ TLanPrivateInfo *priv = dev->priv; struct mii_ioctl_data *data = if_mii(rq); u32 phy = priv->phy[priv->phyNum]; if (!priv->phyOnline) return -EAGAIN; switch(cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ data->phy_id = phy; case SIOCGMIIREG: /* Read MII PHY register. */ TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out); return 0; case SIOCSMIIREG: /* Write MII PHY register. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; TLan_MiiWriteReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); return 0; default: return -EOPNOTSUPP; }} /* tlan_ioctl */ /*************************************************************** * TLan_tx_timeout * * Returns: nothing * * Params: * dev structure of device which timed out * during transmit. * **************************************************************/static void TLan_tx_timeout(struct net_device *dev){ TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); /* Ok so we timed out, lets see what we can do about it...*/ TLan_FreeLists( dev ); TLan_ResetLists( dev ); TLan_ReadAndClearStats( dev, TLAN_IGNORE ); TLan_ResetAdapter( dev ); dev->trans_start = jiffies; netif_wake_queue( dev ); } /*************************************************************** * TLan_StartTx * * Returns: * 0 on success, non-zero on failure. * Parms: * skb A pointer to the sk_buff containing the * frame to be sent. * dev The device to send the data on. * * This function adds a frame to the Tx list to be sent * ASAP. First it verifies that the adapter is ready and * there is room in the queue. Then it sets up the next * available list, copies the frame to the corresponding * buffer. If the adapter Tx channel is idle, it gives * the adapter a Tx Go command on the list, otherwise it * sets the forward address of the previous list to point * to this one. Then it frees the sk_buff. * **************************************************************/static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; TLanList *tail_list; dma_addr_t tail_list_phys; u8 *tail_buffer; int pad; unsigned long flags; if ( ! priv->phyOnline ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb_any(skb); return 0; } tail_list = priv->txList + priv->txTail; tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); netif_stop_queue(dev); priv->txBusyCount++; return 1; } tail_list->forward = 0; if ( bbuf ) { tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); memcpy( tail_buffer, skb->data, skb->len ); } else { tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); TLan_StoreSKB(tail_list, skb); } pad = TLAN_MIN_FRAME_SIZE - skb->len; if ( pad > 0 ) { tail_list->frameSize = (u16) skb->len + pad; tail_list->buffer[0].count = (u32) skb->len; tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; tail_list->buffer[1].address = TLanPadBufferDMA; } else { tail_list->frameSize = (u16) skb->len; tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; tail_list->buffer[1].count = 0; tail_list->buffer[1].address = 0; } spin_lock_irqsave(&priv->lock, flags); tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( tail_list_phys, dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD ); } else { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = tail_list_phys; } else { ( priv->txList + ( priv->txTail - 1 ) )->forward = tail_list_phys; } } spin_unlock_irqrestore(&priv->lock, flags); CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); if ( bbuf ) dev_kfree_skb_any(skb); dev->trans_start = jiffies; return 0;} /* TLan_StartTx */ /*************************************************************** * TLan_HandleInterrupt * * Returns: * Nothing * Parms: * irq The line on which the interrupt * occurred. * dev_id A pointer to the device assigned to * this irq line. * regs ??? * * This function handles an interrupt generated by its * assigned TLAN adapter. The function deactivates * interrupts on its adapter, records the type of * interrupt, executes the appropriate subhandler, and * acknowdges the interrupt to the adapter (thus * re-enabling adapter interrupts. * **************************************************************/static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs){ u32 ack; struct net_device *dev; u32 host_cmd; u16 host_int; int type; TLanPrivateInfo *priv; dev = dev_id; priv = dev->priv; spin_lock(&priv->lock); host_int = inw( dev->base_addr + TLAN_HOST_INT ); outw( host_int, dev->base_addr + TLAN_HOST_INT ); type = ( host_int & TLAN_HI_IT_MASK ) >> 2; ack = TLanIntVector[type]( dev, host_int ); if ( ack ) { host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); } spin_unlock(&priv->lock); return IRQ_HANDLED;} /* TLan_HandleInterrupts */ /*************************************************************** * TLan_Close * * Returns: * An error code. * Parms: * dev The device structure of the device to * close. * * This function shuts down the adapter. It records any * stats, puts the adapter into reset state, deactivates * its time as needed, and frees the irq it is using. * **************************************************************/static int TLan_Close(struct net_device *dev){ TLanPrivateInfo *priv = dev->priv; netif_stop_queue(dev); priv->neg_be_verbose = 0; TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); if ( priv->timer.function != NULL ) { del_timer_sync( &priv->timer ); priv->timer.function = NULL; } free_irq( dev->irq, dev ); TLan_FreeLists( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name ); return 0;} /* TLan_Close */ /*************************************************************** * TLan_GetStats * * Returns: * A pointer to the device's statistics structure. * Parms: * dev The device structure to return the * stats for. * * This function updates the devices statistics by reading * the TLAN chip's onboard registers. Then it returns the * address of the statistics structure. * **************************************************************/static struct net_device_stats *TLan_GetStats( struct net_device *dev ){ TLanPrivateInfo *priv = dev->priv; int i; /* Should only read stats if open ? */ TLan_ReadAndClearStats( dev, TLAN_RECORD ); TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, priv->rxEocCount ); TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount ); if ( debug & TLAN_DEBUG_GNRL ) { TLan_PrintDio( dev->base_addr ); TLan_PhyPrint( dev ); } if ( debug & TLAN_DEBUG_LIST ) { for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) TLan_PrintList( priv->rxList + i, "RX", i ); for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) TLan_PrintList( priv->txList + i, "TX", i ); } return ( &( (TLanPrivateInfo *) dev->priv )->stats );} /* TLan_GetStats */ /*************************************************************** * TLan_SetMulticastList * * Returns: * Nothing * Parms: * dev The device structure to set the * multicast list for. * * This function sets the TLAN adaptor to various receive * modes. If the IFF_PROMISC flag is set, promiscuous * mode is acitviated. Otherwise, promiscuous mode is * turned off. If the IFF_ALLMULTI flag is set, then * the hash table is set to receive all group addresses. * Otherwise, the first three multicast addresses are * stored in AREG_1-3, and the rest are selected via the * hash table, as necessary. * **************************************************************/static void TLan_SetMulticastList( struct net_device *dev ){ struct dev_mc_list *dmi = dev->mc_list; u32 hash1 = 0; u32 hash2 = 0; int i; u32 offset; u8 tmp; if ( dev->flags & IFF_PROMISC ) { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); } else { tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); if ( dev->flags & IFF_ALLMULTI ) { for ( i = 0; i < 3; i++ ) TLan_SetMac( dev, i + 1, NULL ); TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); } else { for ( i = 0; i < dev->mc_count; i++ ) { if ( i < 3 ) { TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); } else { offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); if ( offset < 32 ) hash1 |= ( 1 << offset ); else hash2 |= ( 1 << ( offset - 32 ) );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?