usb转百兆网模块一般采用ax88772
在内核中配置添加该模块:
make menuconfig
使用/搜索
回车之后,按5选择8817
输入?可以看到该驱动支持88系列的usb转百兆芯片,然后将其使能
我们还需要将Simple USB Network Links 使能,该驱动为通用usb转网口驱动
然后保存,编译内核烧写到板子里面
正常插入模块打印信息:
usb 1-1.1: new high-speed USB device number 4 using ci_hdrc ,
asix 1-1.1:1.0 eth1: register 'asix' at usb-ci_hdrc.1-1.1,
ASIX AX88772B USB 2.0 Ethernet, 00:0e:c6:87:72:01,IPv6: ADDRCONF(NETDEV_UP): eth1: link is not ready
使用的是AX88772的驱动,识别到了eth1,但是还有一种情况,使用cdc驱动,识别成了usb0
那么,如果我们还是想用eth1这个名字的话,可以从驱动里面做一些修改
进入对应目录搜索用到的驱动
zero@ubuntu:~/linux-4.1.15/drivers/net/usb$ ls -l *.o
用到了cdc_ether.c驱动,可以看里面的driver结构体,里面用到了usbnet_probe,该函数在usbnet.c里面
static struct usb_driver cdc_driver = {
.name = "cdc_ether",
.id_table = products,
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
.disable_hub_initiated_lpm = 1,
};
可以到probe函数里面有很多代码,我们不做详细解读,只关注名字相关代码,往下看
usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
{
struct usbnet *dev;
struct net_device *net;
struct usb_host_interface *interface;
struct driver_info *info;
struct usb_device *xdev;
int status;
const char *name;
struct usb_driver *driver = to_usb_driver(udev->dev.driver);
/* usbnet already took usb runtime pm, so have to enable the feature
\* for usb interface, otherwise usb_autopm_get_interface may return
\* failure if RUNTIME_PM is enabled.
*/
if (!driver->supports_autosuspend) {
driver->supports_autosuspend = 1;
pm_runtime_enable(&udev->dev);
}
name = udev->dev.driver->name;
info = (struct driver_info *) prod->driver_info;
if (!info) {
dev_dbg (&udev->dev, "blacklisted by %s\n", name);
return -ENODEV;
}
xdev = interface_to_usbdev (udev);
interface = udev->cur_altsetting;
status = -ENOMEM;
// set up our own records
net = alloc_etherdev(sizeof(*dev));
if (!net)
goto out;
/* netdev_printk() needs this so do it as early as possible */
SET_NETDEV_DEV(net, &udev->dev);
dev = netdev_priv(net);
dev->udev = xdev;
dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
init_waitqueue_head(&dev->wait);
skb_queue_head_init (&dev->rxq);
skb_queue_head_init (&dev->txq);
skb_queue_head_init (&dev->done);
skb_queue_head_init(&dev->rxq_pause);
dev->bh.func = usbnet_bh;
dev->bh.data = (unsigned long) dev;
INIT_WORK (&dev->kevent, usbnet_deferred_kevent);
init_usb_anchor(&dev->deferred);
dev->delay.function = usbnet_bh;
dev->delay.data = (unsigned long) dev;
init_timer (&dev->delay);
mutex_init (&dev->phy_mutex);
mutex_init(&dev->interrupt_mutex);
dev->interrupt_count = 0;
dev->net = net;
strcpy (net->name, "usb%d");
memcpy (net->dev_addr, node_id, sizeof node_id);
/* rx and tx sides can use different message sizes;
\* bind() should set rx_urb_size in that case.
*/
dev->hard_mtu = net->mtu + net->hard_header_len;
\#if 0
// dma_supported() is deeply broken on almost all architectures
// possible with some EHCI controllers
if (dma_supported (&udev->dev, DMA_BIT_MASK(64)))
net->features |= NETIF_F_HIGHDMA;
\#endif
net->netdev_ops = &usbnet_netdev_ops;
net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
net->ethtool_ops = &usbnet_ethtool_ops;
// allow device-specific bind/init procedures
// NOTE net->name still not usable ...
if (info->bind) {
status = info->bind (dev, udev);
if (status < 0)
goto out1;
// heuristic: "usb%d" for links we know are two-host,
// else "eth%d" when there's reasonable doubt. userspace
// can rename the link if it knows better.
if ((dev->driver_info->flags & FLAG_ETHER) != 0 &&
((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 ||
(net->dev_addr [0] & 0x02) == 0))
strcpy (net->name, "eth%d");
/* WLAN devices should always be named "wlan%d" */
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
strcpy(net->name, "wlan%d");
/* WWAN devices should always be named "wwan%d" */
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
strcpy(net->name, "wwan%d");
/* devices that cannot do ARP */
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
/* maybe the remote can't receive an Ethernet MTU */
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
net->mtu = dev->hard_mtu - net->hard_header_len;
} else if (!info->in || !info->out)
status = usbnet_get_endpoints (dev, udev);
else {
dev->in = usb_rcvbulkpipe (xdev, info->in);
dev->out = usb_sndbulkpipe (xdev, info->out);
if (!(info->flags & FLAG_NO_SETINT))
status = usb_set_interface (xdev,
interface->desc.bInterfaceNumber,
interface->desc.bAlternateSetting);
else
status = 0;
}
if (status >= 0 && dev->status)
status = init_status (dev, udev);
if (status < 0)
goto out3;
if (!dev->rx_urb_size)
dev->rx_urb_size = dev->hard_mtu;
dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
/* let userspace know we have a random address */
if (ether_addr_equal(net->dev_addr, node_id))
net->addr_assign_type = NET_ADDR_RANDOM;
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
SET_NETDEV_DEVTYPE(net, &wlan_type);
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
SET_NETDEV_DEVTYPE(net, &wwan_type);
/* initialize max rx_qlen and tx_qlen */
usbnet_update_max_qlen(dev);
if (dev->can_dma_sg && !(info->flags & FLAG_SEND_ZLP) &&
!(info->flags & FLAG_MULTI_PACKET)) {
dev->padding_pkt = kzalloc(1, GFP_KERNEL);
if (!dev->padding_pkt) {
status = -ENOMEM;
goto out4;
}
}
status = register_netdev (net);
if (status)
goto out5;
netif_info(dev, probe, dev->net,
"register '%s' at usb-%s-%s, %s, %pM\n",
udev->dev.driver->name,
xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description,
net->dev_addr);
// ok, it's ready to go.
usb_set_intfdata (udev, dev);
netif_device_attach (net);
if (dev->driver_info->flags & FLAG_LINK_INTR)
usbnet_link_change(dev, 0, 0);
return 0;
out5:
kfree(dev->padding_pkt);
out4:
usb_free_urb(dev->interrupt);
out3:
if (info->unbind)
info->unbind (dev, udev);
out1:
free_netdev(net);
out:
return status;
}
下面代码是有关名字的设置,
if (info->bind) {
status = info->bind (dev, udev);
if (status < 0)
goto out1;
// heuristic: "usb%d" for links we know are two-host,
// else "eth%d" when there's reasonable doubt. userspace
// can rename the link if it knows better.
dev->driver_info->flags=FLAG_ETHER; //加上这一行
if ((dev->driver_info->flags & FLAG_ETHER) != 0 &&
((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 ||
(net->dev_addr [0] & 0x02) == 0))
strcpy (net->name, "eth%d");
/* WLAN devices should always be named "wlan%d" */
if ((dev->driver_info->flags & FLAG_WLAN) != 0)
strcpy(net->name, "wlan%d");
/* WWAN devices should always be named "wwan%d" */
if ((dev->driver_info->flags & FLAG_WWAN) != 0)
strcpy(net->name, "wwan%d");
/* devices that cannot do ARP */
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
/* maybe the remote can't receive an Ethernet MTU */
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
net->mtu = dev->hard_mtu - net->hard_header_len;
}
所以需要修改net->dev_addr [0],使它不等于0x02,并且FLAG_ETHER和dev->driver_info->flags做位与运算不等于0
FLAG_ETHER=0x20
添加一些打印信息后[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oxZG13yE-1662347013764)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220830161213766.png)]
发现net->dev_addr [0]是9a,2进制展开10011010,2展开是10,
10011010
00000010
=2 !=0
所以需要修改第二位为0,如:0x08,那么需要在哪里改呢?
usb转百兆网口被识别的时候会执行bind初始化函数
int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
{
int status;
struct cdc_state *info = (void *) &dev->data;
BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
status = usbnet_generic_cdc_bind(dev, intf);
if (status < 0)
return status;
status = usbnet_get_ethernet_addr(dev, info->ether->iMACAddress);
if (status < 0) {
usb_set_intfdata(info->data, NULL);
usb_driver_release_interface(driver_of(intf), info->data);
return status;
}
dev->net->dev_addr [0] = 0x08; //加上这一行
return 0;
}
然后会执行usbnet_get_ethernet_addr()
int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
{
int tmp = -1, ret;
unsigned char buf [13];
ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf); //将地址转换为16进制
if (ret == 12)
tmp = hex2bin(dev->net->dev_addr, buf, 6); //转化为2进制
if (tmp < 0) {
dev_dbg(&dev->udev->dev,
"bad MAC string %d fetch, %d\n", iMACAddress, tmp);
if (ret >= 0)
ret = -EINVAL;
return ret;
}
return 0;
}
usb_string()函数
/**
* usb_string - returns UTF-8 version of a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @index: the number of the descriptor
* @buf: where to put the string
* @size: how big is "buf"?
* Context: !in_interrupt ()
*
* This converts the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
* that are more usable in most kernel contexts. Note that this function
* chooses strings in the first language supported by the device.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Return: length of the string (>= 0) or usb_control_msg status (< 0).
*/
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
unsigned char *tbuf;
int err;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
if (size <= 0 || !buf || !index)
return -EINVAL;
buf[0] = 0;
tbuf = kmalloc(256, GFP_NOIO);
if (!tbuf)
return -ENOMEM;
err = usb_get_langid(dev, tbuf);
if (err < 0)
goto errout;
err = usb_string_sub(dev, dev->string_langid, index, tbuf);
if (err < 0)
goto errout;
size--; /* leave room for trailing NULL char in output buffer */
err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
UTF16_LITTLE_ENDIAN, buf, size);
buf[err] = 0;
if (tbuf[1] != USB_DT_STRING)
dev_dbg(&dev->dev,
"wrong descriptor type %02x for string %d (\"%s\")\n",
tbuf[1], index, buf);
errout:
kfree(tbuf);
return err;
}
EXPORT_SYMBOL_GPL(usb_string);
hex2bin()函数
/**
* hex2bin - convert an ascii hexadecimal string to its binary representation
* @dst: binary result
* @src: ascii hexadecimal string
* @count: result length
*
* Return 0 on success, -1 in case of bad input.
*/
int hex2bin(u8 *dst, const char *src, size_t count)
{
while (count--) {
int hi = hex_to_bin(*src++);
int lo = hex_to_bin(*src++);
if ((hi < 0) || (lo < 0))
return -1;
*dst++ = (hi << 4) | lo;
}
return 0;
}
EXPORT_SYMBOL(hex2bin);
修改内容见上面代码中的加上这一行