// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for USB ethernet port of Conexant CX82310-based ADSL routers * Copyright (C) 2010 by Ondrej Zary * some parts inspired by the cxacru driver
*/
/* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */ if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0
&& strcmp(buf, "USB NET CARD")) {
dev_info(&udev->dev, "ignoring: probably an ADSL modem\n"); return -ENODEV;
}
ret = usbnet_get_endpoints(dev, intf); if (ret) return ret;
/* * this must not include ethernet header as the device can send partial * packets with no header (and sometimes even empty URBs)
*/
dev->net->hard_header_len = 0; /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */
dev->hard_mtu = CX82310_MTU + 2; /* we can receive URBs up to 4KB from the device */
dev->rx_urb_size = 4096;
dev->partial_data = (unsignedlong) kmalloc(dev->hard_mtu, GFP_KERNEL); if (!dev->partial_data) return -ENOMEM;
/* wait for firmware to become ready (indicated by the link being up) */ while (--timeout) {
ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,
link, sizeof(link)); /* the command can time out during boot - it's not an error */ if (!ret && link[0] == 1 && link[2] == 1) break;
msleep(500);
} if (!timeout) {
netdev_err(dev->net, "firmware not ready in time\n");
ret = -ETIMEDOUT; goto err;
}
/* enable ethernet mode (?) */
ret = cx82310_enable_ethernet(dev); if (ret) goto err;
/* get the MAC address */
ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0, addr, ETH_ALEN); if (ret) {
netdev_err(dev->net, "unable to read MAC address: %d\n", ret); goto err;
}
eth_hw_addr_set(dev->net, addr);
/* start (does not seem to have any effect?) */
ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0); if (ret) goto err;
/* * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte * packet length at the beginning. * The last packet might be incomplete (when it crosses the 4KB URB size), * continuing in the next skb (without any headers). * If a packet has odd length, there is one extra byte at the end (before next * packet or at the end of the URB).
*/ staticint cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{ int len; struct sk_buff *skb2; struct cx82310_priv *priv = dev->driver_priv;
/* * If the last skb ended with an incomplete packet, this skb contains * end of that packet at the beginning.
*/ if (dev->partial_rem) {
len = dev->partial_len + dev->partial_rem;
skb2 = alloc_skb(len, GFP_ATOMIC); if (!skb2) return 0;
skb_put(skb2, len);
memcpy(skb2->data, (void *)dev->partial_data,
dev->partial_len);
memcpy(skb2->data + dev->partial_len, skb->data,
dev->partial_rem);
usbnet_skb_return(dev, skb2);
skb_pull(skb, (dev->partial_rem + 1) & ~1);
dev->partial_rem = 0; if (skb->len < 2) return 1;
}
/* a skb can contain multiple packets */ while (skb->len > 1) { /* first two bytes are packet length */
len = skb->data[0] | (skb->data[1] << 8);
skb_pull(skb, 2);
/* if last packet in the skb, let usbnet to process it */ if (len == skb->len || len + 1 == skb->len) {
skb_trim(skb, len); break;
}
if (len == 0xffff) {
netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");
schedule_work(&priv->reenable_work);
} elseif (len > CX82310_MTU) {
netdev_err(dev->net, "RX packet too long: %d B\n", len); return 0;
}
/* incomplete packet, save it for the next skb */ if (len > skb->len) {
dev->partial_len = skb->len;
dev->partial_rem = len - skb->len;
memcpy((void *)dev->partial_data, skb->data,
dev->partial_len);
skb_pull(skb, skb->len); break;
}
skb2 = alloc_skb(len, GFP_ATOMIC); if (!skb2) return 0;
skb_put(skb2, len);
memcpy(skb2->data, skb->data, len); /* process the packet */
usbnet_skb_return(dev, skb2);
skb_pull(skb, (len + 1) & ~1);
}
/* let usbnet process the last packet */ return 1;
}
/* TX is easy, just add 2 bytes of length at the beginning */ staticstruct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
gfp_t flags)
{ int len = skb->len;
if (skb_cow_head(skb, 2)) {
dev_kfree_skb_any(skb); return NULL;
}
skb_push(skb, 2);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.