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
43 /*-------------------------------------------------------------------------*/
113 /* super speed support: */
160 .language = 0x0409, /* en-us */
169 /*-------------------------------------------------------------------------*/
173 struct usb_composite_dev *cdev = f->config->cdev; in eem_setup()
174 u16 w_index = le16_to_cpu(ctrl->wIndex); in eem_setup()
175 u16 w_value = le16_to_cpu(ctrl->wValue); in eem_setup()
176 u16 w_length = le16_to_cpu(ctrl->wLength); in eem_setup()
179 ctrl->bRequestType, ctrl->bRequest, in eem_setup()
183 return -EOPNOTSUPP; in eem_setup()
190 struct usb_composite_dev *cdev = f->config->cdev; in eem_set_alt()
197 if (intf == eem->ctrl_id) { in eem_set_alt()
199 gether_disconnect(&eem->port); in eem_set_alt()
201 if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) { in eem_set_alt()
203 if (config_ep_by_speed(cdev->gadget, f, in eem_set_alt()
204 eem->port.in_ep) || in eem_set_alt()
205 config_ep_by_speed(cdev->gadget, f, in eem_set_alt()
206 eem->port.out_ep)) { in eem_set_alt()
207 eem->port.in_ep->desc = NULL; in eem_set_alt()
208 eem->port.out_ep->desc = NULL; in eem_set_alt()
213 /* zlps should not occur because zero-length EEM packets in eem_set_alt()
216 eem->port.is_zlp_ok = 1; in eem_set_alt()
217 eem->port.cdc_filter = DEFAULT_FILTER; in eem_set_alt()
219 net = gether_connect(&eem->port); in eem_set_alt()
227 return -EINVAL; in eem_set_alt()
233 struct usb_composite_dev *cdev = f->config->cdev; in eem_disable()
237 if (eem->port.in_ep->enabled) in eem_disable()
238 gether_disconnect(&eem->port); in eem_disable()
241 /*-------------------------------------------------------------------------*/
247 struct usb_composite_dev *cdev = c->cdev; in eem_bind()
255 eem_opts = container_of(f->fi, struct f_eem_opts, func_inst); in eem_bind()
261 * with regard to eem_opts->bound access in eem_bind()
263 if (!eem_opts->bound) { in eem_bind()
264 mutex_lock(&eem_opts->lock); in eem_bind()
265 gether_set_gadget(eem_opts->net, cdev->gadget); in eem_bind()
266 status = gether_register_netdev(eem_opts->net); in eem_bind()
267 mutex_unlock(&eem_opts->lock); in eem_bind()
270 eem_opts->bound = true; in eem_bind()
279 /* allocate instance-specific interface IDs */ in eem_bind()
283 eem->ctrl_id = status; in eem_bind()
286 status = -ENODEV; in eem_bind()
288 /* allocate instance-specific endpoints */ in eem_bind()
289 ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc); in eem_bind()
292 eem->port.in_ep = ep; in eem_bind()
294 ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc); in eem_bind()
297 eem->port.out_ep = ep; in eem_bind()
300 * hardware is dual speed, all bulk-capable endpoints work at in eem_bind()
315 eem->port.in_ep->name, eem->port.out_ep->name); in eem_bind()
319 ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); in eem_bind()
326 struct in_context *ctx = req->context; in eem_cmd_complete()
328 dev_kfree_skb_any(ctx->skb); in eem_cmd_complete()
329 kfree(req->buf); in eem_cmd_complete()
330 usb_ep_free_request(ctx->ep, req); in eem_cmd_complete()
336 * We currently do not attempt to put multiple ethernet frames
342 struct usb_ep *in = port->in_ep; in eem_wrap()
349 len = skb->len; in eem_wrap()
353 /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, in eem_wrap()
354 * stick two bytes of zero-length EEM packet on the end. in eem_wrap()
356 if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0) in eem_wrap()
378 len = skb->len; in eem_wrap()
381 /* add a zero-length EEM packet, if needed */ in eem_wrap()
396 struct usb_composite_dev *cdev = port->func.config->cdev; in eem_unwrap()
404 if (skb->len < EEM_HLEN) { in eem_unwrap()
405 status = -EINVAL; in eem_unwrap()
411 header = get_unaligned_le16(skb->data); in eem_unwrap()
437 if (skb->len < len) { in eem_unwrap()
438 status = -EOVERFLOW; in eem_unwrap()
451 ep = port->in_ep; in eem_unwrap()
458 req->buf = kmalloc(skb2->len, GFP_KERNEL); in eem_unwrap()
459 if (!req->buf) { in eem_unwrap()
467 kfree(req->buf); in eem_unwrap()
472 ctx->skb = skb2; in eem_unwrap()
473 ctx->ep = ep; in eem_unwrap()
475 skb_copy_bits(skb2, 0, req->buf, skb2->len); in eem_unwrap()
476 req->length = skb2->len; in eem_unwrap()
477 req->complete = eem_cmd_complete; in eem_unwrap()
478 req->zero = 1; in eem_unwrap()
479 req->context = ctx; in eem_unwrap()
480 if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC)) 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 (opts->bound) 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()
638 DBG(c->cdev, "eem unbind\n"); in eem_unbind()
651 return ERR_PTR(-ENOMEM); in eem_alloc()
654 mutex_lock(&opts->lock); in eem_alloc()
655 opts->refcnt++; in eem_alloc()
657 eem->port.ioport = netdev_priv(opts->net); in eem_alloc()
658 mutex_unlock(&opts->lock); in eem_alloc()
659 eem->port.cdc_filter = DEFAULT_FILTER; in eem_alloc()
661 eem->port.func.name = "cdc_eem"; in eem_alloc()
662 /* descriptors are per-instance copies */ in eem_alloc()
663 eem->port.func.bind = eem_bind; in eem_alloc()
664 eem->port.func.unbind = eem_unbind; in eem_alloc()
665 eem->port.func.set_alt = eem_set_alt; in eem_alloc()
666 eem->port.func.setup = eem_setup; in eem_alloc()
667 eem->port.func.disable = eem_disable; in eem_alloc()
668 eem->port.func.free_func = eem_free; in eem_alloc()
669 eem->port.wrap = eem_wrap; in eem_alloc()
670 eem->port.unwrap = eem_unwrap; in eem_alloc()
671 eem->port.header_len = EEM_HLEN; in eem_alloc()
673 return &eem->port.func; in eem_alloc()