/* 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;
/* *thismustnotincludeethernetheaderasthedevicecansendpartial *packetswithnoheader(andsometimesevenemptyURBs)
*/
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;
/* 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); return0;
}
/* 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) return0;
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 */ return1;
}
/* 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.