@ -5,11 +5,11 @@
*/
# include <common.h>
# include <dm.h>
# include <usb.h>
# include <malloc.h>
# include <linux/mii.h>
# include "usb_ether.h"
# include <malloc.h>
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
@ -92,14 +92,20 @@
# define FLAG_TYPE_AX88772B (1U << 2)
# define FLAG_EEPROM_MAC (1U << 3) /* initial mac address in eeprom */
/* local vars */
static int curr_eth_dev ; /* index for name of next device detected */
/* driver private */
struct asix_private {
int flags ;
# ifdef CONFIG_DM_ETH
struct ueth_data ueth ;
# endif
} ;
# ifndef CONFIG_DM_ETH
/* local vars */
static int curr_eth_dev ; /* index for name of next device detected */
# endif
/*
* Asix infrastructure commands
*/
@ -284,13 +290,12 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)
return ret ;
}
static int asix_write_hwaddr ( struct eth_device * eth )
static int asix_write_hwaddr_common ( struct ueth_data * dev , uint8_t * enetaddr )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
int ret ;
ALLOC_CACHE_ALIGN_BUFFER ( unsigned char , buf , ETH_ALEN ) ;
memcpy ( buf , eth - > e netaddr , ETH_ALEN ) ;
memcpy ( buf , enetaddr , ETH_ALEN ) ;
ret = asix_write_cmd ( dev , AX_CMD_WRITE_NODE_ID , 0 , 0 , ETH_ALEN , buf ) ;
if ( ret < 0 )
@ -325,12 +330,11 @@ static int mii_nway_restart(struct ueth_data *dev)
return r ;
}
static int asix_read_mac ( struct eth_device * eth )
static int asix_read_mac_common ( struct ueth_data * dev ,
struct asix_private * priv , uint8_t * enetaddr )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
struct asix_private * priv = ( struct asix_private * ) dev - > dev_priv ;
int i ;
ALLOC_CACHE_ALIGN_BUFFER ( unsigned char , buf , ETH_ALEN ) ;
int i ;
if ( priv - > flags & FLAG_EEPROM_MAC ) {
for ( i = 0 ; i < ( ETH_ALEN > > 1 ) ; i + + ) {
@ -339,7 +343,7 @@ static int asix_read_mac(struct eth_device *eth)
debug ( " Failed to read SROM address 04h. \n " ) ;
return - 1 ;
}
memcpy ( ( eth - > enetaddr + i * 2 ) , buf , 2 ) ;
memcpy ( enetaddr + i * 2 , buf , 2 ) ;
}
} else {
if ( asix_read_cmd ( dev , AX_CMD_READ_NODE_ID , 0 , 0 , ETH_ALEN , buf )
@ -347,7 +351,7 @@ static int asix_read_mac(struct eth_device *eth)
debug ( " Failed to read MAC address. \n " ) ;
return - 1 ;
}
memcpy ( eth - > e netaddr , buf , ETH_ALEN ) ;
memcpy ( enetaddr , buf , ETH_ALEN ) ;
}
return 0 ;
@ -414,12 +418,8 @@ static int asix_basic_reset(struct ueth_data *dev)
return 0 ;
}
/*
* Asix callbacks
*/
static int asix_init ( struct eth_device * eth , bd_t * bd )
static int asix_init_common ( struct ueth_data * dev )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
int timeout = 0 ;
# define TIMEOUT_RESOLUTION 50 /* ms */
int link_detected ;
@ -452,9 +452,8 @@ out_err:
return - 1 ;
}
static int asix_send ( struct eth_device * eth , void * packet , int length )
static int asix_send_common ( struct ueth_data * dev , void * packet , int length )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
int err ;
u32 packet_len ;
int actual_len ;
@ -481,6 +480,24 @@ static int asix_send(struct eth_device *eth, void *packet, int length)
return err ;
}
# ifndef CONFIG_DM_ETH
/*
* Asix callbacks
*/
static int asix_init ( struct eth_device * eth , bd_t * bd )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
return asix_init_common ( dev ) ;
}
static int asix_send ( struct eth_device * eth , void * packet , int length )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
return asix_send_common ( dev , packet , length ) ;
}
static int asix_recv ( struct eth_device * eth )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
@ -552,6 +569,13 @@ static void asix_halt(struct eth_device *eth)
debug ( " ** %s() \n " , __func__ ) ;
}
static int asix_write_hwaddr ( struct eth_device * eth )
{
struct ueth_data * dev = ( struct ueth_data * ) eth - > priv ;
return asix_write_hwaddr_common ( dev , eth - > enetaddr ) ;
}
/*
* Asix probing functions
*/
@ -694,9 +718,180 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
return 0 ;
/* Get the MAC address */
if ( asix_read_mac ( eth ) )
if ( asix_read_mac_common ( ss , priv , eth - > enetaddr ) )
return 0 ;
debug ( " MAC %pM \n " , eth - > enetaddr ) ;
return 1 ;
}
# endif
# ifdef CONFIG_DM_ETH
static int asix_eth_start ( struct udevice * dev )
{
struct asix_private * priv = dev_get_priv ( dev ) ;
return asix_init_common ( & priv - > ueth ) ;
}
void asix_eth_stop ( struct udevice * dev )
{
debug ( " ** %s() \n " , __func__ ) ;
}
int asix_eth_send ( struct udevice * dev , void * packet , int length )
{
struct asix_private * priv = dev_get_priv ( dev ) ;
return asix_send_common ( & priv - > ueth , packet , length ) ;
}
int asix_eth_recv ( struct udevice * dev , int flags , uchar * * packetp )
{
struct asix_private * priv = dev_get_priv ( dev ) ;
struct ueth_data * ueth = & priv - > ueth ;
uint8_t * ptr ;
int ret , len ;
u32 packet_len ;
len = usb_ether_get_rx_bytes ( ueth , & ptr ) ;
debug ( " %s: first try, len=%d \n " , __func__ , len ) ;
if ( ! len ) {
if ( ! ( flags & ETH_RECV_CHECK_DEVICE ) )
return - EAGAIN ;
ret = usb_ether_receive ( ueth , AX_RX_URB_SIZE ) ;
if ( ret = = - EAGAIN )
return ret ;
len = usb_ether_get_rx_bytes ( ueth , & ptr ) ;
debug ( " %s: second try, len=%d \n " , __func__ , len ) ;
}
/*
* 1 st 4 bytes contain the length of the actual data as two
* complementary 16 - bit words . Extract the length of the data .
*/
if ( len < sizeof ( packet_len ) ) {
debug ( " Rx: incomplete packet length \n " ) ;
goto err ;
}
memcpy ( & packet_len , ptr , sizeof ( packet_len ) ) ;
le32_to_cpus ( & packet_len ) ;
if ( ( ( ~ packet_len > > 16 ) & 0x7ff ) ! = ( packet_len & 0x7ff ) ) {
debug ( " Rx: malformed packet length: %#x (%#x:%#x) \n " ,
packet_len , ( ~ packet_len > > 16 ) & 0x7ff ,
packet_len & 0x7ff ) ;
goto err ;
}
packet_len = packet_len & 0x7ff ;
if ( packet_len > len - sizeof ( packet_len ) ) {
debug ( " Rx: too large packet: %d \n " , packet_len ) ;
goto err ;
}
* packetp = ptr + sizeof ( packet_len ) ;
return packet_len ;
err :
usb_ether_advance_rxbuf ( ueth , - 1 ) ;
return - EINVAL ;
}
static int asix_free_pkt ( struct udevice * dev , uchar * packet , int packet_len )
{
struct asix_private * priv = dev_get_priv ( dev ) ;
if ( packet_len & 1 )
packet_len + + ;
usb_ether_advance_rxbuf ( & priv - > ueth , sizeof ( u32 ) + packet_len ) ;
return 0 ;
}
int asix_write_hwaddr ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
struct asix_private * priv = dev_get_priv ( dev ) ;
if ( priv - > flags & FLAG_TYPE_AX88172 )
return - ENOSYS ;
return asix_write_hwaddr_common ( & priv - > ueth , pdata - > enetaddr ) ;
}
static int asix_eth_probe ( struct udevice * dev )
{
struct eth_pdata * pdata = dev_get_platdata ( dev ) ;
struct asix_private * priv = dev_get_priv ( dev ) ;
struct ueth_data * ss = & priv - > ueth ;
int ret ;
priv - > flags = dev - > driver_data ;
ret = usb_ether_register ( dev , ss , AX_RX_URB_SIZE ) ;
if ( ret )
return ret ;
ret = asix_basic_reset ( ss ) ;
if ( ret )
goto err ;
/* Get the MAC address */
ret = asix_read_mac_common ( ss , priv , pdata - > enetaddr ) ;
if ( ret )
goto err ;
debug ( " MAC %pM \n " , pdata - > enetaddr ) ;
return 0 ;
err :
return usb_ether_deregister ( ss ) ;
}
static const struct eth_ops asix_eth_ops = {
. start = asix_eth_start ,
. send = asix_eth_send ,
. recv = asix_eth_recv ,
. free_pkt = asix_free_pkt ,
. stop = asix_eth_stop ,
. write_hwaddr = asix_write_hwaddr ,
} ;
U_BOOT_DRIVER ( asix_eth ) = {
. name = " asix_eth " ,
. id = UCLASS_ETH ,
. probe = asix_eth_probe ,
. ops = & asix_eth_ops ,
. priv_auto_alloc_size = sizeof ( struct asix_private ) ,
. platdata_auto_alloc_size = sizeof ( struct eth_pdata ) ,
} ;
static const struct usb_device_id asix_eth_id_table [ ] = {
/* Apple USB Ethernet Adapter */
{ USB_DEVICE ( 0x05ac , 0x1402 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* D-Link DUB-E100 H/W Ver B1 */
{ USB_DEVICE ( 0x07d1 , 0x3c05 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* D-Link DUB-E100 H/W Ver C1 */
{ USB_DEVICE ( 0x2001 , 0x1a02 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* Cables-to-Go USB Ethernet Adapter */
{ USB_DEVICE ( 0x0b95 , 0x772a ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* Trendnet TU2-ET100 V3.0R */
{ USB_DEVICE ( 0x0b95 , 0x7720 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* SMC */
{ USB_DEVICE ( 0x0b95 , 0x1720 ) , . driver_info = FLAG_TYPE_AX88172 } ,
/* MSI - ASIX 88772a */
{ USB_DEVICE ( 0x0db0 , 0xa877 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* Linksys 200M v2.1 */
{ USB_DEVICE ( 0x13b1 , 0x0018 ) , . driver_info = FLAG_TYPE_AX88172 } ,
/* 0Q0 cable ethernet */
{ USB_DEVICE ( 0x1557 , 0x7720 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* DLink DUB-E100 H/W Ver B1 Alternate */
{ USB_DEVICE ( 0x2001 , 0x3c05 ) , . driver_info = FLAG_TYPE_AX88772 } ,
/* ASIX 88772B */
{ USB_DEVICE ( 0x0b95 , 0x772b ) ,
. driver_info = FLAG_TYPE_AX88772B | FLAG_EEPROM_MAC } ,
{ USB_DEVICE ( 0x0b95 , 0x7e2b ) , . driver_info = FLAG_TYPE_AX88772B } ,
{ } /* Terminating entry */
} ;
U_BOOT_USB_DEVICE ( asix_eth , asix_eth_id_table ) ;
# endif