376 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for USB ethernet port of Conexant CX82310-based ADSL routers4 * Copyright (C) 2010 by Ondrej Zary5 * some parts inspired by the cxacru driver6 */7 8#include <linux/module.h>9#include <linux/netdevice.h>10#include <linux/etherdevice.h>11#include <linux/ethtool.h>12#include <linux/workqueue.h>13#include <linux/mii.h>14#include <linux/usb.h>15#include <linux/usb/usbnet.h>16 17enum cx82310_cmd {18 CMD_START = 0x84, /* no effect? */19 CMD_STOP = 0x85, /* no effect? */20 CMD_GET_STATUS = 0x90, /* returns nothing? */21 CMD_GET_MAC_ADDR = 0x91, /* read MAC address */22 CMD_GET_LINK_STATUS = 0x92, /* not useful, link is always up */23 CMD_ETHERNET_MODE = 0x99, /* unknown, needed during init */24};25 26enum cx82310_status {27 STATUS_UNDEFINED,28 STATUS_SUCCESS,29 STATUS_ERROR,30 STATUS_UNSUPPORTED,31 STATUS_UNIMPLEMENTED,32 STATUS_PARAMETER_ERROR,33 STATUS_DBG_LOOPBACK,34};35 36#define CMD_PACKET_SIZE 6437#define CMD_TIMEOUT 10038#define CMD_REPLY_RETRY 539 40#define CX82310_MTU 151441#define CMD_EP 0x0142 43struct cx82310_priv {44 struct work_struct reenable_work;45 struct usbnet *dev;46};47 48/*49 * execute control command50 * - optionally send some data (command parameters)51 * - optionally wait for the reply52 * - optionally read some data from the reply53 */54static int cx82310_cmd(struct usbnet *dev, enum cx82310_cmd cmd, bool reply,55 u8 *wdata, int wlen, u8 *rdata, int rlen)56{57 int actual_len, retries, ret;58 struct usb_device *udev = dev->udev;59 u8 *buf = kzalloc(CMD_PACKET_SIZE, GFP_KERNEL);60 61 if (!buf)62 return -ENOMEM;63 64 /* create command packet */65 buf[0] = cmd;66 if (wdata)67 memcpy(buf + 4, wdata, min_t(int, wlen, CMD_PACKET_SIZE - 4));68 69 /* send command packet */70 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, CMD_EP), buf,71 CMD_PACKET_SIZE, &actual_len, CMD_TIMEOUT);72 if (ret < 0) {73 if (cmd != CMD_GET_LINK_STATUS)74 netdev_err(dev->net, "send command %#x: error %d\n",75 cmd, ret);76 goto end;77 }78 79 if (reply) {80 /* wait for reply, retry if it's empty */81 for (retries = 0; retries < CMD_REPLY_RETRY; retries++) {82 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, CMD_EP),83 buf, CMD_PACKET_SIZE, &actual_len,84 CMD_TIMEOUT);85 if (ret < 0) {86 if (cmd != CMD_GET_LINK_STATUS)87 netdev_err(dev->net, "reply receive error %d\n",88 ret);89 goto end;90 }91 if (actual_len > 0)92 break;93 }94 if (actual_len == 0) {95 netdev_err(dev->net, "no reply to command %#x\n", cmd);96 ret = -EIO;97 goto end;98 }99 if (buf[0] != cmd) {100 netdev_err(dev->net, "got reply to command %#x, expected: %#x\n",101 buf[0], cmd);102 ret = -EIO;103 goto end;104 }105 if (buf[1] != STATUS_SUCCESS) {106 netdev_err(dev->net, "command %#x failed: %#x\n", cmd,107 buf[1]);108 ret = -EIO;109 goto end;110 }111 if (rdata)112 memcpy(rdata, buf + 4,113 min_t(int, rlen, CMD_PACKET_SIZE - 4));114 }115end:116 kfree(buf);117 return ret;118}119 120static int cx82310_enable_ethernet(struct usbnet *dev)121{122 int ret = cx82310_cmd(dev, CMD_ETHERNET_MODE, true, "\x01", 1, NULL, 0);123 124 if (ret)125 netdev_err(dev->net, "unable to enable ethernet mode: %d\n",126 ret);127 return ret;128}129 130static void cx82310_reenable_work(struct work_struct *work)131{132 struct cx82310_priv *priv = container_of(work, struct cx82310_priv,133 reenable_work);134 cx82310_enable_ethernet(priv->dev);135}136 137#define partial_len data[0] /* length of partial packet data */138#define partial_rem data[1] /* remaining (missing) data length */139#define partial_data data[2] /* partial packet data */140 141static int cx82310_bind(struct usbnet *dev, struct usb_interface *intf)142{143 int ret;144 char buf[15];145 struct usb_device *udev = dev->udev;146 u8 link[3];147 int timeout = 50;148 struct cx82310_priv *priv;149 u8 addr[ETH_ALEN];150 151 /* avoid ADSL modems - continue only if iProduct is "USB NET CARD" */152 if (usb_string(udev, udev->descriptor.iProduct, buf, sizeof(buf)) > 0153 && strcmp(buf, "USB NET CARD")) {154 dev_info(&udev->dev, "ignoring: probably an ADSL modem\n");155 return -ENODEV;156 }157 158 ret = usbnet_get_endpoints(dev, intf);159 if (ret)160 return ret;161 162 /*163 * this must not include ethernet header as the device can send partial164 * packets with no header (and sometimes even empty URBs)165 */166 dev->net->hard_header_len = 0;167 /* we can send at most 1514 bytes of data (+ 2-byte header) per URB */168 dev->hard_mtu = CX82310_MTU + 2;169 /* we can receive URBs up to 4KB from the device */170 dev->rx_urb_size = 4096;171 172 dev->partial_data = (unsigned long) kmalloc(dev->hard_mtu, GFP_KERNEL);173 if (!dev->partial_data)174 return -ENOMEM;175 176 priv = kzalloc(sizeof(*priv), GFP_KERNEL);177 if (!priv) {178 ret = -ENOMEM;179 goto err_partial;180 }181 dev->driver_priv = priv;182 INIT_WORK(&priv->reenable_work, cx82310_reenable_work);183 priv->dev = dev;184 185 /* wait for firmware to become ready (indicated by the link being up) */186 while (--timeout) {187 ret = cx82310_cmd(dev, CMD_GET_LINK_STATUS, true, NULL, 0,188 link, sizeof(link));189 /* the command can time out during boot - it's not an error */190 if (!ret && link[0] == 1 && link[2] == 1)191 break;192 msleep(500);193 }194 if (!timeout) {195 netdev_err(dev->net, "firmware not ready in time\n");196 ret = -ETIMEDOUT;197 goto err;198 }199 200 /* enable ethernet mode (?) */201 ret = cx82310_enable_ethernet(dev);202 if (ret)203 goto err;204 205 /* get the MAC address */206 ret = cx82310_cmd(dev, CMD_GET_MAC_ADDR, true, NULL, 0, addr, ETH_ALEN);207 if (ret) {208 netdev_err(dev->net, "unable to read MAC address: %d\n", ret);209 goto err;210 }211 eth_hw_addr_set(dev->net, addr);212 213 /* start (does not seem to have any effect?) */214 ret = cx82310_cmd(dev, CMD_START, false, NULL, 0, NULL, 0);215 if (ret)216 goto err;217 218 return 0;219err:220 kfree(dev->driver_priv);221err_partial:222 kfree((void *)dev->partial_data);223 return ret;224}225 226static void cx82310_unbind(struct usbnet *dev, struct usb_interface *intf)227{228 struct cx82310_priv *priv = dev->driver_priv;229 230 kfree((void *)dev->partial_data);231 cancel_work_sync(&priv->reenable_work);232 kfree(dev->driver_priv);233}234 235/*236 * RX is NOT easy - we can receive multiple packets per skb, each having 2-byte237 * packet length at the beginning.238 * The last packet might be incomplete (when it crosses the 4KB URB size),239 * continuing in the next skb (without any headers).240 * If a packet has odd length, there is one extra byte at the end (before next241 * packet or at the end of the URB).242 */243static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)244{245 int len;246 struct sk_buff *skb2;247 struct cx82310_priv *priv = dev->driver_priv;248 249 /*250 * If the last skb ended with an incomplete packet, this skb contains251 * end of that packet at the beginning.252 */253 if (dev->partial_rem) {254 len = dev->partial_len + dev->partial_rem;255 skb2 = alloc_skb(len, GFP_ATOMIC);256 if (!skb2)257 return 0;258 skb_put(skb2, len);259 memcpy(skb2->data, (void *)dev->partial_data,260 dev->partial_len);261 memcpy(skb2->data + dev->partial_len, skb->data,262 dev->partial_rem);263 usbnet_skb_return(dev, skb2);264 skb_pull(skb, (dev->partial_rem + 1) & ~1);265 dev->partial_rem = 0;266 if (skb->len < 2)267 return 1;268 }269 270 /* a skb can contain multiple packets */271 while (skb->len > 1) {272 /* first two bytes are packet length */273 len = skb->data[0] | (skb->data[1] << 8);274 skb_pull(skb, 2);275 276 /* if last packet in the skb, let usbnet to process it */277 if (len == skb->len || len + 1 == skb->len) {278 skb_trim(skb, len);279 break;280 }281 282 if (len == 0xffff) {283 netdev_info(dev->net, "router was rebooted, re-enabling ethernet mode");284 schedule_work(&priv->reenable_work);285 } else if (len > CX82310_MTU) {286 netdev_err(dev->net, "RX packet too long: %d B\n", len);287 return 0;288 }289 290 /* incomplete packet, save it for the next skb */291 if (len > skb->len) {292 dev->partial_len = skb->len;293 dev->partial_rem = len - skb->len;294 memcpy((void *)dev->partial_data, skb->data,295 dev->partial_len);296 skb_pull(skb, skb->len);297 break;298 }299 300 skb2 = alloc_skb(len, GFP_ATOMIC);301 if (!skb2)302 return 0;303 skb_put(skb2, len);304 memcpy(skb2->data, skb->data, len);305 /* process the packet */306 usbnet_skb_return(dev, skb2);307 308 skb_pull(skb, (len + 1) & ~1);309 }310 311 /* let usbnet process the last packet */312 return 1;313}314 315/* TX is easy, just add 2 bytes of length at the beginning */316static struct sk_buff *cx82310_tx_fixup(struct usbnet *dev, struct sk_buff *skb,317 gfp_t flags)318{319 int len = skb->len;320 321 if (skb_cow_head(skb, 2)) {322 dev_kfree_skb_any(skb);323 return NULL;324 }325 skb_push(skb, 2);326 327 skb->data[0] = len;328 skb->data[1] = len >> 8;329 330 return skb;331}332 333 334static const struct driver_info cx82310_info = {335 .description = "Conexant CX82310 USB ethernet",336 .flags = FLAG_ETHER,337 .bind = cx82310_bind,338 .unbind = cx82310_unbind,339 .rx_fixup = cx82310_rx_fixup,340 .tx_fixup = cx82310_tx_fixup,341};342 343#define USB_DEVICE_CLASS(vend, prod, cl, sc, pr) \344 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \345 USB_DEVICE_ID_MATCH_DEV_INFO, \346 .idVendor = (vend), \347 .idProduct = (prod), \348 .bDeviceClass = (cl), \349 .bDeviceSubClass = (sc), \350 .bDeviceProtocol = (pr)351 352static const struct usb_device_id products[] = {353 {354 USB_DEVICE_CLASS(0x0572, 0xcb01, 0xff, 0, 0),355 .driver_info = (unsigned long) &cx82310_info356 },357 { },358};359MODULE_DEVICE_TABLE(usb, products);360 361static struct usb_driver cx82310_driver = {362 .name = "cx82310_eth",363 .id_table = products,364 .probe = usbnet_probe,365 .disconnect = usbnet_disconnect,366 .suspend = usbnet_suspend,367 .resume = usbnet_resume,368 .disable_hub_initiated_lpm = 1,369};370 371module_usb_driver(cx82310_driver);372 373MODULE_AUTHOR("Ondrej Zary");374MODULE_DESCRIPTION("Conexant CX82310-based ADSL router USB ethernet driver");375MODULE_LICENSE("GPL");376