📄 tlan.c
字号:
priv->speed = ( ( dev->mem_start & 0x30 ) == 0x30 ) ? 0 : ( dev->mem_start & 0x30 ) >> 4; if ( priv->speed == 0x1 ) { priv->speed = TLAN_SPEED_10; } else if ( priv->speed == 0x2 ) { priv->speed = TLAN_SPEED_100; } priv->sa_int = dev->mem_start & 0x02; priv->debug = dev->mem_end; printk("TLAN %d.%d: %s irq=%2d io=%04x, %s, Rev. %d\n", TLanVersionMajor, TLanVersionMinor, dev->name, (int) irq, io_base, priv->adapter->deviceLabel, priv->adapterRev ); TLan_Init( dev ); return 0;} /* tlan_probe */#endif /* MODULE */ /*************************************************************** * TLan_PciProbe * * Returns: * 1 if another TLAN card was found, 0 if not. * Parms: * pci_dfn The PCI whatever the card was * found at. * pci_irq The IRQ of the found adapter. * pci_rev The revision of the adapter. * pci_io_base The first IO port used by the * adapter. * dl_ix The index in the device list * of the adapter. * * This function searches for an adapter with PCI vendor * and device IDs matching those in the TLanAdapterList. * The function 'remembers' the last device it found, * and so finds a new device (if anymore are to be found) * each time the function is called. It then looks up * pertinent PCI info and returns it to the caller. * **************************************************************/int TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ){ static int dl_index = 0; static struct pci_dev * pdev = NULL; u16 pci_command; int reg; if ( ! pci_present() ) { printk( "TLAN: PCI Bios not present.\n" ); return 0; } for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) { pdev = pci_find_device( TLanAdapterList[dl_index].vendorId, TLanAdapterList[dl_index].deviceId, pdev); if ( pdev ) { TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", TLanAdapterList[dl_index].vendorId, TLanAdapterList[dl_index].deviceId ); *pci_irq = pdev->irq; *pci_io_base = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; *pci_dfn = pdev->devfn; pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) { pci_read_config_dword( pdev, reg, pci_io_base); if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); break; } else { *pci_io_base = 0; } } if ( *pci_io_base == 0 ) printk("TLAN: IO mapping not available, ignoring device.\n"); pci_set_master(pdev); if ( *pci_io_base ) { *dl_ix = dl_index; return 1; } } else { pdev = NULL; } } return 0;} /* TLan_PciProbe */ /*************************************************************** * TLan_Init * * Returns: * 0 on success, error code otherwise. * Parms: * dev The structure of the device to be * init'ed. * * This function completes the initialization of the * device structure and driver. It reserves the IO * addresses, allocates memory for the lists and bounce * buffers, retrieves the MAC address from the eeprom * and assignes the device's methods. * **************************************************************/int TLan_Init( struct device *dev ){ int dma_size; int err; int i; TLanPrivateInfo *priv; priv = (TLanPrivateInfo *) dev->priv; err = check_region( dev->base_addr, 0x10 ); if ( err ) { printk( "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", dev->name, dev->base_addr, 0x10 ); return -EIO; } request_region( dev->base_addr, 0x10, TLanSignature ); if ( bbuf ) { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); } else { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) ); } priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA ); if ( priv->dmaStorage == NULL ) { printk( "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; if ( bbuf ) { priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); } 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( "TLAN: %s: Error reading MAC from eeprom: %d\n", dev->name, err ); } dev->addr_len = 6; 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; 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. * **************************************************************/int TLan_Open( struct device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; int err; priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION ); if ( priv->sa_int ) { TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Using SA_INTERRUPT\n" ); err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ | SA_INTERRUPT, TLanSignature, dev ); } else { err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); } if ( err ) { printk( "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq ); return -EAGAIN; } MOD_INC_USE_COUNT; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; /* 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, "TLAN: %s: Opened. TLAN Chip Rev: %x\n", dev->name, priv->tlanRev ); return 0;} /* TLan_Open */ /*************************************************************** * 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. * **************************************************************/int TLan_StartTx( struct sk_buff *skb, struct device *dev ){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; TLanList *tail_list; u8 *tail_buffer; int pad; if ( ! priv->phyOnline ) { TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); dev_kfree_skb( skb ); return 0; } tail_list = priv->txList + priv->txTail; if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail ); dev->tbusy = 1; 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 = virt_to_bus( skb->data ); tail_list->buffer[9].address = (u32) 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 = virt_to_bus( TLanPadBuffer ); } 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; } cli(); tail_list->cStat = TLAN_CSTAT_READY; if ( ! priv->txInProgress ) { priv->txInProgress = 1; outw( 0x4, dev->base_addr + TLAN_HOST_INT ); TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Starting TX on buffer %d\n", priv->txTail ); outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); } else { TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: Adding buffer %d to TX channel\n", priv->txTail ); if ( priv->txTail == 0 ) { ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); } else { ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); } } sti(); CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); if ( bbuf ) { dev_kfree_skb( 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. * **************************************************************/void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs){ u32 ack; struct device *dev; u32 host_cmd; u16 host_int; int type; dev = (struct device *) dev_id; cli(); if ( dev->interrupt ) { printk( "TLAN: Re-entering interrupt handler for %s: %ld.\n" , dev->name, dev->interrupt ); } dev->interrupt++; 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 ); } dev->interrupt--; sti();} /* 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. * **************************************************************/int TLan_Close(struct device *dev){ TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; dev->start = 0; dev->tbusy = 1; TLan_ReadAndClearStats( dev, TLAN_RECORD ); outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); if ( priv->timer.function != NULL ) del_timer( &priv->timer ); free_irq( dev->irq, dev ); TLan_FreeLists( dev ); TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Device %s closed.\n", dev->name ); MOD_DEC_USE_COUNT; 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -