diff options
Diffstat (limited to 'qemu/roms/u-boot/drivers/usb/eth/smsc95xx.c')
-rw-r--r-- | qemu/roms/u-boot/drivers/usb/eth/smsc95xx.c | 897 |
1 files changed, 0 insertions, 897 deletions
diff --git a/qemu/roms/u-boot/drivers/usb/eth/smsc95xx.c b/qemu/roms/u-boot/drivers/usb/eth/smsc95xx.c deleted file mode 100644 index 7bf0a3407..000000000 --- a/qemu/roms/u-boot/drivers/usb/eth/smsc95xx.c +++ /dev/null @@ -1,897 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * Copyright (C) 2009 NVIDIA, Corporation - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <asm/unaligned.h> -#include <common.h> -#include <usb.h> -#include <linux/mii.h> -#include "usb_ether.h" -#include <malloc.h> - -/* SMSC LAN95xx based USB 2.0 Ethernet Devices */ - -/* LED defines */ -#define LED_GPIO_CFG (0x24) -#define LED_GPIO_CFG_SPD_LED (0x01000000) -#define LED_GPIO_CFG_LNK_LED (0x00100000) -#define LED_GPIO_CFG_FDX_LED (0x00010000) - -/* Tx command words */ -#define TX_CMD_A_FIRST_SEG_ 0x00002000 -#define TX_CMD_A_LAST_SEG_ 0x00001000 - -/* Rx status word */ -#define RX_STS_FL_ 0x3FFF0000 /* Frame Length */ -#define RX_STS_ES_ 0x00008000 /* Error Summary */ - -/* SCSRs */ -#define ID_REV 0x00 - -#define INT_STS 0x08 - -#define TX_CFG 0x10 -#define TX_CFG_ON_ 0x00000004 - -#define HW_CFG 0x14 -#define HW_CFG_BIR_ 0x00001000 -#define HW_CFG_RXDOFF_ 0x00000600 -#define HW_CFG_MEF_ 0x00000020 -#define HW_CFG_BCE_ 0x00000002 -#define HW_CFG_LRST_ 0x00000008 - -#define PM_CTRL 0x20 -#define PM_CTL_PHY_RST_ 0x00000010 - -#define AFC_CFG 0x2C - -/* - * Hi watermark = 15.5Kb (~10 mtu pkts) - * low watermark = 3k (~2 mtu pkts) - * backpressure duration = ~ 350us - * Apply FC on any frame. - */ -#define AFC_CFG_DEFAULT 0x00F830A1 - -#define E2P_CMD 0x30 -#define E2P_CMD_BUSY_ 0x80000000 -#define E2P_CMD_READ_ 0x00000000 -#define E2P_CMD_TIMEOUT_ 0x00000400 -#define E2P_CMD_LOADED_ 0x00000200 -#define E2P_CMD_ADDR_ 0x000001FF - -#define E2P_DATA 0x34 - -#define BURST_CAP 0x38 - -#define INT_EP_CTL 0x68 -#define INT_EP_CTL_PHY_INT_ 0x00008000 - -#define BULK_IN_DLY 0x6C - -/* MAC CSRs */ -#define MAC_CR 0x100 -#define MAC_CR_MCPAS_ 0x00080000 -#define MAC_CR_PRMS_ 0x00040000 -#define MAC_CR_HPFILT_ 0x00002000 -#define MAC_CR_TXEN_ 0x00000008 -#define MAC_CR_RXEN_ 0x00000004 - -#define ADDRH 0x104 - -#define ADDRL 0x108 - -#define MII_ADDR 0x114 -#define MII_WRITE_ 0x02 -#define MII_BUSY_ 0x01 -#define MII_READ_ 0x00 /* ~of MII Write bit */ - -#define MII_DATA 0x118 - -#define FLOW 0x11C - -#define VLAN1 0x120 - -#define COE_CR 0x130 -#define Tx_COE_EN_ 0x00010000 -#define Rx_COE_EN_ 0x00000001 - -/* Vendor-specific PHY Definitions */ -#define PHY_INT_SRC 29 - -#define PHY_INT_MASK 30 -#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040) -#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010) -#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \ - PHY_INT_MASK_LINK_DOWN_) - -/* USB Vendor Requests */ -#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 -#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 - -/* Some extra defines */ -#define HS_USB_PKT_SIZE 512 -#define FS_USB_PKT_SIZE 64 -#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) -#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) -#define DEFAULT_BULK_IN_DELAY 0x00002000 -#define MAX_SINGLE_PACKET_SIZE 2048 -#define EEPROM_MAC_OFFSET 0x01 -#define SMSC95XX_INTERNAL_PHY_ID 1 -#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ - -/* local defines */ -#define SMSC95XX_BASE_NAME "sms" -#define USB_CTRL_SET_TIMEOUT 5000 -#define USB_CTRL_GET_TIMEOUT 5000 -#define USB_BULK_SEND_TIMEOUT 5000 -#define USB_BULK_RECV_TIMEOUT 5000 - -#define AX_RX_URB_SIZE 2048 -#define PHY_CONNECT_TIMEOUT 5000 - -#define TURBO_MODE - -/* local vars */ -static int curr_eth_dev; /* index for name of next device detected */ - -/* driver private */ -struct smsc95xx_private { - size_t rx_urb_size; /* maximum USB URB size */ - u32 mac_cr; /* MAC control register value */ - int have_hwaddr; /* 1 if we have a hardware MAC address */ -}; - -/* - * Smsc95xx infrastructure commands - */ -static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data) -{ - int len; - ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); - - cpu_to_le32s(&data); - tmpbuf[0] = data; - - len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_WRITE_REGISTER, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT); - if (len != sizeof(data)) { - debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d", - index, data, len); - return -1; - } - return 0; -} - -static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data) -{ - int len; - ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1); - - len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0), - USB_VENDOR_REQUEST_READ_REGISTER, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT); - *data = tmpbuf[0]; - if (len != sizeof(data)) { - debug("smsc95xx_read_reg failed: index=%d, len=%d", - index, len); - return -1; - } - - le32_to_cpus(data); - return 0; -} - -/* Loop until the read is completed with timeout */ -static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev) -{ - unsigned long start_time = get_timer(0); - u32 val; - - do { - smsc95xx_read_reg(dev, MII_ADDR, &val); - if (!(val & MII_BUSY_)) - return 0; - } while (get_timer(start_time) < 1 * 1000 * 1000); - - return -1; -} - -static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx) -{ - u32 val, addr; - - /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { - debug("MII is busy in smsc95xx_mdio_read\n"); - return -1; - } - - /* set the address, index & direction (read from PHY) */ - addr = (phy_id << 11) | (idx << 6) | MII_READ_; - smsc95xx_write_reg(dev, MII_ADDR, addr); - - if (smsc95xx_phy_wait_not_busy(dev)) { - debug("Timed out reading MII reg %02X\n", idx); - return -1; - } - - smsc95xx_read_reg(dev, MII_DATA, &val); - - return (u16)(val & 0xFFFF); -} - -static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx, - int regval) -{ - u32 val, addr; - - /* confirm MII not busy */ - if (smsc95xx_phy_wait_not_busy(dev)) { - debug("MII is busy in smsc95xx_mdio_write\n"); - return; - } - - val = regval; - smsc95xx_write_reg(dev, MII_DATA, val); - - /* set the address, index & direction (write to PHY) */ - addr = (phy_id << 11) | (idx << 6) | MII_WRITE_; - smsc95xx_write_reg(dev, MII_ADDR, addr); - - if (smsc95xx_phy_wait_not_busy(dev)) - debug("Timed out writing MII reg %02X\n", idx); -} - -static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev) -{ - unsigned long start_time = get_timer(0); - u32 val; - - do { - smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_BUSY_)) - return 0; - udelay(40); - } while (get_timer(start_time) < 1 * 1000 * 1000); - - debug("EEPROM is busy\n"); - return -1; -} - -static int smsc95xx_wait_eeprom(struct ueth_data *dev) -{ - unsigned long start_time = get_timer(0); - u32 val; - - do { - smsc95xx_read_reg(dev, E2P_CMD, &val); - if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_)) - break; - udelay(40); - } while (get_timer(start_time) < 1 * 1000 * 1000); - - if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) { - debug("EEPROM read operation timeout\n"); - return -1; - } - return 0; -} - -static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length, - u8 *data) -{ - u32 val; - int i, ret; - - ret = smsc95xx_eeprom_confirm_not_busy(dev); - if (ret) - return ret; - - for (i = 0; i < length; i++) { - val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_); - smsc95xx_write_reg(dev, E2P_CMD, val); - - ret = smsc95xx_wait_eeprom(dev); - if (ret < 0) - return ret; - - smsc95xx_read_reg(dev, E2P_DATA, &val); - data[i] = val & 0xFF; - offset++; - } - return 0; -} - -/* - * mii_nway_restart - restart NWay (autonegotiation) for this interface - * - * Returns 0 on success, negative on error. - */ -static int mii_nway_restart(struct ueth_data *dev) -{ - int bmcr; - int r = -1; - - /* if autoneg is off, it's an error */ - bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR); - - if (bmcr & BMCR_ANENABLE) { - bmcr |= BMCR_ANRESTART; - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr); - r = 0; - } - return r; -} - -static int smsc95xx_phy_initialize(struct ueth_data *dev) -{ - smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); - smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); - - /* read to clear */ - smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC); - - smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK, - PHY_INT_MASK_DEFAULT_); - mii_nway_restart(dev); - - debug("phy initialised succesfully\n"); - return 0; -} - -static int smsc95xx_init_mac_address(struct eth_device *eth, - struct ueth_data *dev) -{ - /* try reading mac address from EEPROM */ - if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - eth->enetaddr) == 0) { - if (is_valid_ether_addr(eth->enetaddr)) { - /* eeprom values are valid so use them */ - debug("MAC address read from EEPROM\n"); - return 0; - } - } - - /* - * No eeprom, or eeprom values are invalid. Generating a random MAC - * address is not safe. Just return an error. - */ - return -1; -} - -static int smsc95xx_write_hwaddr(struct eth_device *eth) -{ - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = dev->dev_priv; - u32 addr_lo = __get_unaligned_le32(ð->enetaddr[0]); - u32 addr_hi = __get_unaligned_le16(ð->enetaddr[4]); - int ret; - - /* set hardware address */ - debug("** %s()\n", __func__); - ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); - if (ret < 0) - return ret; - - ret = smsc95xx_write_reg(dev, ADDRH, addr_hi); - if (ret < 0) - return ret; - - debug("MAC %pM\n", eth->enetaddr); - priv->have_hwaddr = 1; - return 0; -} - -/* Enable or disable Tx & Rx checksum offload engines */ -static int smsc95xx_set_csums(struct ueth_data *dev, - int use_tx_csum, int use_rx_csum) -{ - u32 read_buf; - int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); - if (ret < 0) - return ret; - - if (use_tx_csum) - read_buf |= Tx_COE_EN_; - else - read_buf &= ~Tx_COE_EN_; - - if (use_rx_csum) - read_buf |= Rx_COE_EN_; - else - read_buf &= ~Rx_COE_EN_; - - ret = smsc95xx_write_reg(dev, COE_CR, read_buf); - if (ret < 0) - return ret; - - debug("COE_CR = 0x%08x\n", read_buf); - return 0; -} - -static void smsc95xx_set_multicast(struct ueth_data *dev) -{ - struct smsc95xx_private *priv = dev->dev_priv; - - /* No multicast in u-boot */ - priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); -} - -/* starts the TX path */ -static void smsc95xx_start_tx_path(struct ueth_data *dev) -{ - struct smsc95xx_private *priv = dev->dev_priv; - u32 reg_val; - - /* Enable Tx at MAC */ - priv->mac_cr |= MAC_CR_TXEN_; - - smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); - - /* Enable Tx at SCSRs */ - reg_val = TX_CFG_ON_; - smsc95xx_write_reg(dev, TX_CFG, reg_val); -} - -/* Starts the Receive path */ -static void smsc95xx_start_rx_path(struct ueth_data *dev) -{ - struct smsc95xx_private *priv = dev->dev_priv; - - priv->mac_cr |= MAC_CR_RXEN_; - smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr); -} - -/* - * Smsc95xx callbacks - */ -static int smsc95xx_init(struct eth_device *eth, bd_t *bd) -{ - int ret; - u32 write_buf; - u32 read_buf; - u32 burst_cap; - int timeout; - struct ueth_data *dev = (struct ueth_data *)eth->priv; - struct smsc95xx_private *priv = - (struct smsc95xx_private *)dev->dev_priv; -#define TIMEOUT_RESOLUTION 50 /* ms */ - int link_detected; - - debug("** %s()\n", __func__); - dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */ - - write_buf = HW_CFG_LRST_; - ret = smsc95xx_write_reg(dev, HW_CFG, write_buf); - if (ret < 0) - return ret; - - timeout = 0; - do { - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) - return ret; - udelay(10 * 1000); - timeout++; - } while ((read_buf & HW_CFG_LRST_) && (timeout < 100)); - - if (timeout >= 100) { - debug("timeout waiting for completion of Lite Reset\n"); - return -1; - } - - write_buf = PM_CTL_PHY_RST_; - ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf); - if (ret < 0) - return ret; - - timeout = 0; - do { - ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf); - if (ret < 0) - return ret; - udelay(10 * 1000); - timeout++; - } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100)); - if (timeout >= 100) { - debug("timeout waiting for PHY Reset\n"); - return -1; - } - if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0) - priv->have_hwaddr = 1; - if (!priv->have_hwaddr) { - puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n"); - return -1; - } - if (smsc95xx_write_hwaddr(eth) < 0) - return -1; - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from HW_CFG : 0x%08x\n", read_buf); - - read_buf |= HW_CFG_BIR_; - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from HW_CFG after writing " - "HW_CFG_BIR_: 0x%08x\n", read_buf); - -#ifdef TURBO_MODE - if (dev->pusb_dev->speed == USB_SPEED_HIGH) { - burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; - priv->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; - } else { - burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; - priv->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; - } -#else - burst_cap = 0; - priv->rx_urb_size = MAX_SINGLE_PACKET_SIZE; -#endif - debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size); - - ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf); - - read_buf = DEFAULT_BULK_IN_DELAY; - ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from BULK_IN_DLY after writing: " - "0x%08x\n", read_buf); - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from HW_CFG: 0x%08x\n", read_buf); - -#ifdef TURBO_MODE - read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_); -#endif - read_buf &= ~HW_CFG_RXDOFF_; - -#define NET_IP_ALIGN 0 - read_buf |= NET_IP_ALIGN << 9; - - ret = smsc95xx_write_reg(dev, HW_CFG, read_buf); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); - if (ret < 0) - return ret; - debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf); - - write_buf = 0xFFFFFFFF; - ret = smsc95xx_write_reg(dev, INT_STS, write_buf); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, ID_REV, &read_buf); - if (ret < 0) - return ret; - debug("ID_REV = 0x%08x\n", read_buf); - - /* Configure GPIO pins as LED outputs */ - write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED | - LED_GPIO_CFG_FDX_LED; - ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf); - if (ret < 0) - return ret; - debug("LED_GPIO_CFG set\n"); - - /* Init Tx */ - write_buf = 0; - ret = smsc95xx_write_reg(dev, FLOW, write_buf); - if (ret < 0) - return ret; - - read_buf = AFC_CFG_DEFAULT; - ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf); - if (ret < 0) - return ret; - - ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr); - if (ret < 0) - return ret; - - /* Init Rx. Set Vlan */ - write_buf = (u32)ETH_P_8021Q; - ret = smsc95xx_write_reg(dev, VLAN1, write_buf); - if (ret < 0) - return ret; - - /* Disable checksum offload engines */ - ret = smsc95xx_set_csums(dev, 0, 0); - if (ret < 0) { - debug("Failed to set csum offload: %d\n", ret); - return ret; - } - smsc95xx_set_multicast(dev); - - if (smsc95xx_phy_initialize(dev) < 0) - return -1; - ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf); - if (ret < 0) - return ret; - - /* enable PHY interrupts */ - read_buf |= INT_EP_CTL_PHY_INT_; - - ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf); - if (ret < 0) - return ret; - - smsc95xx_start_tx_path(dev); - smsc95xx_start_rx_path(dev); - - timeout = 0; - do { - link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR) - & BMSR_LSTATUS; - if (!link_detected) { - if (timeout == 0) - printf("Waiting for Ethernet connection... "); - udelay(TIMEOUT_RESOLUTION * 1000); - timeout += TIMEOUT_RESOLUTION; - } - } while (!link_detected && timeout < PHY_CONNECT_TIMEOUT); - if (link_detected) { - if (timeout != 0) - printf("done.\n"); - } else { - printf("unable to connect.\n"); - return -1; - } - return 0; -} - -static int smsc95xx_send(struct eth_device *eth, void* packet, int length) -{ - struct ueth_data *dev = (struct ueth_data *)eth->priv; - int err; - int actual_len; - u32 tx_cmd_a; - u32 tx_cmd_b; - ALLOC_CACHE_ALIGN_BUFFER(unsigned char, msg, - PKTSIZE + sizeof(tx_cmd_a) + sizeof(tx_cmd_b)); - - debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg); - if (length > PKTSIZE) - return -1; - - tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - tx_cmd_b = (u32)length; - cpu_to_le32s(&tx_cmd_a); - cpu_to_le32s(&tx_cmd_b); - - /* prepend cmd_a and cmd_b */ - memcpy(msg, &tx_cmd_a, sizeof(tx_cmd_a)); - memcpy(msg + sizeof(tx_cmd_a), &tx_cmd_b, sizeof(tx_cmd_b)); - memcpy(msg + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), (void *)packet, - length); - err = usb_bulk_msg(dev->pusb_dev, - usb_sndbulkpipe(dev->pusb_dev, dev->ep_out), - (void *)msg, - length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), - &actual_len, - USB_BULK_SEND_TIMEOUT); - debug("Tx: len = %u, actual = %u, err = %d\n", - length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b), - actual_len, err); - return err; -} - -static int smsc95xx_recv(struct eth_device *eth) -{ - struct ueth_data *dev = (struct ueth_data *)eth->priv; - DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE); - unsigned char *buf_ptr; - int err; - int actual_len; - u32 packet_len; - int cur_buf_align; - - debug("** %s()\n", __func__); - err = usb_bulk_msg(dev->pusb_dev, - usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in), - (void *)recv_buf, - AX_RX_URB_SIZE, - &actual_len, - USB_BULK_RECV_TIMEOUT); - debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE, - actual_len, err); - if (err != 0) { - debug("Rx: failed to receive\n"); - return -1; - } - if (actual_len > AX_RX_URB_SIZE) { - debug("Rx: received too many bytes %d\n", actual_len); - return -1; - } - - buf_ptr = recv_buf; - while (actual_len > 0) { - /* - * 1st 4 bytes contain the length of the actual data plus error - * info. Extract data length. - */ - if (actual_len < sizeof(packet_len)) { - debug("Rx: incomplete packet length\n"); - return -1; - } - memcpy(&packet_len, buf_ptr, sizeof(packet_len)); - le32_to_cpus(&packet_len); - if (packet_len & RX_STS_ES_) { - debug("Rx: Error header=%#x", packet_len); - return -1; - } - packet_len = ((packet_len & RX_STS_FL_) >> 16); - - if (packet_len > actual_len - sizeof(packet_len)) { - debug("Rx: too large packet: %d\n", packet_len); - return -1; - } - - /* Notify net stack */ - NetReceive(buf_ptr + sizeof(packet_len), packet_len - 4); - - /* Adjust for next iteration */ - actual_len -= sizeof(packet_len) + packet_len; - buf_ptr += sizeof(packet_len) + packet_len; - cur_buf_align = (int)buf_ptr - (int)recv_buf; - - if (cur_buf_align & 0x03) { - int align = 4 - (cur_buf_align & 0x03); - - actual_len -= align; - buf_ptr += align; - } - } - return err; -} - -static void smsc95xx_halt(struct eth_device *eth) -{ - debug("** %s()\n", __func__); -} - -/* - * SMSC probing functions - */ -void smsc95xx_eth_before_probe(void) -{ - curr_eth_dev = 0; -} - -struct smsc95xx_dongle { - unsigned short vendor; - unsigned short product; -}; - -static const struct smsc95xx_dongle smsc95xx_dongles[] = { - { 0x0424, 0xec00 }, /* LAN9512/LAN9514 Ethernet */ - { 0x0424, 0x9500 }, /* LAN9500 Ethernet */ - { 0x0424, 0x9730 }, /* LAN9730 Ethernet (HSIC) */ - { 0x0424, 0x9900 }, /* SMSC9500 USB Ethernet Device (SAL10) */ - { 0x0000, 0x0000 } /* END - Do not remove */ -}; - -/* Probe to see if a new device is actually an SMSC device */ -int smsc95xx_eth_probe(struct usb_device *dev, unsigned int ifnum, - struct ueth_data *ss) -{ - struct usb_interface *iface; - struct usb_interface_descriptor *iface_desc; - int i; - - /* let's examine the device now */ - iface = &dev->config.if_desc[ifnum]; - iface_desc = &dev->config.if_desc[ifnum].desc; - - for (i = 0; smsc95xx_dongles[i].vendor != 0; i++) { - if (dev->descriptor.idVendor == smsc95xx_dongles[i].vendor && - dev->descriptor.idProduct == smsc95xx_dongles[i].product) - /* Found a supported dongle */ - break; - } - if (smsc95xx_dongles[i].vendor == 0) - return 0; - - /* At this point, we know we've got a live one */ - debug("\n\nUSB Ethernet device detected\n"); - memset(ss, '\0', sizeof(struct ueth_data)); - - /* Initialize the ueth_data structure with some useful info */ - ss->ifnum = ifnum; - ss->pusb_dev = dev; - ss->subclass = iface_desc->bInterfaceSubClass; - ss->protocol = iface_desc->bInterfaceProtocol; - - /* - * We are expecting a minimum of 3 endpoints - in, out (bulk), and int. - * We will ignore any others. - */ - for (i = 0; i < iface_desc->bNumEndpoints; i++) { - /* is it an BULK endpoint? */ - if ((iface->ep_desc[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) { - if (iface->ep_desc[i].bEndpointAddress & USB_DIR_IN) - ss->ep_in = - iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - else - ss->ep_out = - iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - } - - /* is it an interrupt endpoint? */ - if ((iface->ep_desc[i].bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { - ss->ep_int = iface->ep_desc[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - ss->irqinterval = iface->ep_desc[i].bInterval; - } - } - debug("Endpoints In %d Out %d Int %d\n", - ss->ep_in, ss->ep_out, ss->ep_int); - - /* Do some basic sanity checks, and bail if we find a problem */ - if (usb_set_interface(dev, iface_desc->bInterfaceNumber, 0) || - !ss->ep_in || !ss->ep_out || !ss->ep_int) { - debug("Problems with device\n"); - return 0; - } - dev->privptr = (void *)ss; - - /* alloc driver private */ - ss->dev_priv = calloc(1, sizeof(struct smsc95xx_private)); - if (!ss->dev_priv) - return 0; - - return 1; -} - -int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss, - struct eth_device *eth) -{ - debug("** %s()\n", __func__); - if (!eth) { - debug("%s: missing parameter.\n", __func__); - return 0; - } - sprintf(eth->name, "%s%d", SMSC95XX_BASE_NAME, curr_eth_dev++); - eth->init = smsc95xx_init; - eth->send = smsc95xx_send; - eth->recv = smsc95xx_recv; - eth->halt = smsc95xx_halt; - eth->write_hwaddr = smsc95xx_write_hwaddr; - eth->priv = ss; - return 1; -} |