精华内容
下载资源
问答
  • USB转以太网,100M产品; 可以量产。
  • RTL8150L是Realtek公司的一款USB转快速以太网控制器,与USB1.1规范相兼容。给出了基于OMAP1621的宽带终端RTL8150L的USB转以太网功能的软硬件设计,并给出了调试结果。
  • 亚信电子(ASIX Electronics)近日宣布将针对嵌入式网络应用之USB to LAN系列,新增一款USB转以太网控制芯片AX88772C并支持Microsoft AOAC(Always On Always Connected),AX88772C可满足当前嵌入式系统尺寸小型化...
  • 高通8953平台usb转以太网芯片ax88772驱动 文章目录高通8953平台usb转以太网芯片ax88772驱动ax88772电路图ax88772 mac地址烧录工具使用说明增加eeprom的读写USB读写函数进入eeprom获取数据读写eeprom检查网络设备的...

    高通8953平台usb转以太网芯片ax88772驱动

    内核版本 Linux4.4
    平台 rk3399&高通8953
    作者 nineyole

    ​ 在我们平时的时候会经常使用到usb转以太网,特别是在高通平台,由于其没有以太网接口,因此很多时候都是使用的usb转以太网来实现的,本文主要讨论起驱动流程,包括驱动调试以及如何写入固定的mac地址。

    ax88772电路图

    其电路图如下图所示,其实也没啥,如果有问题发现不能枚举设备,就可以看一下复位,供电是否正常。

    在这里插入图片描述

    ax88772 mac地址烧录工具使用说明

    ax88772 有这样一个windows下的工具,可以直接来烧录srom的数据,其中就可以产生对应的配置信息。如果你的ax88772 是在windows下使用的,可以直接使用这个工具,但是如果你是在Linux或者Android下就需要自己编写对应的函数来读写了。

    在这里插入图片描述

    增加eeprom的读写

    ax88772驱动调试过程中,会经常碰到一个问题就是如何将MAC地址烧录进去的问题,以下是可行的方案

    • 1. 将USB引出来连接到X86的PC上用附件的工具烧录EEPROM的内容。

    • 2. 请EEPROM厂商直接先烧录好EEPROM的值,直接贴片。

    • 3. 省略掉EEPROM,修改驱动,将MAC地址放入到Flash的某个位置,加载驱动的过程可以读取相应的值并写入到寄存器中。可以参考Linux驱动中ax8817x_get_mac内容。

      但是上面这三个方法都不太适合我们,我们的主板已经焊接好了,并且使用的是Android系统,因此尝试着在Linux底层来产生一个随机的mac地址,然后写入到eeprom中,以下是相关的驱动调试说明。

      我们的策略是先用工具产生一个srom数据。比如我们产生的如下:

      unsigned short eeprom_data_default[]={
      	0x155A,0xEC75,0x2012,0x2927,0x0000,0x0000,0x000E,0x0904,
      	0x6022,0x7112,0x190E,0x3D04,0x3D04,0x3D04,0x3D04,0x8005,
      	0x0006,0x10E0,0x4224,0x4012,0x4927,0xFFFF,0x0000,0xFFFF,
      	0xC009,0x0E03,0x3000,0x3000,0x3000,0x3000,0x3000,0x3200,
      	0x1201,0x0002,0xFFFF,0x0040,0x950B,0x2B77,0x0200,0x0102,
      	0x0301,0x0902,0x2700,0x0101,0x04A0,0x6409,0x0400,0x0003,
      	0xFFFF,0x0007,0x0705,0x8103,0x0800,0x0B07,0x0582,0x0200,
      	0x0200,0x0705,0x0302,0x0002,0x00FF,0x0403,0x3000,0xFFFF,
      	0x1201,0x0002,0xFFFF,0x0008,0x950B,0x2B77,0x0200,0x0102,
      	0x0301,0x0902,0x2700,0x0101,0x04A0,0x6409,0x0400,0x0003,
      	0xFFFF,0x0007,0x0705,0x8103,0x0800,0xA007,0x0582,0x0240,
      	0x0000,0x0705,0x0302,0x4000,0x00DD,0xFFFF,0xAAAA,0xBBBB,
      	0x2203,0x4100,0x5300,0x4900,0x5800,0x2000,0x4500,0x6C00,
      	0x6500,0x6300,0x2E00,0x2000,0x4300,0x6F00,0x7200,0x7000,
      	0x2E00,0x1203,0x4100,0x5800,0x3800,0x3800,0x3700,0x3700,
      	0x3200,0x4300,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF
      };
      

      然后调用对应的函数写入进去。比如我们在asix_devices.c做如下的修改:

      --- a/kernel/msm-4.9/drivers/net/usb/asix_devices.c
      +++ b/kernel/msm-4.9/drivers/net/usb/asix_devices.c
      @@ -20,6 +20,18 @@
        */
       static void asix_set_netdev_dev_addr(struct usbnet *dev, u8 *addr)
       {
       	if (is_valid_ether_addr(addr)) {
      @@ -709,8 +995,12 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
       		return ret;
       	}
      -	asix_set_netdev_dev_addr(dev, buf);
      -
      +	//asix_set_netdev_dev_addr(dev, buf);
      +	memset(buf, 0, ETH_ALEN);
      +	ret = ax8817x_get_mac(dev, buf);
      +	if (ret < 0) {
      +		deverr(dev, "Get HW address failed: %d", ret);
      +	}
       	/* Initialize MII structure */
       	dev->mii.dev = dev->net;
       	dev->mii.mdio_read = asix_mdio_read;
      

      调用了ax8817x_get_mac函数,ax8817x_get_mac会去检查eeprom里面是否有mac地址,如果没有(表示为空)就写入一个eeprom_data_default参数,然后随机产生一个mac地址,并通过ioctl_write_eeprom写入到对应的地址。以下是对应的函数解析说明。

    USB读写函数

    static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,u16 size, void *data)
    {
        return usb_control_msg(
            dev->udev,
            usb_rcvctrlpipe(dev->udev, 0),
            cmd,
            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
            value,
            index,
            data,
            size,
            USB_CTRL_GET_TIMEOUT);
    }
    
    static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data)
    {
        return usb_control_msg(
            dev->udev,
            usb_sndctrlpipe(dev->udev, 0),
            cmd,
            USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
            value,
            index,
            data,
            size,
            USB_CTRL_SET_TIMEOUT);
    }
    

    进入eeprom获取数据

    static int access_eeprom_mac(struct usbnet *dev, u8 *buf, u8 offset, bool wflag)
    {
        int ret = 0, i;
        u16* tmp = (u16*)buf;
        if (wflag) {
            ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_EN,0, 0, 0, NULL);
            if (ret < 0)
                return ret;
            mdelay(15);
        }
        for (i = 0; i < (ETH_ALEN >> 1); i++) {
            if (wflag) {
                u16 wd = cpu_to_le16(*(tmp + i));
                ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM, offset + i,wd, 0, NULL);
                if (ret < 0)
                    break;
                    mdelay(15);
            }
            else {
                ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM,offset + i, 0, 2, tmp + i);
                if (ret < 0)
                    break;
            }
        }
        if (!wflag) {
            if (ret < 0) {
            #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
                netdev_dbg(dev->net, "Failed to read MAC address from EEPROM: %d\n", ret);
            #else
                devdbg(dev, "Failed to read MAC address from EEPROM: %d\n", ret);
            #endif
                return ret;
            }
            memcpy(dev->net->dev_addr, buf, ETH_ALEN);
        }
        else {
            ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_DIS,
                              0, 0, 0, NULL);
            if (ret < 0)
                return ret;
            /* reload eeprom data */
            ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS,AX_GPIO_RSE, 0, 0, NULL);
            if (ret < 0)
                return ret;
        }
        return 0;
    }
    

    读写eeprom

    int ioctl_read_eeprom(struct usbnet *dev,u8 *buf)
    {
        int i, retval = 0;
        u16 * tmp16;    
        tmp16 = kmalloc(2, GFP_KERNEL);
        if (!tmp16) {           
            return -ERESTARTSYS;
        }
        for (i = 0; i < sizeof(buf); i++) {
            retval = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, i, 
                                      0, 2, tmp16);
            if(retval < 0) {
                kfree(tmp16);                   
                return retval;
            }
            *(buf + i) = be16_to_cpu(*tmp16);
        }
        kfree(tmp16);   
        return retval;
    }
    int ioctl_write_eeprom(struct usbnet *dev)
    {
        int i, retval;
        printk("start ioctl_write_eeprom\n");
        retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_EN, 0,0, 0, NULL);
        if (retval < 0) {
            printk("ioctl_write_eeprom ax8817x_write_cmd fail\n");
            return retval;
        }
        mdelay(100);
        for (i = 0; i < sizeof(eeprom_data_default); i++){
            retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
                                       cpu_to_be16(*(eeprom_data_default + i)), 0, NULL);
    
            if (retval < 0) {
                return retval;
            }
            mdelay(100);
        }
        retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_DIS, 0,0, 0, NULL);
        if (retval < 0) {
            return retval;
        }
        mdelay(100);
        retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, AXGPIOS_RSE, 0, 0, NULL);
        mdelay(100);
        return retval;
    }
    

    检查网络设备的mac地址

    static int ax8817x_check_ether_addr(struct usbnet *dev)
    {
        unsigned char *tmp = (unsigned char*)dev->net->dev_addr;
        u8 default_mac[6] = {0, 0x0e, 0xc6, 0x87, 0x72, 0x01};
        if (((*((u8*)tmp) == 0) && (*((u8*)tmp + 1) == 0) && (*((u8*)tmp + 2) == 0)) ||
            !is_valid_ether_addr((u8*)tmp) ||
            !memcmp(dev->net->dev_addr, default_mac, ETH_ALEN)) {
            printk("Found invalid EEPROM MAC address value:");              
            printk("%02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)tmp + 0),
                   *((u8*)tmp + 1),
                   *((u8*)tmp + 2),
                   *((u8*)tmp + 3),
                   *((u8*)tmp + 4),
                   *((u8*)tmp + 5));
    
            #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
                eth_hw_addr_random(dev->net);
            #else
                #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
                dev->net->addr_assign_type |= NET_ADDR_RANDOM;
                #endif	
           	 	random_ether_addr(dev->net->dev_addr); 
            #endif
            printk("random mac:%02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)dev->net->dev_addr + 0),
                   *((u8*)dev->net->dev_addr + 1),
                   *((u8*)dev->net->dev_addr + 2),
                   *((u8*)dev->net->dev_addr + 3),
                   *((u8*)dev->net->dev_addr + 4),
                   *((u8*)dev->net->dev_addr + 5));
            return -EADDRNOTAVAIL;  
        } 
        return 0;
    }
    

    获取mac地址

    static int ax8817x_get_mac(struct usbnet *dev, u8* buf)
    {
        int ret, i;
        u8 default_mac[6] = {0, 0x0e, 0xc6, 0x87, 0x72, 0x01};
        /*read mac from eeprom*/
        ret = access_eeprom_mac(dev, buf, 0x04, 0);
        printk("mac from eeprom is: %02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)dev->net->dev_addr + 0),
               *((u8*)dev->net->dev_addr + 1),
               *((u8*)dev->net->dev_addr + 2),
               *((u8*)dev->net->dev_addr + 3),
               *((u8*)dev->net->dev_addr + 4),
               *((u8*)dev->net->dev_addr + 5));
        if (ret < 0)
            goto out;
        if (!memcmp(dev->net->dev_addr, default_mac, ETH_ALEN)) {
            ret=ioctl_write_eeprom(dev);
            if(ret<0)
            {
                deverr(dev, "ioctl_write_eeprom: %d", ret);
                goto out;
            }
        }
        /*check mac,if not ok,use eth_hw_addr_random to get the random mac*/
        if (ax8817x_check_ether_addr(dev)) {
            printk(" write eeprom mac is: %02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)dev->net->dev_addr + 0),
                   *((u8*)dev->net->dev_addr + 1),
                   *((u8*)dev->net->dev_addr + 2),
                   *((u8*)dev->net->dev_addr + 3),
                   *((u8*)dev->net->dev_addr + 4),
                   *((u8*)dev->net->dev_addr + 5));
            ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x04, 1);
            if (ret < 0) {
                deverr(dev, "Failed to write MAC to EEPROM: %d", ret);
                goto out;
            }
            msleep(5);
            /*read mac from eeprom*/
            ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
                                   0, 0, ETH_ALEN, buf);
            printk("test buf: %02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)buf + 0),
                   *((u8*)buf + 1),
                   *((u8*)buf + 2),
                   *((u8*)buf + 3),
                   *((u8*)buf + 4),
                   *((u8*)buf + 5));
    
            if (ret < 0) {
                deverr(dev, "Failed to read MAC address: %d", ret);
                goto out;
            }
            printk("test dev_addr: %02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)dev->net->dev_addr + 0),
                   *((u8*)dev->net->dev_addr + 1),
                   *((u8*)dev->net->dev_addr + 2),
                   *((u8*)dev->net->dev_addr + 3),
                   *((u8*)dev->net->dev_addr + 4),
                   *((u8*)dev->net->dev_addr + 5));
            for (i = 0; i < ETH_ALEN; i++)
                if (*(dev->net->dev_addr + i) != *((u8*)buf + i)) {
                    deverr(dev, "Found invalid EEPROM part or non-EEPROM");
                    break;
                }
        }
        memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
        /* Set the MAC address */
        ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID, 0, 0,ETH_ALEN, dev->net->dev_addr);
        if (ret < 0) {
            deverr(dev, "Failed to write MAC address: %d", ret);
            goto out;
        }
        return 0;
        out:
        return ret;
    }
    

    可能遇到的问题分析

    ax8872针对eeprom无法写入信息排查

    关于eeprom器件的焊接

    SK管脚和DO管脚上的电阻焊错。请检查板子上这两个电阻是否正确。 93C66是否有虚焊。

    在这里插入图片描述

    关于eeprom器件的选择问题

    AX8877293C56和93C66,有支持8bit的,也有同时支持8Bit和16bit的。而ax88772要求的是16bit的EEPROM。需要根据我们使用EEPROM规格书,确定一下EEPROM型号是否正确。 以下是推荐的EEPROM型号及对应的厂商信息:

    这里需要特别注意eeprom的选型。

    在这里插入图片描述

    烧录工具无法使用

    如果在windows下面无法烧录srom,需要先安装一个test的驱动,然后才可以下载的。

    展开全文
  • Quectel_SC20&SC60&SG3x_USB转以太网_应用指导_V1.0.pdf
  • Andorid:msm8909:USB转以太网驱动添加

    千次阅读 2019-05-30 10:43:39
    硬件使用USB转以太网芯片RTL8152,默认的驱动源码中就有,只需要编译进内核就可以使用了。

    目录

    写在前面

    本次目的

    详细步骤

    修改内核

    重新编译

    上电调试

    本次小结

     

    写在前面

    SOC:Qualcomm msm8909

    Core-Board:SC20-CE QA/PJ

    Base-Board:xxx

    Linux Kernel:xxx

    Android:7.1

     

    本次目的

    硬件使用USB转以太网芯片RTL8152,默认的驱动源码中就有,只需要编译进内核就可以使用了。


    详细步骤

     

    修改内核

    kernel/arch/arm/configs/msm8909-1gb_defconfig

    通过menuconfig的搜索功能了解到内核配置中有关于这个驱动的源代码,但是尚未编译进内核,所以这里加入相关配置:

    CONFIG_MII=y
    CONFIG_USB_RTL8152=y

    为什么修改这个配置文件,以及为什么不能在kernel下面直接使用“make menuconfig”修改内核,这里不赘述了,有时间的话我会整理出来,不过相信大家应该也很容易分析到这些,我也是才接触高通不久,发现有很多跟其他平台不一样的细节。 

    重新编译

    使用“make bootimage”重新编译内核,烧录后调试。

    上电调试

    其实早在同平台的其他型号核心板中我做了类似的事情,加入驱动之后上电开机,命令行“ifconfig”就可以看到多出了一块“eth0”的网卡信息,但是这次却没有,当然有可能是网卡没有“up”,当我尝试输入“ifconfig eth0”的时候发现是有这块网卡的信息的,但是注意到Mac地址信息是空的,并且敲一些配置该网卡的命令会出错,比如“ifconfig eth0 192.168.0.188”或者“ifconfig eth0 up”会出现一些不正常的信息,虽然再次查看网卡信息发现命令好像是生效了,但是因为网络之类的仍然不正常,所以我感觉到了网卡还没有正常工作,于是查看了系统启动日志中关于这块的信息有:

    [    5.177596] usbcore: registered new interface driver r8152
    [   11.423978] r8152 1-1.4:1.0 eth0: v1.0.0 (2013/05/03)
    [   12.308264] ueventd: Cannot set 'u:object_r:usb_device:s0' SELinux label on '/dev/bus/usb/001/004' device (Permission denied)
    [   12.340179] ueventd: Coldboot took 1.07s.

     看到前面两条信息的时候我觉得很正常,一切都是对的,当注意到“ueventd”这里有一条关于“SELinux”权限问题的时候,并且注意到“/dev/bus/usb/001/004”感觉这个消息还跟“r8152”可能是相关的,我就在想会不是这个权限导致了Mac地址获取不到(当然后面也证明了这个是无稽之谈,纯属瞎猜),于是我就修改了系统SELinux,放宽了权限,重新启动,的确没有关于这个权限的问题了,我大喜,以为自己解决了这个问题,然后尝试发现Mac地址仍然为空,功能依旧不正常,看来不是这个原因导致的,一切回到解放前。

    于是我就重新尝试用命令给它分配了一个Mac地址,然后测试网络之类的,都正常了。

    ifconfig eth0 down
    ifconfig eth0 hw ether 47:72:65:65:6e:00
    ifconfig eth0 up

     值得一提的是没有获取Mac地址可能是因为网卡没有“up”,当然如果你直接“up”也不会成功,还是需要使用上面第二条命令分配一个Mac地址给“eth0”,当“up”之后,会发现再敲命令“ifconfig”就可以看到“eth0”网卡的相关信息了,Mac地址也有了,网络功能也正常了,纳尼,是不是有一种呵呵的冲动,搞半天就是分配一下Mac地址就可以了。

    关于如何放宽SELinux权限,我的这些博文中有相关记录:

    https://blog.csdn.net/uestc_ganlin/article/details/90673527

    https://blog.csdn.net/uestc_ganlin/article/details/83377528

     

    本次小结

    这个人很懒,什么也没有留下!

     

     

    展开全文
  • 最近安装了一些第三方软件,升级了系统之后发现USB转以太网无法被MacBook识别,但是wifi可以上网的。估计是某些软件注入了什么代码导致系统接口保护系统发生改变。 下面的命令为检测驱动是否装载的一些命令. ...

    最近安装了一些第三方软件,升级了系统之后发现USB转以太网无法被MacBook识别,但是wifi可以上网的。估计是某些软件注入了什么代码导致系统接口保护系统发生改变。

    下面的命令为检测驱动是否装载的一些命令.

    • sudo kextload /Library/Extensions/AX88772.kext
    • sudo kextutil -v AX88772.kext
    • codesign -dvvv AX88772.kext
    • codesign –verify -vvvv AX88772.kext

    就是把mac的新特性System Integrity Protection关闭就解决。

    操作步骤:

    1. 重启电脑,启动时按住Command+R;
    2. 进入恢复模式界面后,在工具栏打开终端;
    3. 输入csrutil status 查看当前状态:
      csrutil status
      System Integrity Protection status: enabled.
    4. 输入: csrutil disable (就是关闭sip)
    5. 重启电脑即可

    重启后如果可以到网络设置里检查有没有网卡生效,如果未生效可以执行:

    sudo kextutil -v AX88772.kext

    如果按照上面的方法执行还不能解决,可能AX88772驱动在系统更新后不兼容或者驱动程序太旧了,这时要下载最新的驱动。

    资源:
    http://www.lulian.cn/download/5-cn.html

    展开全文
  • 在全志A63板子上使用了一个USB转以太网 RTL8152B芯片,但是测试过程中发现不能上网,需要手动写入mac。经过一番询问,需要购买mac。为了自动写入mac,修改驱动就可以。 修改文件 lichee/linux-3.10/drivers/...
    1. 背景
      在全志A63板子上使用了一个USB转以太网 RTL8152B芯片,但是测试过程中发现不能上网,需要手动写入mac。经过一番询问,需要购买mac。为了自动写入mac,修改驱动就可以。
    2. 修改文件 lichee/linux-3.10/drivers/net/usb/r8152.c
      修改内容
    //added by ZWQ in 20181106
    extern int sunxi_get_soc_chipid(u8 *chipid);//16 字节
    
    static int rtl8152_set_mac_address(struct net_device *netdev, void *p);
    static inline void set_ethernet_addr(struct r8152 *tp)
    {
    	#if 0
    	struct net_device *dev = tp->netdev;
    	u8 *node_id;
    
    	node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
    	if (!node_id) {
    		netif_err(tp, probe, dev, "out of memory");
    		return;
    	}
    
    	if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
    		netif_notice(tp, probe, dev, "inet addr fail\n");
    	else {
    		memcpy(dev->dev_addr, node_id, dev->addr_len);
    		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
    	}
    	kfree(node_id);
    	#else //--------------------------------------------------
    	
    	struct net_device *dev = tp->netdev;
    	struct sockaddr sa;
    	int ret;
    	unsigned char chipid[16];//ZWQ 芯片ID号
    	int ii =0 ;
    
    	if (tp->version == RTL_VER_01)
    		ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
    	else
    		ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
    
    	if (ret < 0) {
    		netif_err(tp, probe, dev, "ether addr fail\n");
    	} else if (!is_valid_ether_addr(sa.sa_data)) {
    		netif_warn(tp, probe, dev, "Invalid ether addr\n");
    		eth_hw_addr_random(dev);
    		memcpy(sa.sa_data, dev->dev_addr, ETH_ALEN);
    		memset(chipid,0,16);
    		sunxi_get_soc_chipid(chipid);
    		//04:7d:7b:b8:ee:be  例如这6个字节
    		 memcpy( dev->dev_addr,&chipid[10], ETH_ALEN);
    		 memcpy(sa.sa_data, dev->dev_addr, ETH_ALEN);//unsigned char dev_addr[MAX_ADDR_LEN] ETH_ALEN = 6
    		rtl8152_set_mac_address(dev, &sa);
    	} else {
    		if (tp->version == RTL_VER_01)
    			memcpy(dev->dev_addr, sa.sa_data, ETH_ALEN);
    		else
    			ret = rtl8152_set_mac_address(dev, &sa);
    
    		#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
    		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
    		#endif
    	}
    	#endif
    }
    
    
    1. 完整驱动
    /*
     *  Copyright (c) 2013 Realtek Semiconductor Corp. All rights reserved.
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     */
    
    #include <linux/init.h>
    #include <linux/signal.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/version.h>
    #include <linux/netdevice.h>
    #include <linux/etherdevice.h>
    #include <linux/mii.h>
    #include <linux/ethtool.h>
    #include <linux/usb.h>
    #include <linux/crc32.h>
    #include <linux/if_vlan.h>
    #include <linux/uaccess.h>
    
    /* Version Information */
    #define DRIVER_VERSION "v1.0.0 (2013/05/03)"
    #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
    #define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
    #define MODULENAME "r8152"
    
    #define R8152_PHY_ID		32
    
    #define PLA_IDR			0xc000
    #define PLA_RCR			0xc010
    #define PLA_RMS			0xc016
    #define PLA_RXFIFO_CTRL0	0xc0a0
    #define PLA_RXFIFO_CTRL1	0xc0a4
    #define PLA_RXFIFO_CTRL2	0xc0a8
    #define PLA_FMC			0xc0b4
    #define PLA_CFG_WOL		0xc0b6
    #define PLA_MAR			0xcd00
    #define PLA_BACKUP		0xd000
    #define PAL_BDC_CR		0xd1a0
    #define PLA_LEDSEL		0xdd90
    #define PLA_LED_FEATURE		0xdd92
    #define PLA_PHYAR		0xde00
    #define PLA_GPHY_INTR_IMR	0xe022
    #define PLA_EEE_CR		0xe040
    #define PLA_EEEP_CR		0xe080
    #define PLA_MAC_PWR_CTRL	0xe0c0
    #define PLA_TCR0		0xe610
    #define PLA_TCR1		0xe612
    #define PLA_TXFIFO_CTRL		0xe618
    #define PLA_RSTTELLY		0xe800
    #define PLA_CR			0xe813
    #define PLA_CRWECR		0xe81c
    #define PLA_CONFIG5		0xe822
    #define PLA_PHY_PWR		0xe84c
    #define PLA_OOB_CTRL		0xe84f
    #define PLA_CPCR		0xe854
    #define PLA_MISC_0		0xe858
    #define PLA_MISC_1		0xe85a
    #define PLA_OCP_GPHY_BASE	0xe86c
    #define PLA_TELLYCNT		0xe890
    #define PLA_SFF_STS_7		0xe8de
    #define PLA_PHYSTATUS		0xe908
    #define PLA_BP_BA		0xfc26
    #define PLA_BP_0		0xfc28
    #define PLA_BP_1		0xfc2a
    #define PLA_BP_2		0xfc2c
    #define PLA_BP_3		0xfc2e
    #define PLA_BP_4		0xfc30
    #define PLA_BP_5		0xfc32
    #define PLA_BP_6		0xfc34
    #define PLA_BP_7		0xfc36
    
    #define USB_DEV_STAT		0xb808
    #define USB_USB_CTRL		0xd406
    #define USB_PHY_CTRL		0xd408
    #define USB_TX_AGG		0xd40a
    #define USB_RX_BUF_TH		0xd40c
    #define USB_USB_TIMER		0xd428
    #define USB_PM_CTRL_STATUS	0xd432
    #define USB_TX_DMA		0xd434
    #define USB_UPS_CTRL		0xd800
    #define USB_BP_BA		0xfc26
    #define USB_BP_0		0xfc28
    #define USB_BP_1		0xfc2a
    #define USB_BP_2		0xfc2c
    #define USB_BP_3		0xfc2e
    #define USB_BP_4		0xfc30
    #define USB_BP_5		0xfc32
    #define USB_BP_6		0xfc34
    #define USB_BP_7		0xfc36
    
    /* OCP Registers */
    #define OCP_ALDPS_CONFIG	0x2010
    #define OCP_EEE_CONFIG1		0x2080
    #define OCP_EEE_CONFIG2		0x2092
    #define OCP_EEE_CONFIG3		0x2094
    #define OCP_EEE_AR		0xa41a
    #define OCP_EEE_DATA		0xa41c
    
    /* PLA_RCR */
    #define RCR_AAP			0x00000001
    #define RCR_APM			0x00000002
    #define RCR_AM			0x00000004
    #define RCR_AB			0x00000008
    #define RCR_ACPT_ALL		(RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
    
    /* PLA_RXFIFO_CTRL0 */
    #define RXFIFO_THR1_NORMAL	0x00080002
    #define RXFIFO_THR1_OOB		0x01800003
    
    /* PLA_RXFIFO_CTRL1 */
    #define RXFIFO_THR2_FULL	0x00000060
    #define RXFIFO_THR2_HIGH	0x00000038
    #define RXFIFO_THR2_OOB		0x0000004a
    
    /* PLA_RXFIFO_CTRL2 */
    #define RXFIFO_THR3_FULL	0x00000078
    #define RXFIFO_THR3_HIGH	0x00000048
    #define RXFIFO_THR3_OOB		0x0000005a
    
    /* PLA_TXFIFO_CTRL */
    #define TXFIFO_THR_NORMAL	0x00400008
    
    /* PLA_FMC */
    #define FMC_FCR_MCU_EN		0x0001
    
    /* PLA_EEEP_CR */
    #define EEEP_CR_EEEP_TX		0x0002
    
    /* PLA_TCR0 */
    #define TCR0_TX_EMPTY		0x0800
    #define TCR0_AUTO_FIFO		0x0080
    
    /* PLA_TCR1 */
    #define VERSION_MASK		0x7cf0
    
    /* PLA_CR */
    #define CR_RST			0x10
    #define CR_RE			0x08
    #define CR_TE			0x04
    
    /* PLA_CRWECR */
    #define CRWECR_NORAML		0x00
    #define CRWECR_CONFIG		0xc0
    
    /* PLA_OOB_CTRL */
    #define NOW_IS_OOB		0x80
    #define TXFIFO_EMPTY		0x20
    #define RXFIFO_EMPTY		0x10
    #define LINK_LIST_READY		0x02
    #define DIS_MCU_CLROOB		0x01
    #define FIFO_EMPTY		(TXFIFO_EMPTY | RXFIFO_EMPTY)
    
    /* PLA_MISC_1 */
    #define RXDY_GATED_EN		0x0008
    
    /* PLA_SFF_STS_7 */
    #define RE_INIT_LL		0x8000
    #define MCU_BORW_EN		0x4000
    
    /* PLA_CPCR */
    #define CPCR_RX_VLAN		0x0040
    
    /* PLA_CFG_WOL */
    #define MAGIC_EN		0x0001
    
    /* PAL_BDC_CR */
    #define ALDPS_PROXY_MODE	0x0001
    
    /* PLA_CONFIG5 */
    #define LAN_WAKE_EN		0x0002
    
    /* PLA_LED_FEATURE */
    #define LED_MODE_MASK		0x0700
    
    /* PLA_PHY_PWR */
    #define TX_10M_IDLE_EN		0x0080
    #define PFM_PWM_SWITCH		0x0040
    
    /* PLA_MAC_PWR_CTRL */
    #define D3_CLK_GATED_EN		0x00004000
    #define MCU_CLK_RATIO		0x07010f07
    #define MCU_CLK_RATIO_MASK	0x0f0f0f0f
    
    /* PLA_GPHY_INTR_IMR */
    #define GPHY_STS_MSK		0x0001
    #define SPEED_DOWN_MSK		0x0002
    #define SPDWN_RXDV_MSK		0x0004
    #define SPDWN_LINKCHG_MSK	0x0008
    
    /* PLA_PHYAR */
    #define PHYAR_FLAG		0x80000000
    
    /* PLA_EEE_CR */
    #define EEE_RX_EN		0x0001
    #define EEE_TX_EN		0x0002
    
    /* USB_DEV_STAT */
    #define STAT_SPEED_MASK		0x0006
    #define STAT_SPEED_HIGH		0x0000
    #define STAT_SPEED_FULL		0x0001
    
    /* USB_TX_AGG */
    #define TX_AGG_MAX_THRESHOLD	0x03
    
    /* USB_RX_BUF_TH */
    #define RX_BUF_THR		0x7a120180
    
    /* USB_TX_DMA */
    #define TEST_MODE_DISABLE	0x00000001
    #define TX_SIZE_ADJUST1		0x00000100
    
    /* USB_UPS_CTRL */
    #define POWER_CUT		0x0100
    
    /* USB_PM_CTRL_STATUS */
    #define RWSUME_INDICATE		0x0001
    
    /* USB_USB_CTRL */
    #define RX_AGG_DISABLE		0x0010
    
    /* OCP_ALDPS_CONFIG */
    #define ENPWRSAVE		0x8000
    #define ENPDNPS			0x0200
    #define LINKENA			0x0100
    #define DIS_SDSAVE		0x0010
    
    /* OCP_EEE_CONFIG1 */
    #define RG_TXLPI_MSK_HFDUP	0x8000
    #define RG_MATCLR_EN		0x4000
    #define EEE_10_CAP		0x2000
    #define EEE_NWAY_EN		0x1000
    #define TX_QUIET_EN		0x0200
    #define RX_QUIET_EN		0x0100
    #define SDRISETIME		0x0010	/* bit 4 ~ 6 */
    #define RG_RXLPI_MSK_HFDUP	0x0008
    #define SDFALLTIME		0x0007	/* bit 0 ~ 2 */
    
    /* OCP_EEE_CONFIG2 */
    #define RG_LPIHYS_NUM		0x7000	/* bit 12 ~ 15 */
    #define RG_DACQUIET_EN		0x0400
    #define RG_LDVQUIET_EN		0x0200
    #define RG_CKRSEL		0x0020
    #define RG_EEEPRG_EN		0x0010
    
    /* OCP_EEE_CONFIG3 */
    #define FST_SNR_EYE_R		0x1500	/* bit 7 ~ 15 */
    #define RG_LFS_SEL		0x0060	/* bit 6 ~ 5 */
    #define MSK_PH			0x0006	/* bit 0 ~ 3 */
    
    /* OCP_EEE_AR */
    /* bit[15:14] function */
    #define FUN_ADDR		0x0000
    #define FUN_DATA		0x4000
    /* bit[4:0] device addr */
    #define DEVICE_ADDR		0x0007
    
    /* OCP_EEE_DATA */
    #define EEE_ADDR		0x003C
    #define EEE_DATA		0x0002
    
    enum rtl_register_content {
    	_100bps		= 0x08,
    	_10bps		= 0x04,
    	LINK_STATUS	= 0x02,
    	FULL_DUP	= 0x01,
    };
    
    #define RTL8152_REQT_READ	0xc0
    #define RTL8152_REQT_WRITE	0x40
    #define RTL8152_REQ_GET_REGS	0x05
    #define RTL8152_REQ_SET_REGS	0x05
    
    #define BYTE_EN_DWORD		0xff
    #define BYTE_EN_WORD		0x33
    #define BYTE_EN_BYTE		0x11
    #define BYTE_EN_SIX_BYTES	0x3f
    #define BYTE_EN_START_MASK	0x0f
    #define BYTE_EN_END_MASK	0xf0
    
    #define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + VLAN_HLEN)
    #define RTL8152_TX_TIMEOUT	(HZ)
    
    /* rtl8152 flags */
    enum rtl8152_flags {
    	RTL8152_UNPLUG = 0,
    	RX_URB_FAIL,
    	RTL8152_SET_RX_MODE,
    	WORK_ENABLE
    };
    
    /* Define these values to match your device */
    #define VENDOR_ID_REALTEK		0x0bda
    #define PRODUCT_ID_RTL8152		0x8152
    
    #define MCU_TYPE_PLA			0x0100
    #define MCU_TYPE_USB			0x0000
    
    struct rx_desc {
    	u32 opts1;
    #define RX_LEN_MASK			0x7fff
    	u32 opts2;
    	u32 opts3;
    	u32 opts4;
    	u32 opts5;
    	u32 opts6;
    };
    
    struct tx_desc {
    	u32 opts1;
    #define TX_FS			(1 << 31) /* First segment of a packet */
    #define TX_LS			(1 << 30) /* Final segment of a packet */
    #define TX_LEN_MASK		0xffff
    	u32 opts2;
    };
    
    struct r8152 {
    	unsigned long flags;
    	struct usb_device *udev;
    	struct tasklet_struct tl;
    	struct net_device *netdev;
    	struct urb *rx_urb, *tx_urb;
    	struct sk_buff *tx_skb, *rx_skb;
    	struct delayed_work schedule;
    	struct mii_if_info mii;
    	u32 msg_enable;
    	u16 ocp_base;
    	u8 version;
    	u8 speed;
    };
    
    enum rtl_version {
    	RTL_VER_UNKNOWN = 0,
    	RTL_VER_01,
    	RTL_VER_02
    };
    
    /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
     * The RTL chips use a 64 element hash table based on the Ethernet CRC.
     */
    static const int multicast_filter_limit = 32;
    
    static
    int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
    {
    	return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
    			       RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
    			       value, index, data, size, 500);
    }
    
    static
    int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
    {
    	return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
    			       RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
    			       value, index, data, size, 500);
    }
    
    static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
    				void *data, u16 type)
    {
    	u16	limit = 64;
    	int	ret = 0;
    
    	if (test_bit(RTL8152_UNPLUG, &tp->flags))
    		return -ENODEV;
    
    	/* both size and indix must be 4 bytes align */
    	if ((size & 3) || !size || (index & 3) || !data)
    		return -EPERM;
    
    	if ((u32)index + (u32)size > 0xffff)
    		return -EPERM;
    
    	while (size) {
    		if (size > limit) {
    			ret = get_registers(tp, index, type, limit, data);
    			if (ret < 0)
    				break;
    
    			index += limit;
    			data += limit;
    			size -= limit;
    		} else {
    			ret = get_registers(tp, index, type, size, data);
    			if (ret < 0)
    				break;
    
    			index += size;
    			data += size;
    			size = 0;
    			break;
    		}
    	}
    
    	return ret;
    }
    
    static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
    				u16 size, void *data, u16 type)
    {
    	int	ret;
    	u16	byteen_start, byteen_end, byen;
    	u16	limit = 512;
    
    	if (test_bit(RTL8152_UNPLUG, &tp->flags))
    		return -ENODEV;
    
    	/* both size and indix must be 4 bytes align */
    	if ((size & 3) || !size || (index & 3) || !data)
    		return -EPERM;
    
    	if ((u32)index + (u32)size > 0xffff)
    		return -EPERM;
    
    	byteen_start = byteen & BYTE_EN_START_MASK;
    	byteen_end = byteen & BYTE_EN_END_MASK;
    
    	byen = byteen_start | (byteen_start << 4);
    	ret = set_registers(tp, index, type | byen, 4, data);
    	if (ret < 0)
    		goto error1;
    
    	index += 4;
    	data += 4;
    	size -= 4;
    
    	if (size) {
    		size -= 4;
    
    		while (size) {
    			if (size > limit) {
    				ret = set_registers(tp, index,
    					type | BYTE_EN_DWORD,
    					limit, data);
    				if (ret < 0)
    					goto error1;
    
    				index += limit;
    				data += limit;
    				size -= limit;
    			} else {
    				ret = set_registers(tp, index,
    					type | BYTE_EN_DWORD,
    					size, data);
    				if (ret < 0)
    					goto error1;
    
    				index += size;
    				data += size;
    				size = 0;
    				break;
    			}
    		}
    
    		byen = byteen_end | (byteen_end >> 4);
    		ret = set_registers(tp, index, type | byen, 4, data);
    		if (ret < 0)
    			goto error1;
    	}
    
    error1:
    	return ret;
    }
    
    static inline
    int pla_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
    {
    	return generic_ocp_read(tp, index, size, data, MCU_TYPE_PLA);
    }
    
    static inline
    int pla_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
    {
    	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_PLA);
    }
    
    static inline
    int usb_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data)
    {
    	return generic_ocp_read(tp, index, size, data, MCU_TYPE_USB);
    }
    
    static inline
    int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
    {
    	return generic_ocp_write(tp, index, byteen, size, data, MCU_TYPE_USB);
    }
    
    static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
    {
    	u32 data;
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_read(tp, index, sizeof(data), &data);
    	else
    		usb_ocp_read(tp, index, sizeof(data), &data);
    
    	return __le32_to_cpu(data);
    }
    
    static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
    {
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
    	else
    		usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
    }
    
    static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
    {
    	u32 data;
    	u8 shift = index & 2;
    
    	index &= ~3;
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_read(tp, index, sizeof(data), &data);
    	else
    		usb_ocp_read(tp, index, sizeof(data), &data);
    
    	data = __le32_to_cpu(data);
    	data >>= (shift * 8);
    	data &= 0xffff;
    
    	return (u16)data;
    }
    
    static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
    {
    	u32 tmp, mask = 0xffff;
    	u16 byen = BYTE_EN_WORD;
    	u8 shift = index & 2;
    
    	data &= mask;
    
    	if (index & 2) {
    		byen <<= shift;
    		mask <<= (shift * 8);
    		data <<= (shift * 8);
    		index &= ~3;
    	}
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_read(tp, index, sizeof(tmp), &tmp);
    	else
    		usb_ocp_read(tp, index, sizeof(tmp), &tmp);
    
    	tmp = __le32_to_cpu(tmp) & ~mask;
    	tmp |= data;
    	tmp = __cpu_to_le32(tmp);
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
    	else
    		usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
    }
    
    static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
    {
    	u32 data;
    	u8 shift = index & 3;
    
    	index &= ~3;
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_read(tp, index, sizeof(data), &data);
    	else
    		usb_ocp_read(tp, index, sizeof(data), &data);
    
    	data = __le32_to_cpu(data);
    	data >>= (shift * 8);
    	data &= 0xff;
    
    	return (u8)data;
    }
    
    static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
    {
    	u32 tmp, mask = 0xff;
    	u16 byen = BYTE_EN_BYTE;
    	u8 shift = index & 3;
    
    	data &= mask;
    
    	if (index & 3) {
    		byen <<= shift;
    		mask <<= (shift * 8);
    		data <<= (shift * 8);
    		index &= ~3;
    	}
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_read(tp, index, sizeof(tmp), &tmp);
    	else
    		usb_ocp_read(tp, index, sizeof(tmp), &tmp);
    
    	tmp = __le32_to_cpu(tmp) & ~mask;
    	tmp |= data;
    	tmp = __cpu_to_le32(tmp);
    
    	if (type == MCU_TYPE_PLA)
    		pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
    	else
    		usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
    }
    
    static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
    {
    	u32	ocp_data;
    	int	i;
    
    	ocp_data = PHYAR_FLAG | ((reg_addr & 0x1f) << 16) |
    		   (value & 0xffff);
    
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_PHYAR, ocp_data);
    
    	for (i = 20; i > 0; i--) {
    		udelay(25);
    		ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_PHYAR);
    		if (!(ocp_data & PHYAR_FLAG))
    			break;
    	}
    	udelay(20);
    }
    
    static int r8152_mdio_read(struct r8152 *tp, u32 reg_addr)
    {
    	u32	ocp_data;
    	int	i;
    
    	ocp_data = (reg_addr & 0x1f) << 16;
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_PHYAR, ocp_data);
    
    	for (i = 20; i > 0; i--) {
    		udelay(25);
    		ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_PHYAR);
    		if (ocp_data & PHYAR_FLAG)
    			break;
    	}
    	udelay(20);
    
    	if (!(ocp_data & PHYAR_FLAG))
    		return -EAGAIN;
    
    	return (u16)(ocp_data & 0xffff);
    }
    
    static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    
    	if (phy_id != R8152_PHY_ID)
    		return -EINVAL;
    
    	return r8152_mdio_read(tp, reg);
    }
    
    static
    void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    
    	if (phy_id != R8152_PHY_ID)
    		return;
    
    	r8152_mdio_write(tp, reg, val);
    }
    
    static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
    {
    	u16 ocp_base, ocp_index;
    
    	ocp_base = addr & 0xf000;
    	if (ocp_base != tp->ocp_base) {
    		ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
    		tp->ocp_base = ocp_base;
    	}
    
    	ocp_index = (addr & 0x0fff) | 0xb000;
    	ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
    }
    
    
    //added by ZWQ in 20181106
    extern int sunxi_get_soc_chipid(u8 *chipid);//16 字节
    
    static int rtl8152_set_mac_address(struct net_device *netdev, void *p);
    static inline void set_ethernet_addr(struct r8152 *tp)
    {
    	#if 0
    	struct net_device *dev = tp->netdev;
    	u8 *node_id;
    
    	node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
    	if (!node_id) {
    		netif_err(tp, probe, dev, "out of memory");
    		return;
    	}
    
    	if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
    		netif_notice(tp, probe, dev, "inet addr fail\n");
    	else {
    		memcpy(dev->dev_addr, node_id, dev->addr_len);
    		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
    	}
    	kfree(node_id);
    	#else //--------------------------------------------------
    	
    	struct net_device *dev = tp->netdev;
    	struct sockaddr sa;
    	int ret;
    	unsigned char chipid[16];//ZWQ 芯片ID号
    	int ii =0 ;
    
    	if (tp->version == RTL_VER_01)
    		ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
    	else
    		ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
    
    	if (ret < 0) {
    		netif_err(tp, probe, dev, "ether addr fail\n");
    	} else if (!is_valid_ether_addr(sa.sa_data)) {
    		netif_warn(tp, probe, dev, "Invalid ether addr\n");
    		eth_hw_addr_random(dev);
    		memcpy(sa.sa_data, dev->dev_addr, ETH_ALEN);
    		memset(chipid,0,16);
    		sunxi_get_soc_chipid(chipid);
    		//04:7d:7b:b8:ee:be  例如这6个字节
    		 memcpy( dev->dev_addr,&chipid[10], ETH_ALEN);
    		 memcpy(sa.sa_data, dev->dev_addr, ETH_ALEN);//unsigned char dev_addr[MAX_ADDR_LEN] ETH_ALEN = 6
    		rtl8152_set_mac_address(dev, &sa);
    	} else {
    		if (tp->version == RTL_VER_01)
    			memcpy(dev->dev_addr, sa.sa_data, ETH_ALEN);
    		else
    			ret = rtl8152_set_mac_address(dev, &sa);
    
    		#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
    		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
    		#endif
    	}
    	#endif
    }
    
    static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	struct sockaddr *addr = p;
    
    	if (!is_valid_ether_addr(addr->sa_data))
    		return -EADDRNOTAVAIL;
    
    	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
    
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
    	pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, 8, addr->sa_data);
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
    
    	return 0;
    }
    
    static int alloc_all_urbs(struct r8152 *tp)
    {
    	tp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
    	if (!tp->rx_urb)
    		return 0;
    	tp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
    	if (!tp->tx_urb) {
    		usb_free_urb(tp->rx_urb);
    		return 0;
    	}
    
    	return 1;
    }
    
    static void free_all_urbs(struct r8152 *tp)
    {
    	usb_free_urb(tp->rx_urb);
    	usb_free_urb(tp->tx_urb);
    }
    
    static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
    {
    	return &dev->stats;
    }
    
    static void read_bulk_callback(struct urb *urb)
    {
    	struct r8152 *tp;
    	unsigned pkt_len;
    	struct sk_buff *skb;
    	struct net_device *netdev;
    	struct net_device_stats *stats;
    	int status = urb->status;
    	int result;
    	struct rx_desc *rx_desc;
    
    	tp = urb->context;
    	if (!tp)
    		return;
    	if (test_bit(RTL8152_UNPLUG, &tp->flags))
    		return;
    	netdev = tp->netdev;
    	if (!netif_device_present(netdev))
    		return;
    
    	stats = rtl8152_get_stats(netdev);
    	switch (status) {
    	case 0:
    		break;
    	case -ESHUTDOWN:
    		set_bit(RTL8152_UNPLUG, &tp->flags);
    		netif_device_detach(tp->netdev);
    	case -ENOENT:
    		return;	/* the urb is in unlink state */
    	case -ETIME:
    		pr_warn_ratelimited("may be reset is needed?..\n");
    		goto goon;
    	default:
    		pr_warn_ratelimited("Rx status %d\n", status);
    		goto goon;
    	}
    
    	/* protect against short packets (tell me why we got some?!?) */
    	if (urb->actual_length < sizeof(*rx_desc))
    		goto goon;
    
    
    	rx_desc = (struct rx_desc *)urb->transfer_buffer;
    	pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
    	if (urb->actual_length < sizeof(struct rx_desc) + pkt_len)
    		goto goon;
    
    	skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
    	if (!skb)
    		goto goon;
    
    	memcpy(skb->data, tp->rx_skb->data + sizeof(struct rx_desc), pkt_len);
    	skb_put(skb, pkt_len);
    	skb->protocol = eth_type_trans(skb, netdev);
    	netif_rx(skb);
    	stats->rx_packets++;
    	stats->rx_bytes += pkt_len;
    goon:
    	usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
    		      tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc),
    		      (usb_complete_t)read_bulk_callback, tp);
    	result = usb_submit_urb(tp->rx_urb, GFP_ATOMIC);
    	if (result == -ENODEV) {
    		netif_device_detach(tp->netdev);
    	} else if (result) {
    		set_bit(RX_URB_FAIL, &tp->flags);
    		goto resched;
    	} else {
    		clear_bit(RX_URB_FAIL, &tp->flags);
    	}
    
    	return;
    resched:
    	tasklet_schedule(&tp->tl);
    }
    
    static void rx_fixup(unsigned long data)
    {
    	struct r8152 *tp;
    	int status;
    
    	tp = (struct r8152 *)data;
    	if (!test_bit(WORK_ENABLE, &tp->flags))
    		return;
    
    	status = usb_submit_urb(tp->rx_urb, GFP_ATOMIC);
    	if (status == -ENODEV) {
    		netif_device_detach(tp->netdev);
    	} else if (status) {
    		set_bit(RX_URB_FAIL, &tp->flags);
    		goto tlsched;
    	} else {
    		clear_bit(RX_URB_FAIL, &tp->flags);
    	}
    
    	return;
    tlsched:
    	tasklet_schedule(&tp->tl);
    }
    
    static void write_bulk_callback(struct urb *urb)
    {
    	struct r8152 *tp;
    	int status = urb->status;
    
    	tp = urb->context;
    	if (!tp)
    		return;
    	dev_kfree_skb_irq(tp->tx_skb);
    	if (!netif_device_present(tp->netdev))
    		return;
    	if (status)
    		dev_info(&urb->dev->dev, "%s: Tx status %d\n",
    			 tp->netdev->name, status);
    	tp->netdev->trans_start = jiffies;
    	netif_wake_queue(tp->netdev);
    }
    
    static void rtl8152_tx_timeout(struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	struct net_device_stats *stats = rtl8152_get_stats(netdev);
    	netif_warn(tp, tx_err, netdev, "Tx timeout.\n");
    	usb_unlink_urb(tp->tx_urb);
    	stats->tx_errors++;
    }
    
    static void rtl8152_set_rx_mode(struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    
    	if (tp->speed & LINK_STATUS)
    		set_bit(RTL8152_SET_RX_MODE, &tp->flags);
    }
    
    static void _rtl8152_set_rx_mode(struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	u32 tmp, *mc_filter;	/* Multicast hash filter */
    	u32 ocp_data;
    
    	mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
    	if (!mc_filter) {
    		netif_err(tp, link, netdev, "out of memory");
    		return;
    	}
    
    	clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
    	netif_stop_queue(netdev);
    	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
    	ocp_data &= ~RCR_ACPT_ALL;
    	ocp_data |= RCR_AB | RCR_APM;
    
    	if (netdev->flags & IFF_PROMISC) {
    		/* Unconditionally log net taps. */
    		netif_notice(tp, link, netdev, "Promiscuous mode enabled\n");
    		ocp_data |= RCR_AM | RCR_AAP;
    		mc_filter[1] = mc_filter[0] = 0xffffffff;
    	} else if ((netdev_mc_count(netdev) > multicast_filter_limit) ||
    		   (netdev->flags & IFF_ALLMULTI)) {
    		/* Too many to filter perfectly -- accept all multicasts. */
    		ocp_data |= RCR_AM;
    		mc_filter[1] = mc_filter[0] = 0xffffffff;
    	} else {
    		struct netdev_hw_addr *ha;
    
    		mc_filter[1] = mc_filter[0] = 0;
    		netdev_for_each_mc_addr(ha, netdev) {
    			int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
    			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
    			ocp_data |= RCR_AM;
    		}
    	}
    
    	tmp = mc_filter[0];
    	mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1]));
    	mc_filter[1] = __cpu_to_le32(swab32(tmp));
    
    	pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
    	netif_wake_queue(netdev);
    	kfree(mc_filter);
    }
    
    static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
    					    struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	struct net_device_stats *stats = rtl8152_get_stats(netdev);
    	struct tx_desc *tx_desc;
    	int len, res;
    
    	netif_stop_queue(netdev);
    	len = skb->len;
    	if (skb_header_cloned(skb) || skb_headroom(skb) < sizeof(*tx_desc)) {
    		struct sk_buff *tx_skb;
    
    		tx_skb = skb_copy_expand(skb, sizeof(*tx_desc), 0, GFP_ATOMIC);
    		dev_kfree_skb_any(skb);
    		if (!tx_skb) {
    			stats->tx_dropped++;
    			netif_wake_queue(netdev);
    			return NETDEV_TX_OK;
    		}
    		skb = tx_skb;
    	}
    	tx_desc = (struct tx_desc *)skb_push(skb, sizeof(*tx_desc));
    	memset(tx_desc, 0, sizeof(*tx_desc));
    	tx_desc->opts1 = cpu_to_le32((len & TX_LEN_MASK) | TX_FS | TX_LS);
    	tp->tx_skb = skb;
    	skb_tx_timestamp(skb);
    	usb_fill_bulk_urb(tp->tx_urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
    			  skb->data, skb->len,
    			  (usb_complete_t)write_bulk_callback, tp);
    	res = usb_submit_urb(tp->tx_urb, GFP_ATOMIC);
    	if (res) {
    		/* Can we get/handle EPIPE here? */
    		if (res == -ENODEV) {
    			netif_device_detach(tp->netdev);
    		} else {
    			netif_warn(tp, tx_err, netdev,
    				   "failed tx_urb %d\n", res);
    			stats->tx_errors++;
    			netif_start_queue(netdev);
    		}
    	} else {
    		stats->tx_packets++;
    		stats->tx_bytes += skb->len;
    	}
    
    	return NETDEV_TX_OK;
    }
    
    static void r8152b_reset_packet_filter(struct r8152 *tp)
    {
    	u32	ocp_data;
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_FMC);
    	ocp_data &= ~FMC_FCR_MCU_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
    	ocp_data |= FMC_FCR_MCU_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_FMC, ocp_data);
    }
    
    static void rtl8152_nic_reset(struct r8152 *tp)
    {
    	int	i;
    
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, CR_RST);
    
    	for (i = 0; i < 1000; i++) {
    		if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
    			break;
    		udelay(100);
    	}
    }
    
    static inline u8 rtl8152_get_speed(struct r8152 *tp)
    {
    	return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS);
    }
    
    static int rtl8152_enable(struct r8152 *tp)
    {
    	u32	ocp_data;
    	u8 speed;
    
    	speed = rtl8152_get_speed(tp);
    	if (speed & _100bps) {
    		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
    		ocp_data &= ~EEEP_CR_EEEP_TX;
    		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
    	} else {
    		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
    		ocp_data |= EEEP_CR_EEEP_TX;
    		ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
    	}
    
    	r8152b_reset_packet_filter(tp);
    
    	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR);
    	ocp_data |= CR_RE | CR_TE;
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
    	ocp_data &= ~RXDY_GATED_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
    
    	usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
    		      tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc),
    		      (usb_complete_t)read_bulk_callback, tp);
    
    	return usb_submit_urb(tp->rx_urb, GFP_KERNEL);
    }
    
    static void rtl8152_disable(struct r8152 *tp)
    {
    	u32	ocp_data;
    	int	i;
    
    	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
    	ocp_data &= ~RCR_ACPT_ALL;
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
    
    	usb_kill_urb(tp->tx_urb);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
    	ocp_data |= RXDY_GATED_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
    
    	for (i = 0; i < 1000; i++) {
    		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    		if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
    			break;
    		mdelay(1);
    	}
    
    	for (i = 0; i < 1000; i++) {
    		if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
    			break;
    		mdelay(1);
    	}
    
    	usb_kill_urb(tp->rx_urb);
    
    	rtl8152_nic_reset(tp);
    }
    
    static void r8152b_exit_oob(struct r8152 *tp)
    {
    	u32	ocp_data;
    	int	i;
    
    	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
    	ocp_data &= ~RCR_ACPT_ALL;
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
    	ocp_data |= RXDY_GATED_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
    
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
    
    	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    	ocp_data &= ~NOW_IS_OOB;
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
    	ocp_data &= ~MCU_BORW_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
    
    	for (i = 0; i < 1000; i++) {
    		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    		if (ocp_data & LINK_LIST_READY)
    			break;
    		mdelay(1);
    	}
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
    	ocp_data |= RE_INIT_LL;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
    
    	for (i = 0; i < 1000; i++) {
    		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    		if (ocp_data & LINK_LIST_READY)
    			break;
    		mdelay(1);
    	}
    
    	rtl8152_nic_reset(tp);
    
    	/* rx share fifo credit full threshold */
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_DEV_STAT);
    	ocp_data &= STAT_SPEED_MASK;
    	if (ocp_data == STAT_SPEED_FULL) {
    		/* rx share fifo credit near full threshold */
    		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
    				RXFIFO_THR2_FULL);
    		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
    				RXFIFO_THR3_FULL);
    	} else {
    		/* rx share fifo credit near full threshold */
    		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
    				RXFIFO_THR2_HIGH);
    		ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
    				RXFIFO_THR3_HIGH);
    	}
    
    	/* TX share fifo free credit full threshold */
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
    
    	ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_BUF_THR);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
    			TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
    	ocp_data &= ~CPCR_RX_VLAN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
    
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0);
    	ocp_data |= TCR0_AUTO_FIFO;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
    }
    
    static void r8152b_enter_oob(struct r8152 *tp)
    {
    	u32	ocp_data;
    	int	i;
    
    	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    	ocp_data &= ~NOW_IS_OOB;
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
    
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
    
    	rtl8152_disable(tp);
    
    	for (i = 0; i < 1000; i++) {
    		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    		if (ocp_data & LINK_LIST_READY)
    			break;
    		mdelay(1);
    	}
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
    	ocp_data |= RE_INIT_LL;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
    
    	for (i = 0; i < 1000; i++) {
    		ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    		if (ocp_data & LINK_LIST_READY)
    			break;
    		mdelay(1);
    	}
    
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
    	ocp_data |= MAGIC_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
    	ocp_data |= CPCR_RX_VLAN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR);
    	ocp_data |= ALDPS_PROXY_MODE;
    	ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
    
    	ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
    	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
    
    	ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
    	ocp_data &= ~RXDY_GATED_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
    
    	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
    	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
    }
    
    static void r8152b_disable_aldps(struct r8152 *tp)
    {
    	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
    	msleep(20);
    }
    
    static inline void r8152b_enable_aldps(struct r8152 *tp)
    {
    	ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
    					    LINKENA | DIS_SDSAVE);
    }
    
    static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
    {
    	u16 bmcr, anar;
    	int ret = 0;
    
    	cancel_delayed_work_sync(&tp->schedule);
    	anar = r8152_mdio_read(tp, MII_ADVERTISE);
    	anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
    		  ADVERTISE_100HALF | ADVERTISE_100FULL);
    
    	if (autoneg == AUTONEG_DISABLE) {
    		if (speed == SPEED_10) {
    			bmcr = 0;
    			anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
    		} else if (speed == SPEED_100) {
    			bmcr = BMCR_SPEED100;
    			anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
    		} else {
    			ret = -EINVAL;
    			goto out;
    		}
    
    		if (duplex == DUPLEX_FULL)
    			bmcr |= BMCR_FULLDPLX;
    	} else {
    		if (speed == SPEED_10) {
    			if (duplex == DUPLEX_FULL)
    				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
    			else
    				anar |= ADVERTISE_10HALF;
    		} else if (speed == SPEED_100) {
    			if (duplex == DUPLEX_FULL) {
    				anar |= ADVERTISE_10HALF | ADVERTISE_10FULL;
    				anar |= ADVERTISE_100HALF | ADVERTISE_100FULL;
    			} else {
    				anar |= ADVERTISE_10HALF;
    				anar |= ADVERTISE_100HALF;
    			}
    		} else {
    			ret = -EINVAL;
    			goto out;
    		}
    
    		bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
    	}
    
    	r8152_mdio_write(tp, MII_ADVERTISE, anar);
    	r8152_mdio_write(tp, MII_BMCR, bmcr);
    
    out:
    	schedule_delayed_work(&tp->schedule, 5 * HZ);
    
    	return ret;
    }
    
    static void rtl8152_down(struct r8152 *tp)
    {
    	u32	ocp_data;
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
    	ocp_data &= ~POWER_CUT;
    	ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
    
    	r8152b_disable_aldps(tp);
    	r8152b_enter_oob(tp);
    	r8152b_enable_aldps(tp);
    }
    
    static void set_carrier(struct r8152 *tp)
    {
    	struct net_device *netdev = tp->netdev;
    	u8 speed;
    
    	speed = rtl8152_get_speed(tp);
    
    	if (speed & LINK_STATUS) {
    		if (!(tp->speed & LINK_STATUS)) {
    			rtl8152_enable(tp);
    			set_bit(RTL8152_SET_RX_MODE, &tp->flags);
    			netif_carrier_on(netdev);
    		}
    	} else {
    		if (tp->speed & LINK_STATUS) {
    			netif_carrier_off(netdev);
    			rtl8152_disable(tp);
    		}
    	}
    	tp->speed = speed;
    }
    
    static void rtl_work_func_t(struct work_struct *work)
    {
    	struct r8152 *tp = container_of(work, struct r8152, schedule.work);
    
    	if (!test_bit(WORK_ENABLE, &tp->flags))
    		goto out1;
    
    	if (test_bit(RTL8152_UNPLUG, &tp->flags))
    		goto out1;
    
    	set_carrier(tp);
    
    	if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
    		_rtl8152_set_rx_mode(tp->netdev);
    
    	schedule_delayed_work(&tp->schedule, HZ);
    
    out1:
    	return;
    }
    
    static int rtl8152_open(struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	int res = 0;
    
    	tp->speed = rtl8152_get_speed(tp);
    	if (tp->speed & LINK_STATUS) {
    		res = rtl8152_enable(tp);
    		if (res) {
    			if (res == -ENODEV)
    				netif_device_detach(tp->netdev);
    
    			netif_err(tp, ifup, netdev,
    				  "rtl8152_open failed: %d\n", res);
    			return res;
    		}
    
    		netif_carrier_on(netdev);
    	} else {
    		netif_stop_queue(netdev);
    		netif_carrier_off(netdev);
    	}
    
    	rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL);
    	netif_start_queue(netdev);
    	set_bit(WORK_ENABLE, &tp->flags);
    	schedule_delayed_work(&tp->schedule, 0);
    
    	return res;
    }
    
    static int rtl8152_close(struct net_device *netdev)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	int res = 0;
    
    	clear_bit(WORK_ENABLE, &tp->flags);
    	cancel_delayed_work_sync(&tp->schedule);
    	netif_stop_queue(netdev);
    	rtl8152_disable(tp);
    
    	return res;
    }
    
    static void rtl_clear_bp(struct r8152 *tp)
    {
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
    	ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
    	mdelay(3);
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
    	ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
    }
    
    static void r8152b_enable_eee(struct r8152 *tp)
    {
    	u32	ocp_data;
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR);
    	ocp_data |= EEE_RX_EN | EEE_TX_EN;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
    	ocp_reg_write(tp, OCP_EEE_CONFIG1, RG_TXLPI_MSK_HFDUP | RG_MATCLR_EN |
    					   EEE_10_CAP | EEE_NWAY_EN |
    					   TX_QUIET_EN | RX_QUIET_EN |
    					   SDRISETIME | RG_RXLPI_MSK_HFDUP |
    					   SDFALLTIME);
    	ocp_reg_write(tp, OCP_EEE_CONFIG2, RG_LPIHYS_NUM | RG_DACQUIET_EN |
    					   RG_LDVQUIET_EN | RG_CKRSEL |
    					   RG_EEEPRG_EN);
    	ocp_reg_write(tp, OCP_EEE_CONFIG3, FST_SNR_EYE_R | RG_LFS_SEL | MSK_PH);
    	ocp_reg_write(tp, OCP_EEE_AR, FUN_ADDR | DEVICE_ADDR);
    	ocp_reg_write(tp, OCP_EEE_DATA, EEE_ADDR);
    	ocp_reg_write(tp, OCP_EEE_AR, FUN_DATA | DEVICE_ADDR);
    	ocp_reg_write(tp, OCP_EEE_DATA, EEE_DATA);
    	ocp_reg_write(tp, OCP_EEE_AR, 0x0000);
    }
    
    static void r8152b_enable_fc(struct r8152 *tp)
    {
    	u16 anar;
    
    	anar = r8152_mdio_read(tp, MII_ADVERTISE);
    	anar |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
    	r8152_mdio_write(tp, MII_ADVERTISE, anar);
    }
    
    static void r8152b_hw_phy_cfg(struct r8152 *tp)
    {
    	r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
    	r8152b_disable_aldps(tp);
    }
    
    static void r8152b_init(struct r8152 *tp)
    {
    	u32	ocp_data;
    	int	i;
    
    	rtl_clear_bp(tp);
    
    	if (tp->version == RTL_VER_01) {
    		ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
    		ocp_data &= ~LED_MODE_MASK;
    		ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
    	}
    
    	r8152b_hw_phy_cfg(tp);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
    	ocp_data &= ~POWER_CUT;
    	ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
    	ocp_data &= ~RWSUME_INDICATE;
    	ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
    
    	r8152b_exit_oob(tp);
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
    	ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
    	ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
    	ocp_data &= ~MCU_CLK_RATIO_MASK;
    	ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
    	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
    	ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
    		   SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
    	ocp_write_word(tp, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
    
    	r8152b_enable_eee(tp);
    	r8152b_enable_aldps(tp);
    	r8152b_enable_fc(tp);
    
    	r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
    				       BMCR_ANRESTART);
    	for (i = 0; i < 100; i++) {
    		udelay(100);
    		if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET))
    			break;
    	}
    
    	/* disable rx aggregation */
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
    	ocp_data |= RX_AGG_DISABLE;
    	ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
    }
    
    static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
    {
    	struct r8152 *tp = usb_get_intfdata(intf);
    
    	netif_device_detach(tp->netdev);
    
    	if (netif_running(tp->netdev)) {
    		clear_bit(WORK_ENABLE, &tp->flags);
    		cancel_delayed_work_sync(&tp->schedule);
    	}
    
    	rtl8152_down(tp);
    
    	return 0;
    }
    
    static int rtl8152_resume(struct usb_interface *intf)
    {
    	struct r8152 *tp = usb_get_intfdata(intf);
    
    	r8152b_init(tp);
    	netif_device_attach(tp->netdev);
    	if (netif_running(tp->netdev)) {
    		rtl8152_enable(tp);
    		set_bit(WORK_ENABLE, &tp->flags);
    		set_bit(RTL8152_SET_RX_MODE, &tp->flags);
    		schedule_delayed_work(&tp->schedule, 0);
    	}
    
    	return 0;
    }
    
    static void rtl8152_get_drvinfo(struct net_device *netdev,
    				struct ethtool_drvinfo *info)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    
    	strncpy(info->driver, MODULENAME, ETHTOOL_BUSINFO_LEN);
    	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
    	usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
    }
    
    static
    int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    
    	if (!tp->mii.mdio_read)
    		return -EOPNOTSUPP;
    
    	return mii_ethtool_gset(&tp->mii, cmd);
    }
    
    static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
    {
    	struct r8152 *tp = netdev_priv(dev);
    
    	return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
    }
    
    static struct ethtool_ops ops = {
    	.get_drvinfo = rtl8152_get_drvinfo,
    	.get_settings = rtl8152_get_settings,
    	.set_settings = rtl8152_set_settings,
    	.get_link = ethtool_op_get_link,
    };
    
    static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
    {
    	struct r8152 *tp = netdev_priv(netdev);
    	struct mii_ioctl_data *data = if_mii(rq);
    	int res = 0;
    
    	switch (cmd) {
    	case SIOCGMIIPHY:
    		data->phy_id = R8152_PHY_ID; /* Internal PHY */
    		break;
    
    	case SIOCGMIIREG:
    		data->val_out = r8152_mdio_read(tp, data->reg_num);
    		break;
    
    	case SIOCSMIIREG:
    		if (!capable(CAP_NET_ADMIN)) {
    			res = -EPERM;
    			break;
    		}
    		r8152_mdio_write(tp, data->reg_num, data->val_in);
    		break;
    
    	default:
    		res = -EOPNOTSUPP;
    	}
    
    	return res;
    }
    
    static const struct net_device_ops rtl8152_netdev_ops = {
    	.ndo_open		= rtl8152_open,
    	.ndo_stop		= rtl8152_close,
    	.ndo_do_ioctl		= rtl8152_ioctl,
    	.ndo_start_xmit		= rtl8152_start_xmit,
    	.ndo_tx_timeout		= rtl8152_tx_timeout,
    	.ndo_set_rx_mode	= rtl8152_set_rx_mode,
    	.ndo_set_mac_address	= rtl8152_set_mac_address,
    
    	.ndo_change_mtu		= eth_change_mtu,
    	.ndo_validate_addr	= eth_validate_addr,
    };
    
    static void r8152b_get_version(struct r8152 *tp)
    {
    	u32	ocp_data;
    	u16	version;
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1);
    	version = (u16)(ocp_data & VERSION_MASK);
    
    	switch (version) {
    	case 0x4c00:
    		tp->version = RTL_VER_01;
    		break;
    	case 0x4c10:
    		tp->version = RTL_VER_02;
    		break;
    	default:
    		netif_info(tp, probe, tp->netdev,
    			   "Unknown version 0x%04x\n", version);
    		break;
    	}
    }
    
    static int rtl8152_probe(struct usb_interface *intf,
    			 const struct usb_device_id *id)
    {
    	struct usb_device *udev = interface_to_usbdev(intf);
    	struct r8152 *tp;
    	struct net_device *netdev;
    
    	if (udev->actconfig->desc.bConfigurationValue != 1) {
    		usb_driver_set_configuration(udev, 1);
    		return -ENODEV;
    	}
    
    	netdev = alloc_etherdev(sizeof(struct r8152));
    	if (!netdev) {
    		dev_err(&intf->dev, "Out of memory");
    		return -ENOMEM;
    	}
    
    	tp = netdev_priv(netdev);
    	tp->msg_enable = 0x7FFF;
    
    	tasklet_init(&tp->tl, rx_fixup, (unsigned long)tp);
    	INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
    
    	tp->udev = udev;
    	tp->netdev = netdev;
    	netdev->netdev_ops = &rtl8152_netdev_ops;
    	netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
    	netdev->features &= ~NETIF_F_IP_CSUM;
    	SET_ETHTOOL_OPS(netdev, &ops);
    	tp->speed = 0;
    
    	tp->mii.dev = netdev;
    	tp->mii.mdio_read = read_mii_word;
    	tp->mii.mdio_write = write_mii_word;
    	tp->mii.phy_id_mask = 0x3f;
    	tp->mii.reg_num_mask = 0x1f;
    	tp->mii.phy_id = R8152_PHY_ID;
    	tp->mii.supports_gmii = 0;
    
    	r8152b_get_version(tp);
    	r8152b_init(tp);
    	set_ethernet_addr(tp);
    
    	if (!alloc_all_urbs(tp)) {
    		netif_err(tp, probe, netdev, "out of memory");
    		goto out;
    	}
    
    	tp->rx_skb = netdev_alloc_skb(netdev,
    			RTL8152_RMS + sizeof(struct rx_desc));
    	if (!tp->rx_skb)
    		goto out1;
    
    	usb_set_intfdata(intf, tp);
    	SET_NETDEV_DEV(netdev, &intf->dev);
    
    
    	if (register_netdev(netdev) != 0) {
    		netif_err(tp, probe, netdev, "couldn't register the device");
    		goto out2;
    	}
    
    	netif_info(tp, probe, netdev, "%s", DRIVER_VERSION);
    
    	return 0;
    
    out2:
    	usb_set_intfdata(intf, NULL);
    	dev_kfree_skb(tp->rx_skb);
    out1:
    	free_all_urbs(tp);
    out:
    	free_netdev(netdev);
    	return -EIO;
    }
    
    static void rtl8152_unload(struct r8152 *tp)
    {
    	u32	ocp_data;
    
    	if (tp->version != RTL_VER_01) {
    		ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
    		ocp_data |= POWER_CUT;
    		ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
    	}
    
    	ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
    	ocp_data &= ~RWSUME_INDICATE;
    	ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
    }
    
    static void rtl8152_disconnect(struct usb_interface *intf)
    {
    	struct r8152 *tp = usb_get_intfdata(intf);
    
    	usb_set_intfdata(intf, NULL);
    	if (tp) {
    		set_bit(RTL8152_UNPLUG, &tp->flags);
    		tasklet_kill(&tp->tl);
    		unregister_netdev(tp->netdev);
    		rtl8152_unload(tp);
    		free_all_urbs(tp);
    		if (tp->rx_skb)
    			dev_kfree_skb(tp->rx_skb);
    		free_netdev(tp->netdev);
    	}
    }
    
    /* table of devices that work with this driver */
    static struct usb_device_id rtl8152_table[] = {
    	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
    	{}
    };
    
    MODULE_DEVICE_TABLE(usb, rtl8152_table);
    
    static struct usb_driver rtl8152_driver = {
    	.name =		MODULENAME,
    	.probe =	rtl8152_probe,
    	.disconnect =	rtl8152_disconnect,
    	.id_table =	rtl8152_table,
    	.suspend =	rtl8152_suspend,
    	.resume =	rtl8152_resume
    };
    
    static int __init usb_rtl8152_init(void)
    {
    	return usb_register(&rtl8152_driver);
    }
    
    static void __exit usb_rtl8152_exit(void)
    {
    	usb_deregister(&rtl8152_driver);
    }
    
    module_init(usb_rtl8152_init);
    module_exit(usb_rtl8152_exit);
    
    MODULE_AUTHOR(DRIVER_AUTHOR);
    MODULE_DESCRIPTION(DRIVER_DESC);
    MODULE_LICENSE("GPL");
    
    
    1. 内核配置
      在这里插入图片描述

    驱动加载顺序在这里插入图片描述

    展开全文
  • 没有任何的Wi-Fi和3G无线网卡情况下,通过有线网络(以太网)也可以上网,用户还可以通过有线网络... 最近接到许多客户需要增加以太网功能,所以在网上搜集了一下相关USB网卡资讯:发现有几款USB转以太网的芯片可供选
  • mac安装绿联USB转以太网驱动

    万次阅读 2016-08-22 10:51:29
    本文介绍绿联USB外置网卡在mac OSX苹果中文系统系统驱动安装流程。 苹果系统无光驱,您可从绿联官网下载或用其他电脑拷贝出驱动盘里的安装文件夹,即可进行安装。 第一步:打开驱动文件夹,打开m
  • AX88772C USB2.0转以太网转资料合集,包括芯片datasheet,原理图和PCB布局文件
  • SR9900是一款USB2.0接口的100M以太网芯片,超低功耗,采用QFN小封装,广泛应用于电脑周边和嵌入式设计
  • USB2.0转以太网芯片 SR9900原理图资料 5V输入,也可以3.3V直接输入,100M低功耗网卡原理图
  • 亚信电子(ASIX Electronics)近日宣布,其高速USB以太网系列新增一款USB 2.0转以太网控制芯片AX88772B,低功耗、低引脚数、内置封包校验和承载引擎、支持100BASE-FX光纤模式及-40℃~85℃工业规格。AX88772B可满足...
  • 亚信电子(ASIX Electronics)日前宣布,其高速USB以太网系列新增一款USB 2.0转以太网控制芯片 AX88772B,低功耗、低引脚数、内置封包校验和承载引擎、支持100BASE-FX光纤模式及-40℃~85℃工业规格。AX88772B可满足...
  • PCB为四层板,方案设计是基于亚信AX88772C设计,实现USB2.0百兆以太网功能,支持windows,wince,linux系统,已完成小批量生产,性能稳定,不丢包
  • USB2.0千兆以太网方案芯片, AX88178A datasheet。
  • 测试可用,使用cadence15.7或以上打开,压缩包也有输出pdf,方便查看。
  • USB接口以太网芯片SR9900

    千次阅读 2019-07-31 18:25:29
    SR9900是一个高集成度、超低功耗、单芯片USB 2.010/100M以太网控制电路。为各类应用增加低成本、小型封装、即插即用的快速以太网功能,可用于台式电脑、笔计本电脑、超便携式电脑、平板电脑、托架/端口复制器/扩展...
  • SR9900是一款USB2.0接口的100M以太网控制器芯片,采用QFN24 4*4封装,低功耗,广泛应用于电脑周边,嵌入式系统设计。 附件资料包括(规格书,原理图,windows系统驱动,Linux系统驱动,以及一些设计说明)
  • 嵌入式USB结合以太网技术可以将USB设备转换到TCP/IP,让USB 设备不再受距离限制,可以通过网络随时随地访问USB设备,可以让一个USB设备供多个用户使用,从而提高USB设备的利用率。通过使USB设备具备联网能力的设备...

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 233
精华内容 93
关键字:

usb转以太网