iPXE
Functions | Variables
smsc95xx.c File Reference

SMSC LAN95xx USB Ethernet driver. More...

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/ethernet.h>
#include <ipxe/usb.h>
#include <ipxe/usbnet.h>
#include <ipxe/profile.h>
#include <ipxe/base16.h>
#include <ipxe/smbios.h>
#include "smsc95xx.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int smsc95xx_vm3_fetch_mac (struct smscusb_device *smscusb)
 Construct MAC address for Honeywell VM3.
static int smsc95xx_fetch_mac (struct smscusb_device *smscusb)
 Fetch MAC address.
static int smsc95xx_dump_statistics (struct smscusb_device *smscusb)
 Dump statistics (for debugging)
static int smsc95xx_reset (struct smscusb_device *smscusb)
 Reset device.
static void smsc95xx_in_complete (struct usb_endpoint *ep, struct io_buffer *iobuf, int rc)
 Complete bulk IN transfer.
static int smsc95xx_out_transmit (struct smscusb_device *smscusb, struct io_buffer *iobuf)
 Transmit packet.
static int smsc95xx_open (struct net_device *netdev)
 Open network device.
static void smsc95xx_close (struct net_device *netdev)
 Close network device.
static int smsc95xx_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 Transmit packet.
static void smsc95xx_poll (struct net_device *netdev)
 Poll for completed and received packets.
static int smsc95xx_probe (struct usb_function *func, struct usb_configuration_descriptor *config)
 Probe device.
static void smsc95xx_remove (struct usb_function *func)
 Remove device.

Variables

static struct profiler
smsc95xx_in_profiler 
__profiler
 Bulk IN completion profiler.
static struct
usb_endpoint_driver_operations 
smsc95xx_in_operations
 Bulk IN endpoint operations.
static struct net_device_operations smsc95xx_operations
 SMSC95xx network device operations.
static struct usb_device_id smsc95xx_ids []
 SMSC95xx device IDs.
struct usb_driver smsc95xx_driver __usb_driver
 SMSC LAN95xx driver.

Detailed Description

SMSC LAN95xx USB Ethernet driver.

Definition in file smsc95xx.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static int smsc95xx_vm3_fetch_mac ( struct smscusb_device smscusb) [static]

Construct MAC address for Honeywell VM3.

Parameters:
smscusbSMSC USB device
Return values:
rcReturn status code

Definition at line 65 of file smsc95xx.c.

References base16_encoded_len(), DBGC, EINVAL, ENOTTY, ETH_ALEN, eth_ntoa(), find_smbios_structure(), net_device::hw_addr, len, mac, smbios_system_information::manufacturer, memset(), netdev, smscusb_device::netdev, smbios_system_information::product, rc, read_smbios_string(), read_smbios_structure(), SMBIOS_TYPE_OEM_STRINGS, SMBIOS_TYPE_SYSTEM_INFORMATION, SMSC95XX_VM3_OEM_STRING_MAC, strcmp(), and strerror().

Referenced by smsc95xx_fetch_mac().

                                                                     {
        struct net_device *netdev = smscusb->netdev;
        struct smbios_structure structure;
        struct smbios_system_information system;
        struct {
                char manufacturer[ 10 /* "Honeywell" + NUL */ ];
                char product[ 4 /* "VM3" + NUL */ ];
                char mac[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
        } strings;
        int len;
        int rc;

        /* Find system information */
        if ( ( rc = find_smbios_structure ( SMBIOS_TYPE_SYSTEM_INFORMATION, 0,
                                            &structure ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not find system "
                       "information: %s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* Read system information */
        if ( ( rc = read_smbios_structure ( &structure, &system,
                                            sizeof ( system ) ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not read system "
                       "information: %s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* NUL-terminate all strings to be fetched */
        memset ( &strings, 0, sizeof ( strings ) );

        /* Fetch system manufacturer name */
        len = read_smbios_string ( &structure, system.manufacturer,
                                   strings.manufacturer,
                                   ( sizeof ( strings.manufacturer ) - 1 ) );
        if ( len < 0 ) {
                rc = len;
                DBGC ( smscusb, "SMSC95XX %p could not read manufacturer "
                       "name: %s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* Fetch system product name */
        len = read_smbios_string ( &structure, system.product, strings.product,
                                   ( sizeof ( strings.product ) - 1 ) );
        if ( len < 0 ) {
                rc = len;
                DBGC ( smscusb, "SMSC95XX %p could not read product name: "
                       "%s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* Ignore non-VM3 devices */
        if ( ( strcmp ( strings.manufacturer, "Honeywell" ) != 0 ) ||
             ( strcmp ( strings.product, "VM3" ) != 0 ) )
                return -ENOTTY;

        /* Find OEM strings */
        if ( ( rc = find_smbios_structure ( SMBIOS_TYPE_OEM_STRINGS, 0,
                                            &structure ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not find OEM strings: %s\n",
                       smscusb, strerror ( rc ) );
                return rc;
        }

        /* Fetch MAC address */
        len = read_smbios_string ( &structure, SMSC95XX_VM3_OEM_STRING_MAC,
                                   strings.mac, ( sizeof ( strings.mac ) - 1 ));
        if ( len < 0 ) {
                rc = len;
                DBGC ( smscusb, "SMSC95XX %p could not read OEM string: %s\n",
                       smscusb, strerror ( rc ) );
                return rc;
        }

        /* Sanity check */
        if ( len != ( ( int ) ( sizeof ( strings.mac ) - 1 ) ) ) {
                DBGC ( smscusb, "SMSC95XX %p invalid MAC address \"%s\"\n",
                       smscusb, strings.mac );
                return -EINVAL;
        }

        /* Decode MAC address */
        len = base16_decode ( strings.mac, netdev->hw_addr, ETH_ALEN );
        if ( len < 0 ) {
                rc = len;
                DBGC ( smscusb, "SMSC95XX %p invalid MAC address \"%s\"\n",
                       smscusb, strings.mac );
                return rc;
        }

        DBGC ( smscusb, "SMSC95XX %p using VM3 MAC %s\n",
               smscusb, eth_ntoa ( netdev->hw_addr ) );
        return 0;
}
static int smsc95xx_fetch_mac ( struct smscusb_device smscusb) [static]

Fetch MAC address.

Parameters:
smscusbSMSC USB device
Return values:
rcReturn status code

Definition at line 167 of file smsc95xx.c.

References DBGC, eth_ntoa(), eth_random_addr(), net_device::hw_addr, netdev, smscusb_device::netdev, rc, SMSC95XX_E2P_BASE, smsc95xx_vm3_fetch_mac(), and smscusb_eeprom_fetch_mac().

Referenced by smsc95xx_probe().

                                                                 {
        struct net_device *netdev = smscusb->netdev;
        int rc;

        /* Read MAC address from EEPROM, if present */
        if ( ( rc = smscusb_eeprom_fetch_mac ( smscusb,
                                               SMSC95XX_E2P_BASE ) ) == 0 )
                return 0;

        /* Construct MAC address for Honeywell VM3, if applicable */
        if ( ( rc = smsc95xx_vm3_fetch_mac ( smscusb ) ) == 0 )
                return 0;

        /* Otherwise, generate a random MAC address */
        eth_random_addr ( netdev->hw_addr );
        DBGC ( smscusb, "SMSC95XX %p using random MAC %s\n",
               smscusb, eth_ntoa ( netdev->hw_addr ) );
        return 0;
}
static int smsc95xx_dump_statistics ( struct smscusb_device smscusb) [static]

Dump statistics (for debugging)

Parameters:
smscusbSMSC USB device
Return values:
rcReturn status code

Definition at line 200 of file smsc95xx.c.

References smsc95xx_rx_statistics::alignment, smsc95xx_rx_statistics::bad, smsc95xx_tx_statistics::bad, smsc95xx_tx_statistics::carrier, smsc95xx_rx_statistics::crc, DBG_LOG, DBGC, smsc95xx_tx_statistics::deferred, smsc95xx_rx_statistics::dropped, smsc95xx_tx_statistics::excessive, smsc95xx_rx_statistics::good, smsc95xx_tx_statistics::good, smsc95xx_rx_statistics::late, smsc95xx_tx_statistics::late, le32_to_cpu, smsc95xx_tx_statistics::multiple, smsc95xx_rx_statistics::oversize, smsc95xx_tx_statistics::pause, rc, smsc95xx_tx_statistics::single, SMSC95XX_RX_STATISTICS, SMSC95XX_TX_STATISTICS, smscusb_get_statistics(), strerror(), smsc95xx_tx_statistics::underrun, and smsc95xx_rx_statistics::undersize.

Referenced by smsc95xx_close().

                                                                       {
        struct smsc95xx_rx_statistics rx;
        struct smsc95xx_tx_statistics tx;
        int rc;

        /* Do nothing unless debugging is enabled */
        if ( ! DBG_LOG )
                return 0;

        /* Get RX statistics */
        if ( ( rc = smscusb_get_statistics ( smscusb, SMSC95XX_RX_STATISTICS,
                                             &rx, sizeof ( rx ) ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not get RX statistics: "
                       "%s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* Get TX statistics */
        if ( ( rc = smscusb_get_statistics ( smscusb, SMSC95XX_TX_STATISTICS,
                                             &tx, sizeof ( tx ) ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not get TX statistics: "
                       "%s\n", smscusb, strerror ( rc ) );
                return rc;
        }

        /* Dump statistics */
        DBGC ( smscusb, "SMSC95XX %p RX good %d bad %d crc %d und %d aln %d "
               "ovr %d lat %d drp %d\n", smscusb, le32_to_cpu ( rx.good ),
               le32_to_cpu ( rx.bad ), le32_to_cpu ( rx.crc ),
               le32_to_cpu ( rx.undersize ), le32_to_cpu ( rx.alignment ),
               le32_to_cpu ( rx.oversize ), le32_to_cpu ( rx.late ),
               le32_to_cpu ( rx.dropped ) );
        DBGC ( smscusb, "SMSC95XX %p TX good %d bad %d pau %d sgl %d mul %d "
               "exc %d lat %d und %d def %d car %d\n", smscusb,
               le32_to_cpu ( tx.good ), le32_to_cpu ( tx.bad ),
               le32_to_cpu ( tx.pause ), le32_to_cpu ( tx.single ),
               le32_to_cpu ( tx.multiple ), le32_to_cpu ( tx.excessive ),
               le32_to_cpu ( tx.late ), le32_to_cpu ( tx.underrun ),
               le32_to_cpu ( tx.deferred ), le32_to_cpu ( tx.carrier ) );

        return 0;
}
static int smsc95xx_reset ( struct smscusb_device smscusb) [static]

Reset device.

Parameters:
smscusbSMSC USB device
Return values:
rcReturn status code

Definition at line 256 of file smsc95xx.c.

References DBGC, ETIMEDOUT, rc, SMSC95XX_HW_CFG, SMSC95XX_HW_CFG_LRST, SMSC95XX_LED_GPIO_CFG, SMSC95XX_LED_GPIO_CFG_GPCTL0_NFDX_LED, SMSC95XX_LED_GPIO_CFG_GPCTL1_NLNKA_LED, SMSC95XX_LED_GPIO_CFG_GPCTL2_NSPD_LED, SMSC95XX_RESET_DELAY_US, smscusb_readl(), smscusb_writel(), strerror(), and udelay().

Referenced by smsc95xx_close(), smsc95xx_open(), and smsc95xx_probe().

                                                             {
        uint32_t hw_cfg;
        uint32_t led_gpio_cfg;
        int rc;

        /* Reset device */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_HW_CFG,
                                     SMSC95XX_HW_CFG_LRST ) ) != 0 )
                return rc;

        /* Wait for reset to complete */
        udelay ( SMSC95XX_RESET_DELAY_US );

        /* Check that reset has completed */
        if ( ( rc = smscusb_readl ( smscusb, SMSC95XX_HW_CFG, &hw_cfg ) ) != 0 )
                return rc;
        if ( hw_cfg & SMSC95XX_HW_CFG_LRST ) {
                DBGC ( smscusb, "SMSC95XX %p failed to reset\n", smscusb );
                return -ETIMEDOUT;
        }

        /* Configure LEDs */
        led_gpio_cfg = ( SMSC95XX_LED_GPIO_CFG_GPCTL2_NSPD_LED |
                         SMSC95XX_LED_GPIO_CFG_GPCTL1_NLNKA_LED |
                         SMSC95XX_LED_GPIO_CFG_GPCTL0_NFDX_LED );
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_LED_GPIO_CFG,
                                     led_gpio_cfg ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not configure LEDs: %s\n",
                       smscusb, strerror ( rc ) );
                /* Ignore error and continue */
        }

        return 0;
}
static void smsc95xx_in_complete ( struct usb_endpoint ep,
struct io_buffer iobuf,
int  rc 
) [static]

Complete bulk IN transfer.

Parameters:
epUSB endpoint
iobufI/O buffer
rcCompletion status code

Definition at line 305 of file smsc95xx.c.

References smsc95xx_rx_header::command, container_of, cpu_to_le32, io_buffer::data, DBGC, DBGC_HDA, EINVAL, EIO, free_iob(), header, usbnet_device::in, iob_disown, iob_len(), iob_pull, iob_unput, le32_to_cpu, netdev, smscusb_device::netdev, netdev_rx(), netdev_rx_err(), usb_endpoint::open, profile_start(), profile_stop(), SMSC95XX_RX_CRC, SMSC95XX_RX_LATE, SMSC95XX_RX_RUNT, strerror(), and smscusb_device::usbnet.

                                                                     {
        struct smscusb_device *smscusb =
                container_of ( ep, struct smscusb_device, usbnet.in );
        struct net_device *netdev = smscusb->netdev;
        struct smsc95xx_rx_header *header;

        /* Profile completions */
        profile_start ( &smsc95xx_in_profiler );

        /* Ignore packets cancelled when the endpoint closes */
        if ( ! ep->open ) {
                free_iob ( iobuf );
                return;
        }

        /* Record USB errors against the network device */
        if ( rc != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p bulk IN failed: %s\n",
                       smscusb, strerror ( rc ) );
                goto err;
        }

        /* Sanity check */
        if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) {
                DBGC ( smscusb, "SMSC95XX %p underlength bulk IN\n",
                       smscusb );
                DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
                rc = -EINVAL;
                goto err;
        }

        /* Strip header and CRC */
        header = iobuf->data;
        iob_pull ( iobuf, sizeof ( *header ) );
        iob_unput ( iobuf, 4 /* CRC */ );

        /* Check for errors */
        if ( header->command & cpu_to_le32 ( SMSC95XX_RX_RUNT |
                                             SMSC95XX_RX_LATE |
                                             SMSC95XX_RX_CRC ) ) {
                DBGC ( smscusb, "SMSC95XX %p receive error (%08x):\n",
                       smscusb, le32_to_cpu ( header->command ) );
                DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
                rc = -EIO;
                goto err;
        }

        /* Hand off to network stack */
        netdev_rx ( netdev, iob_disown ( iobuf ) );

        profile_stop ( &smsc95xx_in_profiler );
        return;

 err:
        /* Hand off to network stack */
        netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
}
static int smsc95xx_out_transmit ( struct smscusb_device smscusb,
struct io_buffer iobuf 
) [static]

Transmit packet.

Parameters:
smscusbSMSC USB device
iobufI/O buffer
Return values:
rcReturn status code

Definition at line 376 of file smsc95xx.c.

References smsc95xx_tx_header::command, cpu_to_le32, header, iob_ensure_headroom(), iob_len(), iob_push, smsc95xx_tx_header::len, len, usbnet_device::out, profile_start(), profile_stop(), rc, SMSC95XX_TX_FIRST, SMSC95XX_TX_LAST, SMSC95XX_TX_LEN, usb_stream(), and smscusb_device::usbnet.

Referenced by smsc95xx_transmit().

                                                             {
        struct smsc95xx_tx_header *header;
        size_t len = iob_len ( iobuf );
        int rc;

        /* Profile transmissions */
        profile_start ( &smsc95xx_out_profiler );

        /* Prepend header */
        if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 )
                return rc;
        header = iob_push ( iobuf, sizeof ( *header ) );
        header->command = cpu_to_le32 ( SMSC95XX_TX_FIRST | SMSC95XX_TX_LAST |
                                        SMSC95XX_TX_LEN ( len ) );
        header->len = cpu_to_le32 ( len );

        /* Enqueue I/O buffer */
        if ( ( rc = usb_stream ( &smscusb->usbnet.out, iobuf, 0 ) ) != 0 )
                return rc;

        profile_stop ( &smsc95xx_out_profiler );
        return 0;
}
static int smsc95xx_open ( struct net_device netdev) [static]

Open network device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 414 of file smsc95xx.c.

References DBGC, smscusb_device::int_sts, net_device::priv, rc, SMSC95XX_ADDR_BASE, SMSC95XX_BULK_IN_DLY, SMSC95XX_BULK_IN_DLY_SET, SMSC95XX_HW_CFG, SMSC95XX_HW_CFG_BIR, SMSC95XX_INT_EP_CTL, SMSC95XX_INT_EP_CTL_PHY_EN, SMSC95XX_INT_EP_CTL_RXDF_EN, SMSC95XX_MAC_CR, SMSC95XX_MAC_CR_FDPX, SMSC95XX_MAC_CR_MCPAS, SMSC95XX_MAC_CR_PASSBAD, SMSC95XX_MAC_CR_PRMS, SMSC95XX_MAC_CR_RXALL, SMSC95XX_MAC_CR_RXEN, SMSC95XX_MAC_CR_TXEN, SMSC95XX_MII_PHY_INTR_MASK, SMSC95XX_PHY_INTR_ANEG_DONE, SMSC95XX_PHY_INTR_LINK_DOWN, smsc95xx_reset(), SMSC95XX_TX_CFG, SMSC95XX_TX_CFG_ON, smscusb_mii_open(), smscusb_set_address(), smscusb_writel(), strerror(), smscusb_device::usbnet, usbnet_close(), and usbnet_open().

                                                       {
        struct smscusb_device *smscusb = netdev->priv;
        int rc;

        /* Clear stored interrupt status */
        smscusb->int_sts = 0;

        /* Configure bulk IN empty response */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_HW_CFG,
                                     SMSC95XX_HW_CFG_BIR ) ) != 0 )
                goto err_hw_cfg;

        /* Open USB network device */
        if ( ( rc = usbnet_open ( &smscusb->usbnet ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not open: %s\n",
                       smscusb, strerror ( rc ) );
                goto err_open;
        }

        /* Configure interrupt endpoint */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_INT_EP_CTL,
                                     ( SMSC95XX_INT_EP_CTL_RXDF_EN |
                                       SMSC95XX_INT_EP_CTL_PHY_EN ) ) ) != 0 )
                goto err_int_ep_ctl;

        /* Configure bulk IN delay */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_BULK_IN_DLY,
                                     SMSC95XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 )
                goto err_bulk_in_dly;

        /* Configure MAC */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_MAC_CR,
                                     ( SMSC95XX_MAC_CR_RXALL |
                                       SMSC95XX_MAC_CR_FDPX |
                                       SMSC95XX_MAC_CR_MCPAS |
                                       SMSC95XX_MAC_CR_PRMS |
                                       SMSC95XX_MAC_CR_PASSBAD |
                                       SMSC95XX_MAC_CR_TXEN |
                                       SMSC95XX_MAC_CR_RXEN ) ) ) != 0 )
                goto err_mac_cr;

        /* Configure transmit datapath */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_TX_CFG,
                                     SMSC95XX_TX_CFG_ON ) ) != 0 )
                goto err_tx_cfg;

        /* Set MAC address */
        if ( ( rc = smscusb_set_address ( smscusb, SMSC95XX_ADDR_BASE ) ) != 0 )
                goto err_set_address;

        /* Enable PHY interrupts and update link status */
        if ( ( rc = smscusb_mii_open ( smscusb, SMSC95XX_MII_PHY_INTR_MASK,
                                       ( SMSC95XX_PHY_INTR_ANEG_DONE |
                                         SMSC95XX_PHY_INTR_LINK_DOWN ) ) ) != 0)
                goto err_mii_open;

        return 0;

 err_mii_open:
 err_set_address:
 err_tx_cfg:
 err_mac_cr:
 err_bulk_in_dly:
 err_int_ep_ctl:
        usbnet_close ( &smscusb->usbnet );
 err_open:
 err_hw_cfg:
        smsc95xx_reset ( smscusb );
        return rc;
}
static void smsc95xx_close ( struct net_device netdev) [static]

Close network device.

Parameters:
netdevNetwork device

Definition at line 490 of file smsc95xx.c.

References net_device::priv, smsc95xx_dump_statistics(), smsc95xx_reset(), smscusb_device::usbnet, and usbnet_close().

                                                         {
        struct smscusb_device *smscusb = netdev->priv;

        /* Close USB network device */
        usbnet_close ( &smscusb->usbnet );

        /* Dump statistics (for debugging) */
        smsc95xx_dump_statistics ( smscusb );

        /* Reset device */
        smsc95xx_reset ( smscusb );
}
static int smsc95xx_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Transmit packet.

Parameters:
netdevNetwork device
iobufI/O buffer
Return values:
rcReturn status code

Definition at line 510 of file smsc95xx.c.

References net_device::priv, rc, and smsc95xx_out_transmit().

                                                         {
        struct smscusb_device *smscusb = netdev->priv;
        int rc;

        /* Transmit packet */
        if ( ( rc = smsc95xx_out_transmit ( smscusb, iobuf ) ) != 0 )
                return rc;

        return 0;
}
static void smsc95xx_poll ( struct net_device netdev) [static]

Poll for completed and received packets.

Parameters:
netdevNetwork device

Definition at line 527 of file smsc95xx.c.

References smscusb_device::bus, DBGC, DBGC2, ENOBUFS, ENOTTY, smscusb_device::int_sts, netdev_rx_err(), NULL, net_device::priv, rc, SMSC95XX_INT_STS, SMSC95XX_INT_STS_PHY_INT, SMSC95XX_INT_STS_RXDF_INT, smscusb_mii_check_link(), smscusb_writel(), usb_poll(), smscusb_device::usbnet, and usbnet_refill().

                                                        {
        struct smscusb_device *smscusb = netdev->priv;
        uint32_t int_sts;
        int rc;

        /* Poll USB bus */
        usb_poll ( smscusb->bus );

        /* Refill endpoints */
        if ( ( rc = usbnet_refill ( &smscusb->usbnet ) ) != 0 )
                netdev_rx_err ( netdev, NULL, rc );

        /* Do nothing more unless there are interrupts to handle */
        int_sts = smscusb->int_sts;
        if ( ! int_sts )
                return;

        /* Check link status if applicable */
        if ( int_sts & SMSC95XX_INT_STS_PHY_INT ) {
                smscusb_mii_check_link ( smscusb );
                int_sts &= ~SMSC95XX_INT_STS_PHY_INT;
        }

        /* Record RX FIFO overflow if applicable */
        if ( int_sts & SMSC95XX_INT_STS_RXDF_INT ) {
                DBGC2 ( smscusb, "SMSC95XX %p RX FIFO overflowed\n",
                        smscusb );
                netdev_rx_err ( netdev, NULL, -ENOBUFS );
                int_sts &= ~SMSC95XX_INT_STS_RXDF_INT;
        }

        /* Check for unexpected interrupts */
        if ( int_sts ) {
                DBGC ( smscusb, "SMSC95XX %p unexpected interrupt %#08x\n",
                       smscusb, int_sts );
                netdev_rx_err ( netdev, NULL, -ENOTTY );
        }

        /* Clear interrupts */
        if ( ( rc = smscusb_writel ( smscusb, SMSC95XX_INT_STS,
                                     smscusb->int_sts ) ) != 0 )
                netdev_rx_err ( netdev, NULL, rc );
        smscusb->int_sts = 0;
}
static int smsc95xx_probe ( struct usb_function func,
struct usb_configuration_descriptor config 
) [static]

Probe device.

Parameters:
funcUSB function
configConfiguration descriptor
Return values:
rcReturn status code

Definition at line 594 of file smsc95xx.c.

References alloc_etherdev(), DBGC, net_device::dev, usb_function::dev, ENOMEM, usbnet_device::in, memset(), usb_function::name, netdev, netdev_init(), netdev_nullify(), netdev_put(), net_device::priv, rc, register_netdev(), smsc95xx_fetch_mac(), SMSC95XX_IN_MAX_FILL, SMSC95XX_IN_MTU, SMSC95XX_MII_BASE, SMSC95XX_MII_PHY_INTR_SOURCE, smsc95xx_reset(), smscusb_init(), smscusb_mii_init(), strerror(), unregister_netdev(), usb_func_set_drvdata(), usb_refill_init(), smscusb_device::usbnet, and usbnet_describe().

                                                                          {
        struct net_device *netdev;
        struct smscusb_device *smscusb;
        int rc;

        /* Allocate and initialise structure */
        netdev = alloc_etherdev ( sizeof ( *smscusb ) );
        if ( ! netdev ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        netdev_init ( netdev, &smsc95xx_operations );
        netdev->dev = &func->dev;
        smscusb = netdev->priv;
        memset ( smscusb, 0, sizeof ( *smscusb ) );
        smscusb_init ( smscusb, netdev, func, &smsc95xx_in_operations );
        smscusb_mii_init ( smscusb, SMSC95XX_MII_BASE,
                           SMSC95XX_MII_PHY_INTR_SOURCE );
        usb_refill_init ( &smscusb->usbnet.in,
                          ( sizeof ( struct smsc95xx_tx_header ) -
                            sizeof ( struct smsc95xx_rx_header ) ),
                          SMSC95XX_IN_MTU, SMSC95XX_IN_MAX_FILL );
        DBGC ( smscusb, "SMSC95XX %p on %s\n", smscusb, func->name );

        /* Describe USB network device */
        if ( ( rc = usbnet_describe ( &smscusb->usbnet, config ) ) != 0 ) {
                DBGC ( smscusb, "SMSC95XX %p could not describe: %s\n",
                       smscusb, strerror ( rc ) );
                goto err_describe;
        }

        /* Reset device */
        if ( ( rc = smsc95xx_reset ( smscusb ) ) != 0 )
                goto err_reset;

        /* Read MAC address */
        if ( ( rc = smsc95xx_fetch_mac ( smscusb ) ) != 0 )
                goto err_fetch_mac;

        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err_register;

        usb_func_set_drvdata ( func, netdev );
        return 0;

        unregister_netdev ( netdev );
 err_register:
 err_fetch_mac:
 err_reset:
 err_describe:
        netdev_nullify ( netdev );
        netdev_put ( netdev );
 err_alloc:
        return rc;
}
static void smsc95xx_remove ( struct usb_function func) [static]

Remove device.

Parameters:
funcUSB function

Definition at line 657 of file smsc95xx.c.

References netdev, netdev_nullify(), netdev_put(), unregister_netdev(), and usb_func_get_drvdata().

                                                          {
        struct net_device *netdev = usb_func_get_drvdata ( func );

        unregister_netdev ( netdev );
        netdev_nullify ( netdev );
        netdev_put ( netdev );
}

Variable Documentation

struct profiler smsc95xx_out_profiler __profiler [static]
Initial value:
        { .name = "smsc95xx.in" }

Bulk IN completion profiler.

Bulk OUT profiler.

Definition at line 45 of file smsc95xx.c.

Initial value:
 {
        .complete = smsc95xx_in_complete,
}

Bulk IN endpoint operations.

Definition at line 365 of file smsc95xx.c.

Initial value:
 {
        .open           = smsc95xx_open,
        .close          = smsc95xx_close,
        .transmit       = smsc95xx_transmit,
        .poll           = smsc95xx_poll,
}

SMSC95xx network device operations.

Definition at line 573 of file smsc95xx.c.

struct usb_device_id smsc95xx_ids[] [static]

SMSC95xx device IDs.

Definition at line 666 of file smsc95xx.c.

struct usb_driver smsc95xx_driver __usb_driver
Initial value:
 {
        .ids = smsc95xx_ids,
        .id_count = ( sizeof ( smsc95xx_ids ) / sizeof ( smsc95xx_ids[0] ) ),
        .class = USB_CLASS_ID ( 0xff, 0x00, 0xff ),
        .score = USB_SCORE_NORMAL,
        .probe = smsc95xx_probe,
        .remove = smsc95xx_remove,
}

SMSC LAN95xx driver.

Definition at line 760 of file smsc95xx.c.