Lines Matching +full:super +full:- +full:frames
1 // SPDX-License-Identifier: GPL-2.0+
3 * f_eem.c -- USB CDC Ethernet (EEM) link function driver
5 * Copyright (C) 2003-2005,2008 David Brownell
44 /*-------------------------------------------------------------------------*/
114 /* super speed support: */
161 .language = 0x0409, /* en-us */
170 /*-------------------------------------------------------------------------*/
174 struct usb_composite_dev *cdev = f->config->cdev; in eem_setup()
175 u16 w_index = le16_to_cpu(ctrl->wIndex); in eem_setup()
176 u16 w_value = le16_to_cpu(ctrl->wValue); in eem_setup()
177 u16 w_length = le16_to_cpu(ctrl->wLength); in eem_setup()
180 ctrl->bRequestType, ctrl->bRequest, in eem_setup()
184 return -EOPNOTSUPP; in eem_setup()
191 struct usb_composite_dev *cdev = f->config->cdev; in eem_set_alt()
198 if (intf == eem->ctrl_id) { in eem_set_alt()
200 gether_disconnect(&eem->port); in eem_set_alt()
202 if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) { in eem_set_alt()
204 if (config_ep_by_speed(cdev->gadget, f, in eem_set_alt()
205 eem->port.in_ep) || in eem_set_alt()
206 config_ep_by_speed(cdev->gadget, f, in eem_set_alt()
207 eem->port.out_ep)) { in eem_set_alt()
208 eem->port.in_ep->desc = NULL; in eem_set_alt()
209 eem->port.out_ep->desc = NULL; in eem_set_alt()
214 /* zlps should not occur because zero-length EEM packets in eem_set_alt()
217 eem->port.is_zlp_ok = 1; in eem_set_alt()
218 eem->port.cdc_filter = DEFAULT_FILTER; in eem_set_alt()
220 net = gether_connect(&eem->port); in eem_set_alt()
228 return -EINVAL; in eem_set_alt()
234 struct usb_composite_dev *cdev = f->config->cdev; in eem_disable()
238 if (eem->port.in_ep->enabled) in eem_disable()
239 gether_disconnect(&eem->port); in eem_disable()
242 /*-------------------------------------------------------------------------*/
248 struct usb_composite_dev *cdev = c->cdev; in eem_bind()
257 eem_opts = container_of(f->fi, struct f_eem_opts, func_inst); in eem_bind()
259 scoped_guard(mutex, &eem_opts->lock) in eem_bind()
260 if (eem_opts->bind_count == 0 && !eem_opts->bound) { in eem_bind()
261 if (!device_is_registered(&eem_opts->net->dev)) { in eem_bind()
262 gether_set_gadget(eem_opts->net, cdev->gadget); in eem_bind()
263 status = gether_register_netdev(eem_opts->net); in eem_bind()
265 status = gether_attach_gadget(eem_opts->net, cdev->gadget); in eem_bind()
269 net = eem_opts->net; in eem_bind()
278 /* allocate instance-specific interface IDs */ in eem_bind()
282 eem->ctrl_id = status; in eem_bind()
285 /* allocate instance-specific endpoints */ in eem_bind()
286 ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc); in eem_bind()
288 return -ENODEV; in eem_bind()
289 eem->port.in_ep = ep; in eem_bind()
291 ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc); in eem_bind()
293 return -ENODEV; in eem_bind()
294 eem->port.out_ep = ep; in eem_bind()
297 * hardware is dual speed, all bulk-capable endpoints work at in eem_bind()
311 eem_opts->bind_count++; in eem_bind()
315 eem->port.in_ep->name, eem->port.out_ep->name); in eem_bind()
321 struct in_context *ctx = req->context; in eem_cmd_complete()
323 dev_kfree_skb_any(ctx->skb); in eem_cmd_complete()
324 kfree(req->buf); in eem_cmd_complete()
325 usb_ep_free_request(ctx->ep, req); in eem_cmd_complete()
331 * We currently do not attempt to put multiple ethernet frames
337 struct usb_ep *in = port->in_ep; in eem_wrap()
344 len = skb->len; in eem_wrap()
348 /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, in eem_wrap()
349 * stick two bytes of zero-length EEM packet on the end. in eem_wrap()
351 if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0) in eem_wrap()
373 len = skb->len; in eem_wrap()
376 /* add a zero-length EEM packet, if needed */ in eem_wrap()
391 struct usb_composite_dev *cdev = port->func.config->cdev; in eem_unwrap()
399 if (skb->len < EEM_HLEN) { in eem_unwrap()
400 status = -EINVAL; in eem_unwrap()
406 header = get_unaligned_le16(skb->data); in eem_unwrap()
432 if (skb->len < len) { in eem_unwrap()
433 status = -EOVERFLOW; in eem_unwrap()
446 ep = port->in_ep; in eem_unwrap()
453 req->buf = kmalloc(skb2->len, GFP_KERNEL); in eem_unwrap()
454 if (!req->buf) { in eem_unwrap()
462 kfree(req->buf); in eem_unwrap()
467 ctx->skb = skb2; in eem_unwrap()
468 ctx->ep = ep; in eem_unwrap()
470 skb_copy_bits(skb2, 0, req->buf, skb2->len); in eem_unwrap()
471 req->length = skb2->len; in eem_unwrap()
472 req->complete = eem_cmd_complete; in eem_unwrap()
473 req->zero = 1; in eem_unwrap()
474 req->context = ctx; in eem_unwrap()
475 if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC)) { in eem_unwrap()
478 kfree(req->buf); in eem_unwrap()
496 /* check for zero-length EEM packet */ in eem_unwrap()
506 if ((skb->len < len) in eem_unwrap()
508 status = -EINVAL; in eem_unwrap()
514 crc = get_unaligned_le32(skb->data + len in eem_unwrap()
515 - ETH_FCS_LEN); in eem_unwrap()
517 skb->data, len - ETH_FCS_LEN); in eem_unwrap()
519 crc = get_unaligned_be32(skb->data + len in eem_unwrap()
520 - ETH_FCS_LEN); in eem_unwrap()
533 skb_trim(skb2, len - ETH_FCS_LEN); in eem_unwrap()
548 } while (skb->len); in eem_unwrap()
595 if (device_is_registered(&opts->net->dev)) in eem_free_inst()
596 gether_cleanup(netdev_priv(opts->net)); in eem_free_inst()
598 free_netdev(opts->net); in eem_free_inst()
608 return ERR_PTR(-ENOMEM); in eem_alloc_inst()
609 mutex_init(&opts->lock); in eem_alloc_inst()
610 opts->func_inst.free_func_inst = eem_free_inst; in eem_alloc_inst()
611 opts->net = gether_setup_default(); in eem_alloc_inst()
612 if (IS_ERR(opts->net)) { in eem_alloc_inst()
613 struct net_device *net = opts->net; in eem_alloc_inst()
618 config_group_init_type_name(&opts->func_inst.group, "", &eem_func_type); in eem_alloc_inst()
620 return &opts->func_inst; in eem_alloc_inst()
629 opts = container_of(f->fi, struct f_eem_opts, func_inst); in eem_free()
631 mutex_lock(&opts->lock); in eem_free()
632 opts->refcnt--; in eem_free()
633 mutex_unlock(&opts->lock); in eem_free()
640 DBG(c->cdev, "eem unbind\n"); in eem_unbind()
642 opts = container_of(f->fi, struct f_eem_opts, func_inst); in eem_unbind()
646 opts->bind_count--; in eem_unbind()
647 if (opts->bind_count == 0 && !opts->bound) in eem_unbind()
648 gether_detach_gadget(opts->net); in eem_unbind()
659 return ERR_PTR(-ENOMEM); in eem_alloc()
662 mutex_lock(&opts->lock); in eem_alloc()
663 opts->refcnt++; in eem_alloc()
665 eem->port.ioport = netdev_priv(opts->net); in eem_alloc()
666 mutex_unlock(&opts->lock); in eem_alloc()
667 eem->port.cdc_filter = DEFAULT_FILTER; in eem_alloc()
669 eem->port.func.name = "cdc_eem"; in eem_alloc()
670 /* descriptors are per-instance copies */ in eem_alloc()
671 eem->port.func.bind = eem_bind; in eem_alloc()
672 eem->port.func.unbind = eem_unbind; in eem_alloc()
673 eem->port.func.set_alt = eem_set_alt; in eem_alloc()
674 eem->port.func.setup = eem_setup; in eem_alloc()
675 eem->port.func.disable = eem_disable; in eem_alloc()
676 eem->port.func.free_func = eem_free; in eem_alloc()
677 eem->port.wrap = eem_wrap; in eem_alloc()
678 eem->port.unwrap = eem_unwrap; in eem_alloc()
679 eem->port.header_len = EEM_HLEN; in eem_alloc()
681 return &eem->port.func; in eem_alloc()