/******************************************************************************* * * Linux ThunderLAN Driver * * tlan.c * by James Banks * * (C) 1997-1998 Caldera, Inc. * (C) 1998 James Banks * (C) 1999-2001 Torben Mathiasen * (C) 2002 Samuel Chessman * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * ** Useful (if not required) reading: * * Texas Instruments, ThunderLAN Programmer's Guide, * TI Literature Number SPWU013A * available in PDF format from www.ti.com * Level One, LXT901 and LXT970 Data Sheets * available in PDF format from www.level1.com * National Semiconductor, DP83840A Data Sheet * available in PDF format from www.national.com * Microchip Technology, 24C01A/02A/04A Data Sheet * available in PDF format from www.microchip.com *
******************************************************************************/
MODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>");
MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
MODULE_LICENSE("GPL");
/* Turn on debugging. * See Documentation/networking/device_drivers/ethernet/ti/tlan.rst for details
*/ staticint debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
/*************************************************************** * tlan_remove_one * * Returns: * Nothing * Parms: * None * * Goes through the TLanDevices list and frees the device * structs and memory associated with each device (lists * and buffers). It also ureserves the IO port regions * associated with this device. *
**************************************************************/
staticvoid tlan_start(struct net_device *dev)
{
tlan_reset_lists(dev); /* NOTE: It might not be necessary to read the stats before a reset if you don't care what the values are.
*/
tlan_read_and_clear_stats(dev, TLAN_IGNORE);
tlan_reset_adapter(dev);
netif_wake_queue(dev);
}
/* *************************************************************** * tlan_probe1 * * Returns: * 0 on success, error code on error * Parms: * none * * The name is lower case to fit in with all the rest of * the netcard_probe names. This function looks for * another TLan based adapter, setting it up with the * allocated device struct if one is found. * tlan_probe has been ported to the new net API and * now allocates its own device structure. This function * is also used by modules. *
**************************************************************/
staticint tlan_probe1(struct pci_dev *pdev, long ioaddr, int irq, int rev, conststruct pci_device_id *ent)
{
/* This will be used when we get an adapter error from
* within our irq handler */
INIT_WORK(&priv->tlan_tqueue, tlan_tx_timeout_work);
spin_lock_init(&priv->lock);
rc = tlan_init(dev); if (rc) {
pr_err("Could not set up device\n"); goto err_out_free_dev;
}
rc = register_netdev(dev); if (rc) {
pr_err("Could not register device\n"); goto err_out_uninit;
}
tlan_devices_installed++;
boards_found++;
/* pdev is NULL if this is an EISA device */ if (pdev)
tlan_have_pci++; else {
priv->next_device = tlan_eisa_devices;
tlan_eisa_devices = dev;
tlan_have_eisa++;
}
/************************************************************** * tlan_eisa_probe * * Returns: 0 on success, 1 otherwise * * Parms: None * * * This functions probes for EISA devices and calls * TLan_probe1 when one is found. *
*************************************************************/
staticvoid __init tlan_eisa_probe(void)
{ long ioaddr; int irq;
u16 device_id;
if (!EISA_bus) {
TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n"); return;
}
/* Loop through all slots of the EISA bus */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
/*************************************************************** * 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. *
**************************************************************/
staticint tlan_init(struct net_device *dev)
{ int dma_size; int err; int i; struct tlan_priv *priv;
u8 addr[ETH_ALEN];
/*************************************************************** * 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. *
**************************************************************/
/*************************************************************** * tlan_tx_timeout * * Returns: nothing * * Params: * dev structure of device which timed out * during transmit. *
**************************************************************/
/* Ok so we timed out, lets see what we can do about it...*/
tlan_free_lists(dev);
tlan_reset_lists(dev);
tlan_read_and_clear_stats(dev, TLAN_IGNORE);
tlan_reset_adapter(dev);
netif_trans_update(dev); /* prevent tx timeout */
netif_wake_queue(dev);
}
/*************************************************************** * tlan_tx_timeout_work * * Returns: nothing * * Params: * work work item of device which timed out *
**************************************************************/
/*************************************************************** * tlan_start_tx * * 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. *
**************************************************************/
/*************************************************************** * tlan_handle_interrupt * * Returns: * Nothing * Parms: * irq The line on which the interrupt * occurred. * dev_id A pointer to the device assigned to * this irq line. * * 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. *
**************************************************************/
/*************************************************************** * 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. *
**************************************************************/
/*************************************************************** * tlan_get_stats * * 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. *
**************************************************************/
/* Should only read stats if open ? */
tlan_read_and_clear_stats(dev, TLAN_RECORD);
TLAN_DBG(TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name,
priv->rx_eoc_count);
TLAN_DBG(TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name,
priv->tx_busy_count); if (debug & TLAN_DEBUG_GNRL) {
tlan_print_dio(dev->base_addr);
tlan_phy_print(dev);
} if (debug & TLAN_DEBUG_LIST) { for (i = 0; i < TLAN_NUM_RX_LISTS; i++)
tlan_print_list(priv->rx_list + i, "RX", i); for (i = 0; i < TLAN_NUM_TX_LISTS; i++)
tlan_print_list(priv->tx_list + i, "TX", i);
}
return &dev->stats;
}
/*************************************************************** * tlan_set_multicast_list * * 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. *
**************************************************************/
please see chap. 4, "Interrupt Handling" of the "ThunderLAN Programmer's Guide" for more informations on handling interrupts generated by TLAN based adapters.
/*************************************************************** * tlan_handle_tx_eof * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles Tx EOF interrupts which are raised * by the adapter when it has completed sending the * contents of a buffer. If detemines which list/buffer * was completed and resets it. If the buffer was the last * in the channel (EOC), then the function checks to see if * another buffer is ready to send, and if so, sends a Tx * Go command. Finally, the driver activates/continues the * activity LED. *
**************************************************************/
/*************************************************************** * TLan_HandleStatOverflow * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Statistics Overflow interrupt * which means that one or more of the TLAN statistics * registers has reached 1/2 capacity and needs to be read. *
**************************************************************/
/*************************************************************** * TLan_HandleRxEOF * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Rx EOF interrupt which * indicates a frame has been received by the adapter from * the net and the frame has been transferred to memory. * The function determines the bounce buffer the frame has * been loaded into, creates a new sk_buff big enough to * hold the frame, and sends it to protocol stack. It * then resets the used buffer and appends it to the end * of the list. If the frame was the last in the Rx * channel (EOC), the function restarts the receive channel * by sending an Rx Go command to the adapter. Then it * activates/continues the activity LED. *
**************************************************************/
/*************************************************************** * tlan_handle_dummy * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles the Dummy interrupt, which is * raised whenever a test interrupt is generated by setting * the Req_Int bit of HOST_CMD to 1. *
**************************************************************/
/*************************************************************** * tlan_handle_tx_eoc * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This driver is structured to determine EOC occurrences by * reading the CSTAT member of the list structure. Tx EOC * interrupts are disabled via the DIO INTDIS register. * However, TLAN chips before revision 3.0 didn't have this * functionality, so process EOC events if this is the * case. *
**************************************************************/
/*************************************************************** * tlan_handle_status_check * * Returns: * 0 if Adapter check, 1 if Network Status check. * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This function handles Adapter Check/Network Status * interrupts generated by the adapter. It checks the * vector in the HOST_INT register to determine if it is * an Adapter Check interrupt. If so, it resets the * adapter. Otherwise it clears the status registers * and services the PHY. *
**************************************************************/
/*************************************************************** * tlan_handle_rx_eoc * * Returns: * 1 * Parms: * dev Device assigned the IRQ that was * raised. * host_int The contents of the HOST_INT * port. * * This driver is structured to determine EOC occurrences by * reading the CSTAT member of the list structure. Rx EOC * interrupts are disabled via the DIO INTDIS register. * However, TLAN chips before revision 3.0 didn't have this * CSTAT member or a INTDIS register, so if this chip is * pre-3.0, process EOC interrupts normally. *
**************************************************************/
/*************************************************************** * tlan_timer * * Returns: * Nothing * Parms: * data A value given to add timer when * add_timer was called. * * This function handles timed functionality for the * TLAN driver. The two current timer uses are for * delaying for autonegotionation and driving the ACT LED. * - Autonegotiation requires being allowed about * 2 1/2 seconds before attempting to transmit a * packet. It would be a very bad thing to hang * the kernel this long, so the driver doesn't * allow transmission 'til after this time, for * certain PHYs. It would be much nicer if all * PHYs were interrupt-capable like the internal * PHY. * - The ACT LED, which shows adapter activity, is * driven by the driver, and so must be left on * for a short period to power up the LED so it * can be seen. This delay can be changed by * changing the TLAN_TIMER_ACT_DELAY in tlan.h, * if desired. 100 ms produces a slightly * sluggish response. *
**************************************************************/
/*************************************************************** * tlan_reset_lists * * Returns: * Nothing * Parms: * dev The device structure with the list * structures to be reset. * * This routine sets the variables associated with managing * the TLAN lists to their initial values. *
**************************************************************/
for (i = 0; i < TLAN_NUM_TX_LISTS; i++) {
list = priv->tx_list + i;
skb = tlan_get_skb(list); if (skb) {
dma_unmap_single(&priv->pci_dev->dev,
list->buffer[0].address,
max(skb->len, (unsignedint)TLAN_MIN_FRAME_SIZE),
DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
list->buffer[8].address = 0;
list->buffer[9].address = 0;
}
}
for (i = 0; i < TLAN_NUM_RX_LISTS; i++) {
list = priv->rx_list + i;
skb = tlan_get_skb(list); if (skb) {
dma_unmap_single(&priv->pci_dev->dev,
list->buffer[0].address,
TLAN_MAX_FRAME_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
list->buffer[8].address = 0;
list->buffer[9].address = 0;
}
}
}
/*************************************************************** * tlan_print_dio * * Returns: * Nothing * Parms: * io_base Base IO port of the device of * which to print DIO registers. * * This function prints out all the internal (DIO) * registers of a TLAN chip. *
**************************************************************/
staticvoid tlan_print_dio(u16 io_base)
{
u32 data0, data1; int i;
pr_info("Contents of internal registers for io base 0x%04hx\n",
io_base);
pr_info("Off. +0 +4\n"); for (i = 0; i < 0x4C; i += 8) {
data0 = tlan_dio_read32(io_base, i);
data1 = tlan_dio_read32(io_base, i + 0x4);
pr_info("0x%02x 0x%08x 0x%08x\n", i, data0, data1);
}
}
/*************************************************************** * TLan_PrintList * * Returns: * Nothing * Parms: * list A pointer to the struct tlan_list structure to * be printed. * type A string to designate type of list, * "Rx" or "Tx". * num The index of the list. * * This function prints out the contents of the list * pointed to by the list parameter. *
**************************************************************/
staticvoid tlan_print_list(struct tlan_list *list, char *type, int num)
{ int i;
pr_info("%s List %d at %p\n", type, num, list);
pr_info(" Forward = 0x%08x\n", list->forward);
pr_info(" CSTAT = 0x%04hx\n", list->c_stat);
pr_info(" Frame Size = 0x%04hx\n", list->frame_size); /* for (i = 0; i < 10; i++) { */ for (i = 0; i < 2; i++) {
pr_info(" Buffer[%d].count, addr = 0x%08x, 0x%08x\n",
i, list->buffer[i].count, list->buffer[i].address);
}
}
/*************************************************************** * tlan_read_and_clear_stats * * Returns: * Nothing * Parms: * dev Pointer to device structure of adapter * to which to read stats. * record Flag indicating whether to add * * This functions reads all the internal status registers * of the TLAN chip, which clears them as a side effect. * It then either adds the values to the device's status * struct, or discards them, depending on whether record * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). *
**************************************************************/
/*************************************************************** * TLan_Reset * * Returns: * 0 * Parms: * dev Pointer to device structure of adapter * to be reset. * * This function resets the adapter and it's physical * device. See Chap. 3, pp. 9-10 of the "ThunderLAN * Programmer's Guide" for details. The routine tries to * implement what is detailed there, though adjustments * have been made. *
**************************************************************/
/* don't power down internal PHY if we're going to use it */ if (priv->phy_num == 0 ||
(priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10))
data |= TLAN_NET_CFG_PHY_EN;
tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data);
if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY)
tlan_finish_reset(dev); else
tlan_phy_power_down(dev);
/*************************************************************** * tlan_set_mac * * Returns: * Nothing * Parms: * dev Pointer to device structure of adapter * on which to change the AREG. * areg The AREG to set the address in (0 - 3). * mac A pointer to an array of chars. Each * element stores one byte of the address. * IE, it isn't in ascii. * * This function transfers a MAC address to one of the * TLAN AREGs (address registers). The TLAN chip locks * the register on writing to offset 0 and unlocks the * register after writing to offset 5. If NULL is passed * in mac, then the AREG is filled with 0's. *
**************************************************************/
staticvoid tlan_set_mac(struct net_device *dev, int areg, constchar *mac)
{ int i;
areg *= 6;
if (mac != NULL) { for (i = 0; i < 6; i++)
tlan_dio_write8(dev->base_addr,
TLAN_AREG_0 + areg + i, mac[i]);
} else { for (i = 0; i < 6; i++)
tlan_dio_write8(dev->base_addr,
TLAN_AREG_0 + areg + i, 0);
}
/********************************************************************* * __tlan_phy_print * * Returns: * Nothing * Parms: * dev A pointer to the device structure of the * TLAN device having the PHYs to be detailed. * * This function prints the registers a PHY (aka transceiver). *
********************************************************************/
/********************************************************************* * tlan_phy_detect * * Returns: * Nothing * Parms: * dev A pointer to the device structure of the adapter * for which the PHY needs determined. * * So far I've found that adapters which have external PHYs * may also use the internal PHY for part of the functionality. * (eg, AUI/Thinnet). This function finds out if this TLAN * chip has an internal PHY, and then finds the first external * PHY (starting from address 0) if it exists). *
********************************************************************/
TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name);
value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE;
tlan_mii_sync(dev->base_addr);
tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); if ((priv->phy_num == 0) && (priv->phy[1] != TLAN_PHY_NONE)) { /* if using internal PHY, the external PHY must be powered on */ if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10)
value = MII_GC_ISOLATE; /* just isolate it from MII */
tlan_mii_sync(dev->base_addr);
tlan_mii_write_reg(dev, priv->phy[1], MII_GEN_CTL, value);
}
/* Wait for 50 ms and powerup * This is arbitrary. It is intended to make sure the * transceiver settles.
*/
tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_PUP);
TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name);
tlan_mii_sync(dev->base_addr);
value = MII_GC_LOOPBK;
tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value);
tlan_mii_sync(dev->base_addr); /* Wait for 500 ms and reset the * transceiver. The TLAN docs say both 50 ms and * 500 ms, so do the longer, just in case.
*/
tlan_set_timer(dev, msecs_to_jiffies(500), TLAN_TIMER_PHY_RESET);
TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Resetting PHY.\n", dev->name);
tlan_mii_sync(dev->base_addr);
value = MII_GC_LOOPBK | MII_GC_RESET;
tlan_mii_write_reg(dev, phy, MII_GEN_CTL, value); do {
tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); if (time_after(jiffies, timeout)) {
netdev_err(dev, "PHY reset timeout\n"); return;
}
} while (value & MII_GC_RESET);
/* Wait for 500 ms and initialize. * I don't remember why I wait this long. * I've changed this to 50ms, as it seems long enough.
*/
tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_START_LINK);
/* Set Auto-Neg advertisement */
tlan_mii_write_reg(dev, phy, MII_AN_ADV,
(ability << 5) | 1); /* Enablee Auto-Neg */
tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1000); /* Restart Auto-Neg */
tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1200); /* Wait for 4 sec for autonegotiation * to complete. The max spec time is less than this * but the card need additional time to start AN. * .5 sec should be plenty extra.
*/
netdev_info(dev, "Starting autonegotiation\n");
tlan_set_timer(dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN); return;
}
}
if ((priv->aui) && (priv->phy_num != 0)) {
priv->phy_num = 0;
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN
| TLAN_NET_CFG_PHY_EN;
tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data);
tlan_set_timer(dev, msecs_to_jiffies(40), TLAN_TIMER_PHY_PDOWN); return;
} elseif (priv->phy_num == 0) {
control = 0;
tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tctl); if (priv->aui) {
tctl |= TLAN_TC_AUISEL;
} else {
tctl &= ~TLAN_TC_AUISEL; if (priv->duplex == TLAN_DUPLEX_FULL) {
control |= MII_GC_DUPLEX;
priv->tlan_full_duplex = true;
} if (priv->speed == TLAN_SPEED_100)
control |= MII_GC_SPEEDSEL;
}
tlan_mii_write_reg(dev, phy, MII_GEN_CTL, control);
tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, tctl);
}
/* Wait for 2 sec to give the transceiver time * to establish link.
*/
tlan_set_timer(dev, (4*HZ), TLAN_TIMER_FINISH_RESET);
if (!(status & MII_GS_AUTOCMPLT)) { /* Wait for 8 sec to give the process * more time. Perhaps we should fail after a while.
*/
tlan_set_timer(dev, 2 * HZ, TLAN_TIMER_PHY_FINISH_AN); return;
}
/* Wait for 100 ms. No reason in partiticular.
*/
tlan_set_timer(dev, msecs_to_jiffies(100), TLAN_TIMER_FINISH_RESET);
}
/********************************************************************* * * tlan_phy_monitor * * Returns: * None * * Params: * data The device structure of this device. * * * This function monitors PHY condition by reading the status * register via the MII bus, controls LINK LED and notifies the * kernel about link state. *
*******************************************************************/
/* Get PHY status register */
tlan_mii_read_reg(dev, phy, MII_GEN_STS, &phy_status);
/* Check if link has been lost */ if (!(phy_status & MII_GS_LINK)) { if (netif_carrier_ok(dev)) {
printk(KERN_DEBUG "TLAN: %s has lost link\n",
dev->name);
tlan_dio_write8(dev->base_addr, TLAN_LED_REG, 0);
netif_carrier_off(dev); if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) { /* power down internal PHY */
u16 data = MII_GC_PDOWN | MII_GC_LOOPBK |
MII_GC_ISOLATE;
/*************************************************************** * __tlan_mii_read_reg * * Returns: * false if ack received ok * true if no ack received or other error * * Parms: * dev The device structure containing * The io address and interrupt count * for this device. * phy The address of the PHY to be queried. * reg The register whose contents are to be * retrieved. * val A pointer to a variable to store the * retrieved value. * * This function uses the TLAN's MII bus to retrieve the contents * of a given register on a PHY. It sends the appropriate info * and then reads the 16-bit register value from the MII bus via * the TLAN SIO register. *
**************************************************************/
/*************************************************************** * tlan_mii_send_data * * Returns: * Nothing * Parms: * base_port The base IO port of the adapter in * question. * dev The address of the PHY to be queried. * data The value to be placed on the MII bus. * num_bits The number of bits in data that are to * be placed on the MII bus. * * This function sends on sequence of bits on the MII * configuration bus. *
**************************************************************/
for (i = (0x1 << (num_bits - 1)); i; i >>= 1) {
tlan_clear_bit(TLAN_NET_SIO_MCLK, sio);
(void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio); if (data & i)
tlan_set_bit(TLAN_NET_SIO_MDATA, sio); else
tlan_clear_bit(TLAN_NET_SIO_MDATA, sio);
tlan_set_bit(TLAN_NET_SIO_MCLK, sio);
(void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio);
}
}
/*************************************************************** * TLan_MiiSync * * Returns: * Nothing * Parms: * base_port The base IO port of the adapter in * question. * * This functions syncs all PHYs in terms of the MII configuration * bus. *
**************************************************************/
staticvoid tlan_mii_sync(u16 base_port)
{ int i;
u16 sio;
tlan_clear_bit(TLAN_NET_SIO_MTXEN, sio); for (i = 0; i < 32; i++) {
tlan_clear_bit(TLAN_NET_SIO_MCLK, sio);
tlan_set_bit(TLAN_NET_SIO_MCLK, sio);
}
}
/*************************************************************** * __tlan_mii_write_reg * * Returns: * Nothing * Parms: * dev The device structure for the device * to write to. * phy The address of the PHY to be written to. * reg The register whose contents are to be * written. * val The value to be written to the register. * * This function uses the TLAN's MII bus to write the contents of a * given register on a PHY. It sends the appropriate info and then * writes the 16-bit register value from the MII configuration bus * via the TLAN SIO register. *
**************************************************************/
the Compaq netelligent 10 and 10/100 cards use a microchip 24C02A EEPROM. these functions are based on information in microchip's data sheet. I don't know how well this functions will work with other Eeproms.
/*************************************************************** * tlan_ee_send_start * * Returns: * Nothing * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to * use. * * This function sends a start cycle to an EEPROM attached * to a TLAN chip. *
**************************************************************/
/*************************************************************** * tlan_ee_send_byte * * Returns: * If the correct ack was received, 0, otherwise 1 * Parms: io_base The IO port base address for the * TLAN device with the EEPROM to * use. * data The 8 bits of information to * send to the EEPROM. * stop If TLAN_EEPROM_STOP is passed, a * stop cycle is sent after the * byte is sent after the ack is * read. * * This function sends a byte on the serial EEPROM line, * driving the clock to send each bit. The function then * reverses transmission direction and reads an acknowledge * bit. *
**************************************************************/
staticint tlan_ee_send_byte(u16 io_base, u8 data, int stop)
{ int err;
u8 place;
u16 sio;
/* Assume clock is low, tx is enabled; */ for (place = 0x80; place != 0; place >>= 1) { if (place & data)
tlan_set_bit(TLAN_NET_SIO_EDATA, sio); else
tlan_clear_bit(TLAN_NET_SIO_EDATA, sio);
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio);
}
tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio);
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
err = tlan_get_bit(TLAN_NET_SIO_EDATA, sio);
tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_set_bit(TLAN_NET_SIO_ETXEN, sio);
if ((!err) && stop) { /* STOP, raise data while clock is high */
tlan_clear_bit(TLAN_NET_SIO_EDATA, sio);
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_set_bit(TLAN_NET_SIO_EDATA, sio);
}
return err;
}
/*************************************************************** * tlan_ee_receive_byte * * Returns: * Nothing * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to * use. * data An address to a char to hold the * data sent from the EEPROM. * stop If TLAN_EEPROM_STOP is passed, a * stop cycle is sent after the * byte is received, and no ack is * sent. * * This function receives 8 bits of data from the EEPROM * over the serial link. It then sends and ack bit, or no * ack and a stop bit. This function is used to retrieve * data after the address of a byte in the EEPROM has been * sent. *
**************************************************************/
/* Assume clock is low, tx is enabled; */
tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio); for (place = 0x80; place; place >>= 1) {
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); if (tlan_get_bit(TLAN_NET_SIO_EDATA, sio))
*data |= place;
tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio);
}
tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); if (!stop) {
tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); /* ack = 0 */
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio);
} else {
tlan_set_bit(TLAN_NET_SIO_EDATA, sio); /* no ack = 1 (?) */
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); /* STOP, raise data while clock is high */
tlan_clear_bit(TLAN_NET_SIO_EDATA, sio);
tlan_set_bit(TLAN_NET_SIO_ECLOK, sio);
tlan_set_bit(TLAN_NET_SIO_EDATA, sio);
}
}
/*************************************************************** * tlan_ee_read_byte * * Returns: * No error = 0, else, the stage at which the error * occurred. * Parms: * io_base The IO port base address for the * TLAN device with the EEPROM to * use. * ee_addr The address of the byte in the * EEPROM whose contents are to be * retrieved. * data An address to a char to hold the * data obtained from the EEPROM. * * This function reads a byte of information from an byte * cell in the EEPROM. *
**************************************************************/
staticint tlan_ee_read_byte(struct net_device *dev, u8 ee_addr, u8 *data)
{ int err; struct tlan_priv *priv = netdev_priv(dev); unsignedlong flags = 0; int ret = 0;
spin_lock_irqsave(&priv->lock, flags);
tlan_ee_send_start(dev->base_addr);
err = tlan_ee_send_byte(dev->base_addr, 0xa0, TLAN_EEPROM_ACK); if (err) {
ret = 1; goto fail;
}
err = tlan_ee_send_byte(dev->base_addr, ee_addr, TLAN_EEPROM_ACK); if (err) {
ret = 2; goto fail;
}
tlan_ee_send_start(dev->base_addr);
err = tlan_ee_send_byte(dev->base_addr, 0xa1, TLAN_EEPROM_ACK); if (err) {
ret = 3; goto fail;
}
tlan_ee_receive_byte(dev->base_addr, data, TLAN_EEPROM_STOP);
fail:
spin_unlock_irqrestore(&priv->lock, flags);
return ret;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.37 Sekunden
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.