Lines Matching +full:cdc +full:- +full:acm

1 // SPDX-License-Identifier: GPL-2.0+
3 * f_rndis.c -- RNDIS link function driver
5 * Copyright (C) 2003-2005,2008 David Brownell
6 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
29 * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
30 * been promoted instead of the standard CDC Ethernet. The published RNDIS
36 * doesn't support the CDC Ethernet standard.
40 * what's essentially an "RNDIS RPC" protocol. It's all wrapped in a CDC ACM
41 * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
46 * There is a single technical advantage of RNDIS over CDC Ethernet, if you
53 * have all sorts of contrary-to-specification oddities that can prevent
60 * - Power management ... references data that's scattered around lots
63 * - There are various undocumented protocol requirements, like the need
64 * to send garbage in some control-OUT messages.
66 * - MS-Windows drivers sometimes emit undocumented requests.
87 /*-------------------------------------------------------------------------*/
203 /* control interface matches ACM, not Ethernet */
251 /* control interface matches ACM, not Ethernet */
318 /* control interface matches ACM, not Ethernet */
346 .language = 0x0409, /* en-us */
355 /*-------------------------------------------------------------------------*/
375 struct usb_request *req = rndis->notify_req; in rndis_response_available()
376 struct usb_composite_dev *cdev = rndis->port.func.config->cdev; in rndis_response_available()
377 __le32 *data = req->buf; in rndis_response_available()
380 if (atomic_inc_return(&rndis->notify_count) != 1) in rndis_response_available()
391 status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); in rndis_response_available()
393 atomic_dec(&rndis->notify_count); in rndis_response_available()
394 DBG(cdev, "notify/0 --> %d\n", status); in rndis_response_available()
400 struct f_rndis *rndis = req->context; in rndis_response_complete()
401 struct usb_composite_dev *cdev = rndis->port.func.config->cdev; in rndis_response_complete()
402 int status = req->status; in rndis_response_complete()
405 * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) in rndis_response_complete()
406 * - RNDIS_RESPONSE_AVAILABLE (status/irq) in rndis_response_complete()
409 case -ECONNRESET: in rndis_response_complete()
410 case -ESHUTDOWN: in rndis_response_complete()
412 atomic_set(&rndis->notify_count, 0); in rndis_response_complete()
416 ep->name, status, in rndis_response_complete()
417 req->actual, req->length); in rndis_response_complete()
420 if (ep != rndis->notify) in rndis_response_complete()
426 if (atomic_dec_and_test(&rndis->notify_count)) in rndis_response_complete()
428 status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); in rndis_response_complete()
430 atomic_dec(&rndis->notify_count); in rndis_response_complete()
431 DBG(cdev, "notify/1 --> %d\n", status); in rndis_response_complete()
439 struct f_rndis *rndis = req->context; in rndis_command_complete()
443 // spin_lock(&dev->lock); in rndis_command_complete()
444 status = rndis_msg_parser(rndis->params, (u8 *) req->buf); in rndis_command_complete()
447 status, req->actual, req->length); in rndis_command_complete()
448 // spin_unlock(&dev->lock); in rndis_command_complete()
455 struct usb_composite_dev *cdev = f->config->cdev; in rndis_setup()
456 struct usb_request *req = cdev->req; in rndis_setup()
457 int value = -EOPNOTSUPP; in rndis_setup()
458 u16 w_index = le16_to_cpu(ctrl->wIndex); in rndis_setup()
459 u16 w_value = le16_to_cpu(ctrl->wValue); in rndis_setup()
460 u16 w_length = le16_to_cpu(ctrl->wLength); in rndis_setup()
463 * CDC class messages; interface activation uses set_alt(). in rndis_setup()
465 switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { in rndis_setup()
467 /* RNDIS uses the CDC command encapsulation mechanism to implement in rndis_setup()
472 if (w_value || w_index != rndis->ctrl_id) in rndis_setup()
476 req->complete = rndis_command_complete; in rndis_setup()
477 req->context = rndis; in rndis_setup()
483 if (w_value || w_index != rndis->ctrl_id) in rndis_setup()
490 buf = rndis_get_next_response(rndis->params, &n); in rndis_setup()
492 memcpy(req->buf, buf, n); in rndis_setup()
493 req->complete = rndis_response_complete; in rndis_setup()
494 req->context = rndis; in rndis_setup()
495 rndis_free_response(rndis->params, buf); in rndis_setup()
505 ctrl->bRequestType, ctrl->bRequest, in rndis_setup()
512 ctrl->bRequestType, ctrl->bRequest, in rndis_setup()
514 req->zero = (value < w_length); in rndis_setup()
515 req->length = value; in rndis_setup()
516 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); in rndis_setup()
529 struct usb_composite_dev *cdev = f->config->cdev; in rndis_set_alt()
533 if (intf == rndis->ctrl_id) { in rndis_set_alt()
535 usb_ep_disable(rndis->notify); in rndis_set_alt()
537 if (!rndis->notify->desc) { in rndis_set_alt()
539 if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) in rndis_set_alt()
542 usb_ep_enable(rndis->notify); in rndis_set_alt()
544 } else if (intf == rndis->data_id) { in rndis_set_alt()
547 if (rndis->port.in_ep->enabled) { in rndis_set_alt()
549 gether_disconnect(&rndis->port); in rndis_set_alt()
552 if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { in rndis_set_alt()
554 if (config_ep_by_speed(cdev->gadget, f, in rndis_set_alt()
555 rndis->port.in_ep) || in rndis_set_alt()
556 config_ep_by_speed(cdev->gadget, f, in rndis_set_alt()
557 rndis->port.out_ep)) { in rndis_set_alt()
558 rndis->port.in_ep->desc = NULL; in rndis_set_alt()
559 rndis->port.out_ep->desc = NULL; in rndis_set_alt()
565 rndis->port.is_zlp_ok = false; in rndis_set_alt()
577 * code -- gether_updown(...bool) maybe -- to do it right. in rndis_set_alt()
579 rndis->port.cdc_filter = 0; in rndis_set_alt()
582 net = gether_connect(&rndis->port); in rndis_set_alt()
586 rndis_set_param_dev(rndis->params, net, in rndis_set_alt()
587 &rndis->port.cdc_filter); in rndis_set_alt()
593 return -EINVAL; in rndis_set_alt()
599 struct usb_composite_dev *cdev = f->config->cdev; in rndis_disable()
601 if (!rndis->notify->enabled) in rndis_disable()
606 rndis_uninit(rndis->params); in rndis_disable()
607 gether_disconnect(&rndis->port); in rndis_disable()
609 usb_ep_disable(rndis->notify); in rndis_disable()
610 rndis->notify->desc = NULL; in rndis_disable()
613 /*-------------------------------------------------------------------------*/
616 * This isn't quite the same mechanism as CDC Ethernet, since the
624 struct f_rndis *rndis = func_to_rndis(&geth->func); in rndis_open()
625 struct usb_composite_dev *cdev = geth->func.config->cdev; in rndis_open()
629 rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, in rndis_open()
630 gether_bitrate(cdev->gadget) / 100); in rndis_open()
631 rndis_signal_connect(rndis->params); in rndis_open()
636 struct f_rndis *rndis = func_to_rndis(&geth->func); in rndis_close()
638 DBG(geth->func.config->cdev, "%s\n", __func__); in rndis_close()
640 rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0); in rndis_close()
641 rndis_signal_disconnect(rndis->params); in rndis_close()
644 /*-------------------------------------------------------------------------*/
658 struct usb_composite_dev *cdev = c->cdev; in rndis_bind()
667 return -EINVAL; in rndis_bind()
669 rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); in rndis_bind()
671 if (cdev->use_os_string) { in rndis_bind()
672 f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), in rndis_bind()
674 if (!f->os_desc_table) in rndis_bind()
675 return -ENOMEM; in rndis_bind()
676 f->os_desc_n = 1; in rndis_bind()
677 f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; in rndis_bind()
680 rndis_iad_descriptor.bFunctionClass = rndis_opts->class; in rndis_bind()
681 rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; in rndis_bind()
682 rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; in rndis_bind()
689 * with regard to rndis_opts->bound access in rndis_bind()
691 if (!rndis_opts->bound) { in rndis_bind()
692 gether_set_gadget(rndis_opts->net, cdev->gadget); in rndis_bind()
693 status = gether_register_netdev(rndis_opts->net); in rndis_bind()
696 rndis_opts->bound = true; in rndis_bind()
709 /* allocate instance-specific interface IDs */ in rndis_bind()
713 rndis->ctrl_id = status; in rndis_bind()
719 if (cdev->use_os_string) in rndis_bind()
720 f->os_desc_table[0].if_id = in rndis_bind()
726 rndis->data_id = status; in rndis_bind()
731 status = -ENODEV; in rndis_bind()
733 /* allocate instance-specific endpoints */ in rndis_bind()
734 ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc); in rndis_bind()
737 rndis->port.in_ep = ep; in rndis_bind()
739 ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc); in rndis_bind()
742 rndis->port.out_ep = ep; in rndis_bind()
748 ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc); in rndis_bind()
751 rndis->notify = ep; in rndis_bind()
753 status = -ENOMEM; in rndis_bind()
756 rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); in rndis_bind()
757 if (!rndis->notify_req) in rndis_bind()
759 rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL); in rndis_bind()
760 if (!rndis->notify_req->buf) in rndis_bind()
762 rndis->notify_req->length = STATUS_BYTECOUNT; in rndis_bind()
763 rndis->notify_req->context = rndis; in rndis_bind()
764 rndis->notify_req->complete = rndis_response_complete; in rndis_bind()
767 * hardware is dual speed, all bulk-capable endpoints work at in rndis_bind()
783 rndis->port.open = rndis_open; in rndis_bind()
784 rndis->port.close = rndis_close; in rndis_bind()
786 rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0); in rndis_bind()
787 rndis_set_host_mac(rndis->params, rndis->ethaddr); in rndis_bind()
789 if (rndis->manufacturer && rndis->vendorID && in rndis_bind()
790 rndis_set_param_vendor(rndis->params, rndis->vendorID, in rndis_bind()
791 rndis->manufacturer)) { in rndis_bind()
792 status = -EINVAL; in rndis_bind()
802 rndis->port.in_ep->name, rndis->port.out_ep->name, in rndis_bind()
803 rndis->notify->name); in rndis_bind()
809 kfree(f->os_desc_table); in rndis_bind()
810 f->os_desc_n = 0; in rndis_bind()
812 if (rndis->notify_req) { in rndis_bind()
813 kfree(rndis->notify_req->buf); in rndis_bind()
814 usb_ep_free_request(rndis->notify, rndis->notify_req); in rndis_bind()
817 ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); in rndis_bind()
827 if (opts->bound) in rndis_borrow_net()
828 gether_cleanup(netdev_priv(opts->net)); in rndis_borrow_net()
830 free_netdev(opts->net); in rndis_borrow_net()
831 opts->borrowed_net = opts->bound = true; in rndis_borrow_net()
832 opts->net = net; in rndis_borrow_net()
888 if (!opts->borrowed_net) { in rndis_free_inst()
889 if (opts->bound) in rndis_free_inst()
890 gether_cleanup(netdev_priv(opts->net)); in rndis_free_inst()
892 free_netdev(opts->net); in rndis_free_inst()
895 kfree(opts->rndis_interf_group); /* single VLA chunk */ in rndis_free_inst()
908 return ERR_PTR(-ENOMEM); in rndis_alloc_inst()
909 opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; in rndis_alloc_inst()
911 mutex_init(&opts->lock); in rndis_alloc_inst()
912 opts->func_inst.free_func_inst = rndis_free_inst; in rndis_alloc_inst()
913 opts->net = gether_setup_default(); in rndis_alloc_inst()
914 if (IS_ERR(opts->net)) { in rndis_alloc_inst()
915 struct net_device *net = opts->net; in rndis_alloc_inst()
919 INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); in rndis_alloc_inst()
921 opts->class = rndis_iad_descriptor.bFunctionClass; in rndis_alloc_inst()
922 opts->subclass = rndis_iad_descriptor.bFunctionSubClass; in rndis_alloc_inst()
923 opts->protocol = rndis_iad_descriptor.bFunctionProtocol; in rndis_alloc_inst()
925 descs[0] = &opts->rndis_os_desc; in rndis_alloc_inst()
927 config_group_init_type_name(&opts->func_inst.group, "", in rndis_alloc_inst()
930 usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, in rndis_alloc_inst()
933 rndis_free_inst(&opts->func_inst); in rndis_alloc_inst()
936 opts->rndis_interf_group = rndis_interf_group; in rndis_alloc_inst()
938 return &opts->func_inst; in rndis_alloc_inst()
947 rndis_deregister(rndis->params); in rndis_free()
948 opts = container_of(f->fi, struct f_rndis_opts, func_inst); in rndis_free()
950 mutex_lock(&opts->lock); in rndis_free()
951 opts->refcnt--; in rndis_free()
952 mutex_unlock(&opts->lock); in rndis_free()
959 kfree(f->os_desc_table); in rndis_unbind()
960 f->os_desc_n = 0; in rndis_unbind()
963 kfree(rndis->notify_req->buf); in rndis_unbind()
964 usb_ep_free_request(rndis->notify, rndis->notify_req); in rndis_unbind()
976 return ERR_PTR(-ENOMEM); in rndis_alloc()
979 mutex_lock(&opts->lock); in rndis_alloc()
980 opts->refcnt++; in rndis_alloc()
982 gether_get_host_addr_u8(opts->net, rndis->ethaddr); in rndis_alloc()
983 rndis->vendorID = opts->vendor_id; in rndis_alloc()
984 rndis->manufacturer = opts->manufacturer; in rndis_alloc()
986 rndis->port.ioport = netdev_priv(opts->net); in rndis_alloc()
987 mutex_unlock(&opts->lock); in rndis_alloc()
989 rndis->port.cdc_filter = 0; in rndis_alloc()
992 rndis->port.header_len = sizeof(struct rndis_packet_msg_type); in rndis_alloc()
993 rndis->port.wrap = rndis_add_header; in rndis_alloc()
994 rndis->port.unwrap = rndis_rm_hdr; in rndis_alloc()
996 rndis->port.func.name = "rndis"; in rndis_alloc()
997 /* descriptors are per-instance copies */ in rndis_alloc()
998 rndis->port.func.bind = rndis_bind; in rndis_alloc()
999 rndis->port.func.unbind = rndis_unbind; in rndis_alloc()
1000 rndis->port.func.set_alt = rndis_set_alt; in rndis_alloc()
1001 rndis->port.func.setup = rndis_setup; in rndis_alloc()
1002 rndis->port.func.disable = rndis_disable; in rndis_alloc()
1003 rndis->port.func.free_func = rndis_free; in rndis_alloc()
1010 rndis->params = params; in rndis_alloc()
1012 return &rndis->port.func; in rndis_alloc()