| 1 | |
| 2 | |
| 3 | * f_ecm.c -- USB CDC Ethernet (ECM) link function driver
|
| 4 | *
|
| 5 | * Copyright (C) 2003-2005,2008 David Brownell
|
| 6 | * Copyright (C) 2008 Nokia Corporation
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 | #include <linux/cleanup.h>
|
| 12 | #include <linux/slab.h>
|
| 13 | #include <linux/kernel.h>
|
| 14 | #include <linux/module.h>
|
| 15 | #include <linux/device.h>
|
| 16 | #include <linux/etherdevice.h>
|
| 17 | #include <linux/string_choices.h>
|
| 18 |
|
| 19 | #include <linux/usb/gadget.h>
|
| 20 |
|
| 21 | #include "u_ether.h"
|
| 22 | #include "u_ether_configfs.h"
|
| 23 | #include "u_ecm.h"
|
| 24 |
|
| 25 |
|
| 26 | |
| 27 | * This function is a "CDC Ethernet Networking Control Model" (CDC ECM)
|
| 28 | * Ethernet link. The data transfer model is simple (packets sent and
|
| 29 | * received over bulk endpoints using normal short packet termination),
|
| 30 | * and the control model exposes various data and optional notifications.
|
| 31 | *
|
| 32 | * ECM is well standardized and (except for Microsoft) supported by most
|
| 33 | * operating systems with USB host support. It's the preferred interop
|
| 34 | * solution for Ethernet over USB, at least for firmware based solutions.
|
| 35 | * (Hardware solutions tend to be more minimalist.) A newer and simpler
|
| 36 | * "Ethernet Emulation Model" (CDC EEM) hasn't yet caught on.
|
| 37 | *
|
| 38 | * Note that ECM requires the use of "alternate settings" for its data
|
| 39 | * interface. This means that the set_alt() method has real work to do,
|
| 40 | * and also means that a get_alt() method is required.
|
| 41 |
|
| 42 |
|
| 43 |
|
| 44 | enum ecm_notify_state {
|
| 45 | ECM_NOTIFY_NONE,
|
| 46 | ECM_NOTIFY_CONNECT,
|
| 47 | ECM_NOTIFY_SPEED,
|
| 48 | };
|
| 49 |
|
| 50 | struct f_ecm {
|
| 51 | struct gether port;
|
| 52 | u8 ctrl_id, data_id;
|
| 53 |
|
| 54 | char ethaddr[14];
|
| 55 |
|
| 56 | struct usb_ep *notify;
|
| 57 | struct usb_request *notify_req;
|
| 58 | u8 notify_state;
|
| 59 | atomic_t notify_count;
|
| 60 | bool is_open;
|
| 61 |
|
| 62 | |
| 63 | * ... possibly the same as port.ioport
|
| 64 |
|
| 65 | };
|
| 66 |
|
| 67 | static inline struct f_ecm *func_to_ecm(struct usb_function *f)
|
| 68 | {
|
| 69 | return container_of(f, struct f_ecm, port.func);
|
| 70 | }
|
| 71 |
|
| 72 |
|
| 73 |
|
| 74 | |
| 75 | * Include the status endpoint if we can, even though it's optional.
|
| 76 | *
|
| 77 | * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one
|
| 78 | * packet, to simplify cancellation; and a big transfer interval, to
|
| 79 | * waste less bandwidth.
|
| 80 | *
|
| 81 | * Some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even
|
| 82 | * if they ignore the connect/disconnect notifications that real aether
|
| 83 | * can provide. More advanced cdc configurations might want to support
|
| 84 | * encapsulated commands (vendor-specific, using control-OUT).
|
| 85 |
|
| 86 |
|
| 87 | #define ECM_STATUS_INTERVAL_MS 32
|
| 88 | #define ECM_STATUS_BYTECOUNT 16
|
| 89 |
|
| 90 |
|
| 91 |
|
| 92 |
|
| 93 | static struct usb_interface_assoc_descriptor
|
| 94 | ecm_iad_descriptor = {
|
| 95 | .bLength = sizeof ecm_iad_descriptor,
|
| 96 | .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
| 97 |
|
| 98 |
|
| 99 | .bInterfaceCount = 2,
|
| 100 | .bFunctionClass = USB_CLASS_COMM,
|
| 101 | .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
|
| 102 | .bFunctionProtocol = USB_CDC_PROTO_NONE,
|
| 103 |
|
| 104 | };
|
| 105 |
|
| 106 |
|
| 107 | static struct usb_interface_descriptor ecm_control_intf = {
|
| 108 | .bLength = sizeof ecm_control_intf,
|
| 109 | .bDescriptorType = USB_DT_INTERFACE,
|
| 110 |
|
| 111 |
|
| 112 |
|
| 113 | .bNumEndpoints = 1,
|
| 114 | .bInterfaceClass = USB_CLASS_COMM,
|
| 115 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
|
| 116 | .bInterfaceProtocol = USB_CDC_PROTO_NONE,
|
| 117 |
|
| 118 | };
|
| 119 |
|
| 120 | static struct usb_cdc_header_desc ecm_header_desc = {
|
| 121 | .bLength = sizeof ecm_header_desc,
|
| 122 | .bDescriptorType = USB_DT_CS_INTERFACE,
|
| 123 | .bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
| 124 |
|
| 125 | .bcdCDC = cpu_to_le16(0x0110),
|
| 126 | };
|
| 127 |
|
| 128 | static struct usb_cdc_union_desc ecm_union_desc = {
|
| 129 | .bLength = sizeof(ecm_union_desc),
|
| 130 | .bDescriptorType = USB_DT_CS_INTERFACE,
|
| 131 | .bDescriptorSubType = USB_CDC_UNION_TYPE,
|
| 132 |
|
| 133 |
|
| 134 | };
|
| 135 |
|
| 136 | static struct usb_cdc_ether_desc ecm_desc = {
|
| 137 | .bLength = sizeof ecm_desc,
|
| 138 | .bDescriptorType = USB_DT_CS_INTERFACE,
|
| 139 | .bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
|
| 140 |
|
| 141 |
|
| 142 |
|
| 143 | .bmEthernetStatistics = cpu_to_le32(0),
|
| 144 | .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN),
|
| 145 | .wNumberMCFilters = cpu_to_le16(0),
|
| 146 | .bNumberPowerFilters = 0,
|
| 147 | };
|
| 148 |
|
| 149 |
|
| 150 |
|
| 151 | static struct usb_interface_descriptor ecm_data_nop_intf = {
|
| 152 | .bLength = sizeof ecm_data_nop_intf,
|
| 153 | .bDescriptorType = USB_DT_INTERFACE,
|
| 154 |
|
| 155 | .bInterfaceNumber = 1,
|
| 156 | .bAlternateSetting = 0,
|
| 157 | .bNumEndpoints = 0,
|
| 158 | .bInterfaceClass = USB_CLASS_CDC_DATA,
|
| 159 | .bInterfaceSubClass = 0,
|
| 160 | .bInterfaceProtocol = 0,
|
| 161 |
|
| 162 | };
|
| 163 |
|
| 164 |
|
| 165 |
|
| 166 | static struct usb_interface_descriptor ecm_data_intf = {
|
| 167 | .bLength = sizeof ecm_data_intf,
|
| 168 | .bDescriptorType = USB_DT_INTERFACE,
|
| 169 |
|
| 170 | .bInterfaceNumber = 1,
|
| 171 | .bAlternateSetting = 1,
|
| 172 | .bNumEndpoints = 2,
|
| 173 | .bInterfaceClass = USB_CLASS_CDC_DATA,
|
| 174 | .bInterfaceSubClass = 0,
|
| 175 | .bInterfaceProtocol = 0,
|
| 176 |
|
| 177 | };
|
| 178 |
|
| 179 |
|
| 180 |
|
| 181 | static struct usb_endpoint_descriptor fs_ecm_notify_desc = {
|
| 182 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 183 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 184 |
|
| 185 | .bEndpointAddress = USB_DIR_IN,
|
| 186 | .bmAttributes = USB_ENDPOINT_XFER_INT,
|
| 187 | .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
| 188 | .bInterval = ECM_STATUS_INTERVAL_MS,
|
| 189 | };
|
| 190 |
|
| 191 | static struct usb_endpoint_descriptor fs_ecm_in_desc = {
|
| 192 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 193 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 194 |
|
| 195 | .bEndpointAddress = USB_DIR_IN,
|
| 196 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 197 | };
|
| 198 |
|
| 199 | static struct usb_endpoint_descriptor fs_ecm_out_desc = {
|
| 200 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 201 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 202 |
|
| 203 | .bEndpointAddress = USB_DIR_OUT,
|
| 204 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 205 | };
|
| 206 |
|
| 207 | static struct usb_descriptor_header *ecm_fs_function[] = {
|
| 208 |
|
| 209 | (struct usb_descriptor_header *) &ecm_iad_descriptor,
|
| 210 | (struct usb_descriptor_header *) &ecm_control_intf,
|
| 211 | (struct usb_descriptor_header *) &ecm_header_desc,
|
| 212 | (struct usb_descriptor_header *) &ecm_union_desc,
|
| 213 | (struct usb_descriptor_header *) &ecm_desc,
|
| 214 |
|
| 215 |
|
| 216 | (struct usb_descriptor_header *) &fs_ecm_notify_desc,
|
| 217 |
|
| 218 |
|
| 219 | (struct usb_descriptor_header *) &ecm_data_nop_intf,
|
| 220 | (struct usb_descriptor_header *) &ecm_data_intf,
|
| 221 | (struct usb_descriptor_header *) &fs_ecm_in_desc,
|
| 222 | (struct usb_descriptor_header *) &fs_ecm_out_desc,
|
| 223 | NULL,
|
| 224 | };
|
| 225 |
|
| 226 |
|
| 227 |
|
| 228 | static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
|
| 229 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 230 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 231 |
|
| 232 | .bEndpointAddress = USB_DIR_IN,
|
| 233 | .bmAttributes = USB_ENDPOINT_XFER_INT,
|
| 234 | .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
| 235 | .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS),
|
| 236 | };
|
| 237 |
|
| 238 | static struct usb_endpoint_descriptor hs_ecm_in_desc = {
|
| 239 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 240 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 241 |
|
| 242 | .bEndpointAddress = USB_DIR_IN,
|
| 243 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 244 | .wMaxPacketSize = cpu_to_le16(512),
|
| 245 | };
|
| 246 |
|
| 247 | static struct usb_endpoint_descriptor hs_ecm_out_desc = {
|
| 248 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 249 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 250 |
|
| 251 | .bEndpointAddress = USB_DIR_OUT,
|
| 252 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 253 | .wMaxPacketSize = cpu_to_le16(512),
|
| 254 | };
|
| 255 |
|
| 256 | static struct usb_descriptor_header *ecm_hs_function[] = {
|
| 257 |
|
| 258 | (struct usb_descriptor_header *) &ecm_iad_descriptor,
|
| 259 | (struct usb_descriptor_header *) &ecm_control_intf,
|
| 260 | (struct usb_descriptor_header *) &ecm_header_desc,
|
| 261 | (struct usb_descriptor_header *) &ecm_union_desc,
|
| 262 | (struct usb_descriptor_header *) &ecm_desc,
|
| 263 |
|
| 264 |
|
| 265 | (struct usb_descriptor_header *) &hs_ecm_notify_desc,
|
| 266 |
|
| 267 |
|
| 268 | (struct usb_descriptor_header *) &ecm_data_nop_intf,
|
| 269 | (struct usb_descriptor_header *) &ecm_data_intf,
|
| 270 | (struct usb_descriptor_header *) &hs_ecm_in_desc,
|
| 271 | (struct usb_descriptor_header *) &hs_ecm_out_desc,
|
| 272 | NULL,
|
| 273 | };
|
| 274 |
|
| 275 |
|
| 276 |
|
| 277 | static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
|
| 278 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 279 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 280 |
|
| 281 | .bEndpointAddress = USB_DIR_IN,
|
| 282 | .bmAttributes = USB_ENDPOINT_XFER_INT,
|
| 283 | .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
| 284 | .bInterval = USB_MS_TO_HS_INTERVAL(ECM_STATUS_INTERVAL_MS),
|
| 285 | };
|
| 286 |
|
| 287 | static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = {
|
| 288 | .bLength = sizeof ss_ecm_intr_comp_desc,
|
| 289 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
| 290 |
|
| 291 |
|
| 292 |
|
| 293 |
|
| 294 | .wBytesPerInterval = cpu_to_le16(ECM_STATUS_BYTECOUNT),
|
| 295 | };
|
| 296 |
|
| 297 | static struct usb_endpoint_descriptor ss_ecm_in_desc = {
|
| 298 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 299 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 300 |
|
| 301 | .bEndpointAddress = USB_DIR_IN,
|
| 302 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 303 | .wMaxPacketSize = cpu_to_le16(1024),
|
| 304 | };
|
| 305 |
|
| 306 | static struct usb_endpoint_descriptor ss_ecm_out_desc = {
|
| 307 | .bLength = USB_DT_ENDPOINT_SIZE,
|
| 308 | .bDescriptorType = USB_DT_ENDPOINT,
|
| 309 |
|
| 310 | .bEndpointAddress = USB_DIR_OUT,
|
| 311 | .bmAttributes = USB_ENDPOINT_XFER_BULK,
|
| 312 | .wMaxPacketSize = cpu_to_le16(1024),
|
| 313 | };
|
| 314 |
|
| 315 | static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = {
|
| 316 | .bLength = sizeof ss_ecm_bulk_comp_desc,
|
| 317 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
|
| 318 |
|
| 319 |
|
| 320 |
|
| 321 |
|
| 322 | };
|
| 323 |
|
| 324 | static struct usb_descriptor_header *ecm_ss_function[] = {
|
| 325 |
|
| 326 | (struct usb_descriptor_header *) &ecm_iad_descriptor,
|
| 327 | (struct usb_descriptor_header *) &ecm_control_intf,
|
| 328 | (struct usb_descriptor_header *) &ecm_header_desc,
|
| 329 | (struct usb_descriptor_header *) &ecm_union_desc,
|
| 330 | (struct usb_descriptor_header *) &ecm_desc,
|
| 331 |
|
| 332 |
|
| 333 | (struct usb_descriptor_header *) &ss_ecm_notify_desc,
|
| 334 | (struct usb_descriptor_header *) &ss_ecm_intr_comp_desc,
|
| 335 |
|
| 336 |
|
| 337 | (struct usb_descriptor_header *) &ecm_data_nop_intf,
|
| 338 | (struct usb_descriptor_header *) &ecm_data_intf,
|
| 339 | (struct usb_descriptor_header *) &ss_ecm_in_desc,
|
| 340 | (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
|
| 341 | (struct usb_descriptor_header *) &ss_ecm_out_desc,
|
| 342 | (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
|
| 343 | NULL,
|
| 344 | };
|
| 345 |
|
| 346 |
|
| 347 |
|
| 348 | static struct usb_string ecm_string_defs[] = {
|
| 349 | [0].s = "CDC Ethernet Control Model (ECM)",
|
| 350 | [1].s = "",
|
| 351 | [2].s = "CDC Ethernet Data",
|
| 352 | [3].s = "CDC ECM",
|
| 353 | { }
|
| 354 | };
|
| 355 |
|
| 356 | static struct usb_gadget_strings ecm_string_table = {
|
| 357 | .language = 0x0409,
|
| 358 | .strings = ecm_string_defs,
|
| 359 | };
|
| 360 |
|
| 361 | static struct usb_gadget_strings *ecm_strings[] = {
|
| 362 | &ecm_string_table,
|
| 363 | NULL,
|
| 364 | };
|
| 365 |
|
| 366 |
|
| 367 |
|
| 368 | static void ecm_do_notify(struct f_ecm *ecm)
|
| 369 | {
|
| 370 | struct usb_request *req = ecm->notify_req;
|
| 371 | struct usb_cdc_notification *event;
|
| 372 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
| 373 | __le32 *data;
|
| 374 | int status;
|
| 375 |
|
| 376 |
|
| 377 | if (atomic_read(&ecm->notify_count))
|
| 378 | return;
|
| 379 |
|
| 380 | event = req->buf;
|
| 381 | switch (ecm->notify_state) {
|
| 382 | case ECM_NOTIFY_NONE:
|
| 383 | return;
|
| 384 |
|
| 385 | case ECM_NOTIFY_CONNECT:
|
| 386 | event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION;
|
| 387 | if (ecm->is_open)
|
| 388 | event->wValue = cpu_to_le16(1);
|
| 389 | else
|
| 390 | event->wValue = cpu_to_le16(0);
|
| 391 | event->wLength = 0;
|
| 392 | req->length = sizeof *event;
|
| 393 |
|
| 394 | DBG(cdev, "notify connect %s\n", str_true_false(ecm->is_open));
|
| 395 | ecm->notify_state = ECM_NOTIFY_SPEED;
|
| 396 | break;
|
| 397 |
|
| 398 | case ECM_NOTIFY_SPEED:
|
| 399 | event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE;
|
| 400 | event->wValue = cpu_to_le16(0);
|
| 401 | event->wLength = cpu_to_le16(8);
|
| 402 | req->length = ECM_STATUS_BYTECOUNT;
|
| 403 |
|
| 404 |
|
| 405 | data = req->buf + sizeof *event;
|
| 406 | data[0] = cpu_to_le32(gether_bitrate(cdev->gadget));
|
| 407 | data[1] = data[0];
|
| 408 |
|
| 409 | DBG(cdev, "notify speed %d\n", gether_bitrate(cdev->gadget));
|
| 410 | ecm->notify_state = ECM_NOTIFY_NONE;
|
| 411 | break;
|
| 412 | }
|
| 413 | event->bmRequestType = 0xA1;
|
| 414 | event->wIndex = cpu_to_le16(ecm->ctrl_id);
|
| 415 |
|
| 416 | atomic_inc(&ecm->notify_count);
|
| 417 | status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC);
|
| 418 | if (status < 0) {
|
| 419 | atomic_dec(&ecm->notify_count);
|
| 420 | DBG(cdev, "notify --> %d\n", status);
|
| 421 | }
|
| 422 | }
|
| 423 |
|
| 424 | static void ecm_notify(struct f_ecm *ecm)
|
| 425 | {
|
| 426 | |
| 427 | * won't listen for notifications until its netdevice opens.
|
| 428 | * The first notification then sits in the FIFO for a long
|
| 429 | * time, and the second one is queued.
|
| 430 |
|
| 431 | ecm->notify_state = ECM_NOTIFY_CONNECT;
|
| 432 | ecm_do_notify(ecm);
|
| 433 | }
|
| 434 |
|
| 435 | static void ecm_notify_complete(struct usb_ep *ep, struct usb_request *req)
|
| 436 | {
|
| 437 | struct f_ecm *ecm = req->context;
|
| 438 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
| 439 | struct usb_cdc_notification *event = req->buf;
|
| 440 |
|
| 441 | switch (req->status) {
|
| 442 | case 0:
|
| 443 |
|
| 444 | atomic_dec(&ecm->notify_count);
|
| 445 | break;
|
| 446 | case -ECONNRESET:
|
| 447 | case -ESHUTDOWN:
|
| 448 | atomic_set(&ecm->notify_count, 0);
|
| 449 | ecm->notify_state = ECM_NOTIFY_NONE;
|
| 450 | break;
|
| 451 | default:
|
| 452 | DBG(cdev, "event %02x --> %d\n",
|
| 453 | event->bNotificationType, req->status);
|
| 454 | atomic_dec(&ecm->notify_count);
|
| 455 | break;
|
| 456 | }
|
| 457 | ecm_do_notify(ecm);
|
| 458 | }
|
| 459 |
|
| 460 | static int ecm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
|
| 461 | {
|
| 462 | struct f_ecm *ecm = func_to_ecm(f);
|
| 463 | struct usb_composite_dev *cdev = f->config->cdev;
|
| 464 | struct usb_request *req = cdev->req;
|
| 465 | int value = -EOPNOTSUPP;
|
| 466 | u16 w_index = le16_to_cpu(ctrl->wIndex);
|
| 467 | u16 w_value = le16_to_cpu(ctrl->wValue);
|
| 468 | u16 w_length = le16_to_cpu(ctrl->wLength);
|
| 469 |
|
| 470 | |
| 471 | * CDC class messages; interface activation uses set_alt().
|
| 472 |
|
| 473 | switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
|
| 474 | case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
|
| 475 | | USB_CDC_SET_ETHERNET_PACKET_FILTER:
|
| 476 | |
| 477 | * wValue = packet filter bitmap
|
| 478 |
|
| 479 | if (w_length != 0 || w_index != ecm->ctrl_id)
|
| 480 | goto invalid;
|
| 481 | DBG(cdev, "packet filter %02x\n", w_value);
|
| 482 | |
| 483 | * driver won't have a concurrent packet TX irq running on
|
| 484 | * another CPU; or that if it does, this write is atomic...
|
| 485 |
|
| 486 | ecm->port.cdc_filter = w_value;
|
| 487 | value = 0;
|
| 488 | break;
|
| 489 |
|
| 490 | |
| 491 | * case USB_CDC_SEND_ENCAPSULATED_COMMAND:
|
| 492 | * case USB_CDC_GET_ENCAPSULATED_RESPONSE:
|
| 493 | * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS:
|
| 494 | * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER:
|
| 495 | * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER:
|
| 496 | * case USB_CDC_GET_ETHERNET_STATISTIC:
|
| 497 |
|
| 498 |
|
| 499 | default:
|
| 500 | invalid:
|
| 501 | DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
|
| 502 | ctrl->bRequestType, ctrl->bRequest,
|
| 503 | w_value, w_index, w_length);
|
| 504 | }
|
| 505 |
|
| 506 |
|
| 507 | if (value >= 0) {
|
| 508 | DBG(cdev, "ecm req%02x.%02x v%04x i%04x l%d\n",
|
| 509 | ctrl->bRequestType, ctrl->bRequest,
|
| 510 | w_value, w_index, w_length);
|
| 511 | req->zero = 0;
|
| 512 | req->length = value;
|
| 513 | value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
| 514 | if (value < 0)
|
| 515 | ERROR(cdev, "ecm req %02x.%02x response err %d\n",
|
| 516 | ctrl->bRequestType, ctrl->bRequest,
|
| 517 | value);
|
| 518 | }
|
| 519 |
|
| 520 |
|
| 521 | return value;
|
| 522 | }
|
| 523 |
|
| 524 |
|
| 525 | static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
| 526 | {
|
| 527 | struct f_ecm *ecm = func_to_ecm(f);
|
| 528 | struct usb_composite_dev *cdev = f->config->cdev;
|
| 529 |
|
| 530 |
|
| 531 | if (intf == ecm->ctrl_id) {
|
| 532 | if (alt != 0)
|
| 533 | goto fail;
|
| 534 |
|
| 535 | VDBG(cdev, "reset ecm control %d\n", intf);
|
| 536 | usb_ep_disable(ecm->notify);
|
| 537 | if (!(ecm->notify->desc)) {
|
| 538 | VDBG(cdev, "init ecm ctrl %d\n", intf);
|
| 539 | if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
|
| 540 | goto fail;
|
| 541 | }
|
| 542 | usb_ep_enable(ecm->notify);
|
| 543 |
|
| 544 |
|
| 545 | } else if (intf == ecm->data_id) {
|
| 546 | if (alt > 1)
|
| 547 | goto fail;
|
| 548 |
|
| 549 | if (ecm->port.in_ep->enabled) {
|
| 550 | DBG(cdev, "reset ecm\n");
|
| 551 | gether_disconnect(&ecm->port);
|
| 552 | }
|
| 553 |
|
| 554 | if (!ecm->port.in_ep->desc ||
|
| 555 | !ecm->port.out_ep->desc) {
|
| 556 | DBG(cdev, "init ecm\n");
|
| 557 | if (config_ep_by_speed(cdev->gadget, f,
|
| 558 | ecm->port.in_ep) ||
|
| 559 | config_ep_by_speed(cdev->gadget, f,
|
| 560 | ecm->port.out_ep)) {
|
| 561 | ecm->port.in_ep->desc = NULL;
|
| 562 | ecm->port.out_ep->desc = NULL;
|
| 563 | goto fail;
|
| 564 | }
|
| 565 | }
|
| 566 |
|
| 567 | |
| 568 | * Changing altsettings resets filters, statistics, etc.
|
| 569 |
|
| 570 | if (alt == 1) {
|
| 571 | struct net_device *net;
|
| 572 |
|
| 573 | |
| 574 | * override for musb_hdrc (avoids txdma ovhead).
|
| 575 |
|
| 576 | ecm->port.is_zlp_ok =
|
| 577 | gadget_is_zlp_supported(cdev->gadget);
|
| 578 | ecm->port.cdc_filter = DEFAULT_FILTER;
|
| 579 | DBG(cdev, "activate ecm\n");
|
| 580 | net = gether_connect(&ecm->port);
|
| 581 | if (IS_ERR(net))
|
| 582 | return PTR_ERR(net);
|
| 583 | }
|
| 584 |
|
| 585 | |
| 586 | * which says speed notifications will "always" follow
|
| 587 | * connection notifications. But we allow one connect to
|
| 588 | * follow another (if the first is in flight), and instead
|
| 589 | * just guarantee that a speed notification is always sent.
|
| 590 |
|
| 591 | ecm_notify(ecm);
|
| 592 | } else
|
| 593 | goto fail;
|
| 594 |
|
| 595 | return 0;
|
| 596 | fail:
|
| 597 | return -EINVAL;
|
| 598 | }
|
| 599 |
|
| 600 | |
| 601 | * this ECM function *MUST* implement a get_alt() method.
|
| 602 |
|
| 603 | static int ecm_get_alt(struct usb_function *f, unsigned intf)
|
| 604 | {
|
| 605 | struct f_ecm *ecm = func_to_ecm(f);
|
| 606 |
|
| 607 | if (intf == ecm->ctrl_id)
|
| 608 | return 0;
|
| 609 | return ecm->port.in_ep->enabled ? 1 : 0;
|
| 610 | }
|
| 611 |
|
| 612 | static void ecm_disable(struct usb_function *f)
|
| 613 | {
|
| 614 | struct f_ecm *ecm = func_to_ecm(f);
|
| 615 | struct usb_composite_dev *cdev = f->config->cdev;
|
| 616 |
|
| 617 | DBG(cdev, "ecm deactivated\n");
|
| 618 |
|
| 619 | if (ecm->port.in_ep->enabled) {
|
| 620 | gether_disconnect(&ecm->port);
|
| 621 | } else {
|
| 622 | ecm->port.in_ep->desc = NULL;
|
| 623 | ecm->port.out_ep->desc = NULL;
|
| 624 | }
|
| 625 |
|
| 626 | usb_ep_disable(ecm->notify);
|
| 627 | ecm->notify->desc = NULL;
|
| 628 | }
|
| 629 |
|
| 630 |
|
| 631 |
|
| 632 | |
| 633 | * Callbacks let us notify the host about connect/disconnect when the
|
| 634 | * net device is opened or closed.
|
| 635 | *
|
| 636 | * For testing, note that link states on this side include both opened
|
| 637 | * and closed variants of:
|
| 638 | *
|
| 639 | * - disconnected/unconfigured
|
| 640 | * - configured but inactive (data alt 0)
|
| 641 | * - configured and active (data alt 1)
|
| 642 | *
|
| 643 | * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and
|
| 644 | * SET_INTERFACE (altsetting). Remember also that "configured" doesn't
|
| 645 | * imply the host is actually polling the notification endpoint, and
|
| 646 | * likewise that "active" doesn't imply it's actually using the data
|
| 647 | * endpoints for traffic.
|
| 648 |
|
| 649 |
|
| 650 | static void ecm_open(struct gether *geth)
|
| 651 | {
|
| 652 | struct f_ecm *ecm = func_to_ecm(&geth->func);
|
| 653 |
|
| 654 | DBG(ecm->port.func.config->cdev, "%s\n", __func__);
|
| 655 |
|
| 656 | ecm->is_open = true;
|
| 657 | ecm_notify(ecm);
|
| 658 | }
|
| 659 |
|
| 660 | static void ecm_close(struct gether *geth)
|
| 661 | {
|
| 662 | struct f_ecm *ecm = func_to_ecm(&geth->func);
|
| 663 |
|
| 664 | DBG(ecm->port.func.config->cdev, "%s\n", __func__);
|
| 665 |
|
| 666 | ecm->is_open = false;
|
| 667 | ecm_notify(ecm);
|
| 668 | }
|
| 669 |
|
| 670 |
|
| 671 |
|
| 672 |
|
| 673 |
|
| 674 | static int
|
| 675 | ecm_bind(struct usb_configuration *c, struct usb_function *f)
|
| 676 | {
|
| 677 | struct usb_composite_dev *cdev = c->cdev;
|
| 678 | struct f_ecm *ecm = func_to_ecm(f);
|
| 679 | struct usb_string *us;
|
| 680 | int status = 0;
|
| 681 | struct usb_ep *ep;
|
| 682 |
|
| 683 | struct f_ecm_opts *ecm_opts;
|
| 684 | struct net_device *net __free(detach_gadget) = NULL;
|
| 685 | struct usb_request *request __free(free_usb_request) = NULL;
|
| 686 |
|
| 687 | if (!can_support_ecm(cdev->gadget))
|
| 688 | return -EINVAL;
|
| 689 |
|
| 690 | ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
|
| 691 |
|
| 692 | scoped_guard(mutex, &ecm_opts->lock)
|
| 693 | if (ecm_opts->bind_count == 0 && !ecm_opts->bound) {
|
| 694 | if (!device_is_registered(&ecm_opts->net->dev)) {
|
| 695 | gether_set_gadget(ecm_opts->net, cdev->gadget);
|
| 696 | status = gether_register_netdev(ecm_opts->net);
|
| 697 | } else
|
| 698 | status = gether_attach_gadget(ecm_opts->net, cdev->gadget);
|
| 699 |
|
| 700 | if (status)
|
| 701 | return status;
|
| 702 | net = ecm_opts->net;
|
| 703 | }
|
| 704 |
|
| 705 | ecm_string_defs[1].s = ecm->ethaddr;
|
| 706 |
|
| 707 | us = usb_gstrings_attach(cdev, ecm_strings,
|
| 708 | ARRAY_SIZE(ecm_string_defs));
|
| 709 | if (IS_ERR(us))
|
| 710 | return PTR_ERR(us);
|
| 711 | ecm_control_intf.iInterface = us[0].id;
|
| 712 | ecm_data_intf.iInterface = us[2].id;
|
| 713 | ecm_desc.iMACAddress = us[1].id;
|
| 714 | ecm_iad_descriptor.iFunction = us[3].id;
|
| 715 |
|
| 716 |
|
| 717 | status = usb_interface_id(c, f);
|
| 718 | if (status < 0)
|
| 719 | return status;
|
| 720 | ecm->ctrl_id = status;
|
| 721 | ecm_iad_descriptor.bFirstInterface = status;
|
| 722 |
|
| 723 | ecm_control_intf.bInterfaceNumber = status;
|
| 724 | ecm_union_desc.bMasterInterface0 = status;
|
| 725 |
|
| 726 | status = usb_interface_id(c, f);
|
| 727 | if (status < 0)
|
| 728 | return status;
|
| 729 | ecm->data_id = status;
|
| 730 |
|
| 731 | ecm_data_nop_intf.bInterfaceNumber = status;
|
| 732 | ecm_data_intf.bInterfaceNumber = status;
|
| 733 | ecm_union_desc.bSlaveInterface0 = status;
|
| 734 |
|
| 735 |
|
| 736 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc);
|
| 737 | if (!ep)
|
| 738 | return -ENODEV;
|
| 739 | ecm->port.in_ep = ep;
|
| 740 |
|
| 741 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
|
| 742 | if (!ep)
|
| 743 | return -ENODEV;
|
| 744 | ecm->port.out_ep = ep;
|
| 745 |
|
| 746 | |
| 747 | * don't treat it that way. It's simpler, and some newer CDC
|
| 748 | * profiles (wireless handsets) no longer treat it as optional.
|
| 749 |
|
| 750 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc);
|
| 751 | if (!ep)
|
| 752 | return -ENODEV;
|
| 753 | ecm->notify = ep;
|
| 754 |
|
| 755 |
|
| 756 | request = usb_ep_alloc_request(ep, GFP_KERNEL);
|
| 757 | if (!request)
|
| 758 | return -ENOMEM;
|
| 759 | request->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL);
|
| 760 | if (!request->buf)
|
| 761 | return -ENOMEM;
|
| 762 | request->context = ecm;
|
| 763 | request->complete = ecm_notify_complete;
|
| 764 |
|
| 765 | |
| 766 | * hardware is dual speed, all bulk-capable endpoints work at
|
| 767 | * both speeds
|
| 768 |
|
| 769 | hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
|
| 770 | hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
|
| 771 | hs_ecm_notify_desc.bEndpointAddress =
|
| 772 | fs_ecm_notify_desc.bEndpointAddress;
|
| 773 |
|
| 774 | ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
|
| 775 | ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
|
| 776 | ss_ecm_notify_desc.bEndpointAddress =
|
| 777 | fs_ecm_notify_desc.bEndpointAddress;
|
| 778 |
|
| 779 | status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
|
| 780 | ecm_ss_function, ecm_ss_function);
|
| 781 | if (status)
|
| 782 | return status;
|
| 783 |
|
| 784 | |
| 785 | * the network link ... which is unavailable to this code
|
| 786 | * until we're activated via set_alt().
|
| 787 |
|
| 788 |
|
| 789 | ecm->port.open = ecm_open;
|
| 790 | ecm->port.close = ecm_close;
|
| 791 |
|
| 792 | ecm->notify_req = no_free_ptr(request);
|
| 793 |
|
| 794 | ecm_opts->bind_count++;
|
| 795 | retain_and_null_ptr(net);
|
| 796 |
|
| 797 | DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n",
|
| 798 | ecm->port.in_ep->name, ecm->port.out_ep->name,
|
| 799 | ecm->notify->name);
|
| 800 | return 0;
|
| 801 | }
|
| 802 |
|
| 803 | static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)
|
| 804 | {
|
| 805 | return container_of(to_config_group(item), struct f_ecm_opts,
|
| 806 | func_inst.group);
|
| 807 | }
|
| 808 |
|
| 809 |
|
| 810 | USB_ETHERNET_CONFIGFS_ITEM(ecm);
|
| 811 |
|
| 812 |
|
| 813 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ecm);
|
| 814 |
|
| 815 |
|
| 816 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ecm);
|
| 817 |
|
| 818 |
|
| 819 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ecm);
|
| 820 |
|
| 821 |
|
| 822 | USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ecm);
|
| 823 |
|
| 824 | static struct configfs_attribute *ecm_attrs[] = {
|
| 825 | &ecm_opts_attr_dev_addr,
|
| 826 | &ecm_opts_attr_host_addr,
|
| 827 | &ecm_opts_attr_qmult,
|
| 828 | &ecm_opts_attr_ifname,
|
| 829 | NULL,
|
| 830 | };
|
| 831 |
|
| 832 | static const struct config_item_type ecm_func_type = {
|
| 833 | .ct_item_ops = &ecm_item_ops,
|
| 834 | .ct_attrs = ecm_attrs,
|
| 835 | .ct_owner = THIS_MODULE,
|
| 836 | };
|
| 837 |
|
| 838 | static void ecm_free_inst(struct usb_function_instance *f)
|
| 839 | {
|
| 840 | struct f_ecm_opts *opts;
|
| 841 |
|
| 842 | opts = container_of(f, struct f_ecm_opts, func_inst);
|
| 843 | if (device_is_registered(&opts->net->dev))
|
| 844 | gether_cleanup(netdev_priv(opts->net));
|
| 845 | else
|
| 846 | free_netdev(opts->net);
|
| 847 | kfree(opts);
|
| 848 | }
|
| 849 |
|
| 850 | static struct usb_function_instance *ecm_alloc_inst(void)
|
| 851 | {
|
| 852 | struct f_ecm_opts *opts;
|
| 853 |
|
| 854 | opts = kzalloc_obj(*opts);
|
| 855 | if (!opts)
|
| 856 | return ERR_PTR(-ENOMEM);
|
| 857 | mutex_init(&opts->lock);
|
| 858 | opts->func_inst.free_func_inst = ecm_free_inst;
|
| 859 | opts->net = gether_setup_default();
|
| 860 | if (IS_ERR(opts->net)) {
|
| 861 | struct net_device *net = opts->net;
|
| 862 | kfree(opts);
|
| 863 | return ERR_CAST(net);
|
| 864 | }
|
| 865 |
|
| 866 | config_group_init_type_name(&opts->func_inst.group, "", &ecm_func_type);
|
| 867 |
|
| 868 | return &opts->func_inst;
|
| 869 | }
|
| 870 |
|
| 871 | static void ecm_suspend(struct usb_function *f)
|
| 872 | {
|
| 873 | struct f_ecm *ecm = func_to_ecm(f);
|
| 874 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
| 875 |
|
| 876 | DBG(cdev, "ECM Suspend\n");
|
| 877 |
|
| 878 | gether_suspend(&ecm->port);
|
| 879 | }
|
| 880 |
|
| 881 | static void ecm_resume(struct usb_function *f)
|
| 882 | {
|
| 883 | struct f_ecm *ecm = func_to_ecm(f);
|
| 884 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
|
| 885 |
|
| 886 | DBG(cdev, "ECM Resume\n");
|
| 887 |
|
| 888 | gether_resume(&ecm->port);
|
| 889 | }
|
| 890 |
|
| 891 | static int ecm_get_status(struct usb_function *f)
|
| 892 | {
|
| 893 | return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) |
|
| 894 | USB_INTRF_STAT_FUNC_RW_CAP;
|
| 895 | }
|
| 896 |
|
| 897 | static void ecm_free(struct usb_function *f)
|
| 898 | {
|
| 899 | struct f_ecm *ecm;
|
| 900 | struct f_ecm_opts *opts;
|
| 901 |
|
| 902 | ecm = func_to_ecm(f);
|
| 903 | opts = container_of(f->fi, struct f_ecm_opts, func_inst);
|
| 904 | kfree(ecm);
|
| 905 | mutex_lock(&opts->lock);
|
| 906 | opts->refcnt--;
|
| 907 | mutex_unlock(&opts->lock);
|
| 908 | }
|
| 909 |
|
| 910 | static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)
|
| 911 | {
|
| 912 | struct f_ecm *ecm = func_to_ecm(f);
|
| 913 | struct f_ecm_opts *ecm_opts;
|
| 914 |
|
| 915 | DBG(c->cdev, "ecm unbind\n");
|
| 916 |
|
| 917 | ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst);
|
| 918 |
|
| 919 | usb_free_all_descriptors(f);
|
| 920 |
|
| 921 | if (atomic_read(&ecm->notify_count)) {
|
| 922 | usb_ep_dequeue(ecm->notify, ecm->notify_req);
|
| 923 | atomic_set(&ecm->notify_count, 0);
|
| 924 | }
|
| 925 |
|
| 926 | kfree(ecm->notify_req->buf);
|
| 927 | usb_ep_free_request(ecm->notify, ecm->notify_req);
|
| 928 |
|
| 929 | ecm_opts->bind_count--;
|
| 930 | if (ecm_opts->bind_count == 0 && !ecm_opts->bound)
|
| 931 | gether_detach_gadget(ecm_opts->net);
|
| 932 | }
|
| 933 |
|
| 934 | static struct usb_function *ecm_alloc(struct usb_function_instance *fi)
|
| 935 | {
|
| 936 | struct f_ecm *ecm;
|
| 937 | struct f_ecm_opts *opts;
|
| 938 | int status;
|
| 939 |
|
| 940 |
|
| 941 | ecm = kzalloc_obj(*ecm);
|
| 942 | if (!ecm)
|
| 943 | return ERR_PTR(-ENOMEM);
|
| 944 |
|
| 945 | opts = container_of(fi, struct f_ecm_opts, func_inst);
|
| 946 | mutex_lock(&opts->lock);
|
| 947 | opts->refcnt++;
|
| 948 |
|
| 949 |
|
| 950 | status = gether_get_host_addr_cdc(opts->net, ecm->ethaddr,
|
| 951 | sizeof(ecm->ethaddr));
|
| 952 | if (status < 12) {
|
| 953 | kfree(ecm);
|
| 954 | mutex_unlock(&opts->lock);
|
| 955 | return ERR_PTR(-EINVAL);
|
| 956 | }
|
| 957 |
|
| 958 | ecm->port.ioport = netdev_priv(opts->net);
|
| 959 | mutex_unlock(&opts->lock);
|
| 960 | ecm->port.cdc_filter = DEFAULT_FILTER;
|
| 961 |
|
| 962 | ecm->port.func.name = "cdc_ethernet";
|
| 963 |
|
| 964 | ecm->port.func.bind = ecm_bind;
|
| 965 | ecm->port.func.unbind = ecm_unbind;
|
| 966 | ecm->port.func.set_alt = ecm_set_alt;
|
| 967 | ecm->port.func.get_alt = ecm_get_alt;
|
| 968 | ecm->port.func.setup = ecm_setup;
|
| 969 | ecm->port.func.disable = ecm_disable;
|
| 970 | ecm->port.func.free_func = ecm_free;
|
| 971 | ecm->port.func.suspend = ecm_suspend;
|
| 972 | ecm->port.func.get_status = ecm_get_status;
|
| 973 | ecm->port.func.resume = ecm_resume;
|
| 974 |
|
| 975 | return &ecm->port.func;
|
| 976 | }
|
| 977 |
|
| 978 | DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);
|
| 979 | MODULE_DESCRIPTION("USB CDC Ethernet (ECM) link function driver");
|
| 980 | MODULE_LICENSE("GPL");
|
| 981 | MODULE_AUTHOR("David Brownell");
|