1/****************************************************************************
2 * drivers/usbdev/composite.c
3 *
4 *   Copyright (C) 2012, 2016-2017 Gregory Nutt. All rights reserved.
5 *   Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
6 *   Author: Gregory Nutt <gnutt@nuttx.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 * 3. Neither the name NuttX nor the names of its contributors may be
19 *    used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36/****************************************************************************
37 * Notice of Export Control Law
38 * ===============================================
39 * Huawei LiteOS may be subject to applicable export control laws and regulations,
40 * which might include those applicable to Huawei LiteOS of U.S. and the country in
41 * which you are located.
42 * Import, export and usage of Huawei LiteOS in any manner by you shall be in
43 * compliance with such applicable export control laws and regulations.
44 ****************************************************************************/
45
46/****************************************************************************
47 * Included Files
48 ****************************************************************************/
49#include "los_vm_iomap.h"
50#include "gadget/composite.h"
51#define FCOFNIG_FUN
52
53#undef USB_DEBUG_VAR
54#define USB_DEBUG_VAR g_composite_debug
55#ifdef LOSCFG_USB_DEBUG
56static int g_composite_debug = 0;
57void usb_composite_debug_func(int level)
58{
59  g_composite_debug = level;
60  PRINTK("The level of usb composite debug is %d\n", level);
61}
62DEBUG_MODULE(composite, usb_composite_debug_func);
63#endif
64
65int composite_device_init(struct composite_softc *cdev);
66
67static const uint8_t g_bos_desc_buf[22] =
68{
69  5, 0xf, 0x16, 0, 2, 7, 0x10, 2, 6, 0, 0, 0,
70  0xa, 0x10, 3, 0, 0xf, 0, 1, 1, 0xf4, 1
71};
72
73static device_probe_t  composite_probe;
74static device_attach_t composite_attach;
75static device_detach_t composite_detach;
76static devclass_t      composite_devclass;
77
78static device_method_t g_composite_methods[] =
79{
80  /* Device interface */
81
82  DEVMETHOD(device_probe,  composite_probe),
83  DEVMETHOD(device_attach, composite_attach),
84  DEVMETHOD(device_detach, composite_detach),
85  DEVMETHOD_END
86};
87
88static driver_t g_composite_driver =
89{
90  .name    = "composite",
91  .methods = g_composite_methods,
92  .size    = sizeof(struct composite_softc)
93};
94
95DRIVER_MODULE(composite, hiudc3, g_composite_driver, composite_devclass, NULL, NULL);
96
97void usbd_configep_byspeed(struct usbdev_s *dev, struct usb_endpoint_descriptor *ep_desc)
98{
99  if (ep_desc->bmAttributes == UE_BULK)
100    {
101      switch (dev->speed)
102        {
103        case USB_SPEED_SUPER:
104          USETW(ep_desc->wMaxPacketSize, USB_DWC_MAX_PACKET_SIZE);
105          break;
106
107        case USB_SPEED_HIGH:
108          USETW(ep_desc->wMaxPacketSize, USB_DWC_U2_MAX_PACKET_SIZE);
109          break;
110
111        default:
112          PRINT_ERR("%s invalid speed:%u\r\n", __FUNCTION__, dev->speed);
113          break;
114        }
115    }
116
117  return;
118}
119
120void composite_request_complete(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
121{
122  (void)ep;
123  (void)req;
124}
125
126static struct usbdev_req_s *composite_allocreq(uint16_t len)
127{
128  DMA_ADDR_T paddr;
129  struct usbdev_req_s *req = zalloc(sizeof(struct usbdev_req_s));
130  if (req != NULL)
131    {
132      req->len = len;
133      req->buf = (uint8_t *)LOS_DmaMemAlloc(&paddr, len, USB_CACHE_ALIGN_SIZE, DMA_NOCACHE);
134      if (req->buf == NULL)
135        {
136          free(req);
137          return NULL;
138        }
139      req->dma = (DMA_ADDR_T)VMM_TO_UNCACHED_ADDR((unsigned long)req->buf);
140    }
141
142  return req;
143}
144
145static void composite_freereq(struct usbdev_req_s *req)
146{
147  if (req != NULL)
148    {
149      if (req->buf != NULL)
150        {
151          (VOID)LOS_DmaMemFree(req->buf);
152          req->buf = NULL;
153        }
154      free(req);
155    }
156}
157
158static int usb_composite_unbind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev)
159{
160  struct composite_dev_s *cdev;
161  int ret;
162
163  if (driver == NULL || dev == NULL)
164    {
165      PRINT_ERR("unbind fail, invalid gadget\n");
166      return -1;
167    }
168
169  cdev = ((struct composite_driver_s *)driver)->dev;
170
171  /* Make sure that we are not already unbound */
172
173  if (cdev != NULL)
174    {
175      int i;
176
177      /* Unbind the constituent class drivers */
178
179      for (i = 0; i < cdev->ndevices; i++)
180        {
181          ret = CLASS_UNBIND(cdev->device[i].dev, dev);
182          if (ret < 0)
183            {
184              PRINT_ERR("unbind gadget fail, busy!\n");
185              return -1;
186            }
187        }
188
189      /* Free the pre-allocated control request */
190
191      cdev->config = COMPOSITE_CONFIGIDNONE;
192      composite_freereq(cdev->ctrlreq);
193      cdev->ctrlreq = NULL;
194      cdev->usbdev  = NULL;
195    }
196  dev->ep0->priv = NULL;
197
198  return 0;
199}
200
201static int usb_composite_bind(struct usbdevclass_driver_s *driver, struct usbdev_s *dev)
202{
203  struct composite_dev_s *cdev;
204  int ret;
205  int i;
206
207  if (driver == NULL || dev == NULL)
208    {
209      return -1;
210    }
211  cdev = ((struct composite_driver_s *)driver)->dev;
212  if (cdev == NULL)
213    {
214      PRINT_ERR("cdev == NULL\n");
215      return -1;
216    }
217
218  /* Bind the structures */
219
220  cdev->usbdev = dev;
221
222  /* initialize ctrlreq and allocate memory for it's buf */
223
224  cdev->ctrlreq = composite_allocreq(USB_COMP_EP0_BUFSIZ);
225  if (cdev->ctrlreq == NULL)
226    {
227      PRINT_ERR("%s malloc control request buf failed!\n", __FUNCTION__);
228      goto failed;
229    }
230  dev->ep0->handle_req    = cdev->ctrlreq;
231  cdev->ctrlreq->callback = composite_request_complete;
232
233  /* Save the reference to our private data structure in EP0 so that it
234   * can be recovered in ep0 completion events.
235   */
236  dev->ep0->priv = cdev;
237  for (i = 0; i < cdev->ndevices; i++)
238    {
239      ret = CLASS_BIND(cdev->device[i].dev, dev);
240      if (ret < 0)
241        {
242          PRINT_ERR(" composite device bind gadget failed!\n");
243          goto failed;
244        }
245    }
246
247  DPRINTF("composite bind device success!\n");
248  return 0;
249
250failed:
251  (void)usb_composite_unbind(driver, dev);
252  return -1;
253}
254
255static int modify_config_descriptor_byspeed(struct usbdev_s *dev, struct usbdev_req_s *req)
256{
257  struct usb_descriptor *descriptors;
258  uint32_t config_len = req->len;
259  uint32_t new_config_len;
260  uint8_t *config_tmp_buf;
261  struct usb_config_descriptor *config_des;
262  uint32_t i;
263  int ret;
264
265  if (dev->speed != USB_SPEED_SUPER && dev->speed != USB_SPEED_HIGH)
266    {
267      usb_err("Device controller speed can not support!\n");
268      return -EINVAL;
269    }
270
271  if (dev->speed == USB_SPEED_SUPER)
272    {
273      return 0; /* The configuration descriptor defaults to the superspeed form. */
274    }
275
276  config_tmp_buf = malloc(config_len);
277  if (config_tmp_buf == NULL)
278    {
279      usb_err("malloc failed\n");
280      return -ENOMEM;
281    }
282
283  ret = memset_s(config_tmp_buf, config_len, 0, config_len);
284  if (ret != EOK)
285    {
286      usb_err("memset_s failed, %d\n", ret);
287      goto err;
288    }
289
290  descriptors = (struct usb_descriptor *)req->buf;
291  i = 0;
292  new_config_len = 0;
293  while (i < config_len)
294    {
295      i += descriptors->bLength;
296      if (descriptors->bDescriptorType != UDESC_ENDPOINT_SS_COMP)
297        {
298          ret = memcpy_s(config_tmp_buf + new_config_len, config_len - new_config_len,
299                         descriptors, descriptors->bLength);
300          if (ret != EOK)
301            {
302              usb_err("memcpy_s failed, %d\n", ret);
303              goto err;
304            }
305          new_config_len += descriptors->bLength;
306        }
307      descriptors = (struct usb_descriptor *)((char *)descriptors + descriptors->bLength);
308    }
309  ret = memset_s(req->buf, USB_COMP_EP0_BUFSIZ, 0, config_len);
310  if (ret != EOK)
311    {
312      usb_err("memset_s failed, %d\n", ret);
313      goto err;
314    }
315
316  ret = memcpy_s(req->buf, USB_COMP_EP0_BUFSIZ, config_tmp_buf, new_config_len);
317  if (ret != EOK)
318    {
319      usb_err("memcpy_s failed, %d\n", ret);
320      goto err;
321    }
322
323  config_des = (struct usb_config_descriptor *)req->buf;
324  USETW(config_des->wTotalLength, new_config_len);
325  req->len = new_config_len;
326  free(config_tmp_buf);
327
328  return 0;
329
330err:
331  free(config_tmp_buf);
332  return -EINVAL;
333}
334
335int composite_get_config_descriptor(struct usbdev_s *dev,
336                                           struct usbdev_req_s *req, unsigned len)
337{
338  int retval;
339  struct usb_descriptor *descriptors;
340  struct usb_endpoint_descriptor *ep_des;
341  int ret;
342  int i = 0;
343
344  ret = modify_config_descriptor_byspeed(dev, req);
345  if (ret < 0)
346    {
347      return -1;
348    }
349
350  retval = min(len, req->len);
351  descriptors = (struct usb_descriptor *)req->buf;
352
353  while (i < retval)
354    {
355      i += descriptors->bLength;
356      if (descriptors->bDescriptorType != UDESC_ENDPOINT)
357        {
358          descriptors = (struct usb_descriptor *)((char *)descriptors + descriptors->bLength);
359          continue;
360        }
361
362      ep_des = (struct usb_endpoint_descriptor *)descriptors;
363      usbd_configep_byspeed(dev, ep_des);
364      descriptors = (struct usb_descriptor *)((char *)descriptors + descriptors->bLength);
365    }
366
367  req->len = retval;
368  return retval;
369}
370
371void modify_device_descriptor_byspeed(struct usbdev_s *dev, uint8_t *buf)
372{
373  struct usb_device_descriptor *desc = (struct usb_device_descriptor *)buf;
374  switch (dev->speed)
375    {
376    case USB_SPEED_SUPER:
377      USETW(desc->bcdUSB, 0x0300);
378      desc->bMaxPacketSize = 0x09;
379      break;
380
381    case USB_SPEED_HIGH:
382      USETW(desc->bcdUSB, 0x0200);
383      desc->bMaxPacketSize = 0x40;
384      break;
385
386    default:
387      usb_err("invalid speed:%u\n", dev->speed);
388      break;
389    }
390}
391
392static int composite_classsetup(struct composite_dev_s *priv,
393                                struct usbdev_s *dev,
394                                const struct usb_device_request *ctrl,
395                                uint8_t *dataout, size_t outlen)
396{
397  struct composite_devobj_s *devobj;
398  struct usbdev_devinfo_s *devinfo;
399  uint16_t index;
400  uint8_t  interface;
401  int ret = -EOPNOTSUPP;
402  int i;
403  int j;
404
405  (void)dataout;
406  (void)outlen;
407
408  index     = UGETW(ctrl->wIndex);
409  interface = (uint8_t)(index & 0xff);
410
411  /* Usb standard protocol logic processing, such as set interface. */
412
413  for (i = 0; i < priv->ndevices; i++)
414    {
415      if (interface >= priv->device[i].compdesc.devinfo.ifnobase &&
416          interface < (priv->device[i].compdesc.devinfo.ifnobase +
417          priv->device[i].compdesc.devinfo.ninterfaces))
418        {
419          ret = CLASS_SETUP(priv->device[i].dev, dev, ctrl, dataout, outlen);
420          return ret;
421        }
422    }
423
424  /* Specific protocol logic processing, such as UAC class setup. */
425
426  for (i = 0; i < priv->ndevices; i++)
427    {
428      devobj  = &priv->device[i];
429      devinfo = &devobj->compdesc.devinfo;
430      for (j = 0; j < USBDEV_MAX_EPNUM; j++)
431        {
432          if (devinfo->epno[j] == interface)
433            {
434              ret = CLASS_SETUP(devobj->dev, dev, ctrl, dataout, outlen);
435              break;
436            }
437        }
438    }
439
440  return ret;
441}
442
443static void composite_setup_complete(struct usbdev_ep_s *ep,
444                                     struct usbdev_req_s *req)
445{
446  (void)ep;
447  (void)req;
448}
449
450int usb_composite_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev,
451                               const struct usb_device_request *ctrl, uint8_t *dataout, size_t outlen)
452{
453  int ret     = -1;
454  int value   = 0;
455  int new_req = 0;
456  uint16_t w_value, w_length, w_Index;
457  struct composite_driver_s *driv;
458  struct composite_dev_s *usb_cdev;
459  struct usbdev_req_s *usb_req;
460  int i;
461
462  if (driver == NULL || ctrl == NULL || dev == NULL)
463    {
464      return -1;
465    }
466
467  driv     = (struct composite_driver_s *)driver;
468  usb_cdev = driv->dev;
469  if (usb_cdev == NULL)
470    {
471      return -1;
472    }
473
474  w_value  = UGETW(ctrl->wValue);
475  w_length = UGETW(ctrl->wLength);
476  w_Index  = UGETW(ctrl->wIndex);
477
478  usb_req = usb_cdev->ctrlreq;
479
480  /* Update in the 'setup' function of a specific protocol, or use the default */
481  usb_req->callback = composite_setup_complete;
482  usb_req->len      = 0;
483
484  switch (ctrl->bRequest)
485    {
486    case USB_REQ_GET_DESCRIPTOR:
487      {
488        if (ctrl->bmRequestType != USB_DIR_IN)
489          {
490            goto unknowned;
491          }
492
493        switch (w_value >> 8)
494          {
495          case UDESC_DEVICE:
496            value = MIN(w_length, (UINT16)sizeof(struct usb_device_descriptor));
497            composite_mkdevdesc(usb_cdev, usb_req->buf);
498            modify_device_descriptor_byspeed(dev, usb_req->buf);
499            usb_req->len = value;
500            new_req      = 1;
501            break;
502
503          case UDESC_CONFIG:
504            value = composite_mkcfgdesc(usb_cdev, usb_req->buf);
505            if (value < 0)
506              {
507                break;
508              }
509            usb_req->len = value;
510            (void)composite_get_config_descriptor(dev, usb_req, w_length);
511            new_req = 1;
512            break;
513
514          case UDESC_STRING:
515              value = composite_mkstrdesc(usb_cdev, (w_value & 0xff), w_Index, usb_req->buf);
516              if (value < 0)
517                {
518                  break;
519                }
520              usb_req->len = MIN(w_length, value);
521              new_req      = 1;
522              break;
523
524          case UDESC_BOS:
525              usb_req->len = w_length;
526              ret = memcpy_s(usb_req->buf, USB_COMP_EP0_BUFSIZ, (void *)g_bos_desc_buf, SKB_DATA_ALIGN(usb_req->len));
527              if (ret < 0)
528                {
529                  return -1;
530                }
531              new_req = 1;
532              break;
533
534          default:
535              break;
536          }
537      }
538      break;
539
540    case USB_REQ_SET_CONFIGURATION:
541      {
542        if (ctrl->bmRequestType != USB_DIR_OUT)
543          {
544            goto unknowned;
545          }
546        dprintf("SET_CONFIGURATION\n");
547        /* Save the configuration and inform the constituent classes */
548        for (i = 0; i < usb_cdev->ndevices; i++)
549          {
550            ret = CLASS_SETUP(usb_cdev->device[i].dev, dev, ctrl, dataout, outlen);
551            if (ret < 0)
552              {
553                PRINT_ERR("set config fail!\n");
554                return -1;
555              }
556          }
557
558        /* the ret of usbclass_mass_set_alt is '1', the invoking of usbd_endpoint_request is fmass's protocal */
559        if (ret == 0)
560          {
561            new_req = 1;
562          }
563        usb_req->len = 0;
564        usb_cdev->config = w_value;
565      }
566      break;
567
568    case USB_REQ_GET_CONFIGURATION:
569      {
570        dprintf("%s, USB_REQ_GET_CONFIGURATION\n", __func__);
571        usb_req->len = 1;
572        usb_req->buf[0] = 1;
573        new_req = 1;
574        break;
575      }
576
577    case USB_REQ_SET_INTERFACE:
578      {
579        if (ctrl->bmRequestType == USB_RECIP_INTERFACE &&
580            usb_cdev->config == COMPOSITE_CONFIGID)
581          {
582            value = composite_classsetup(usb_cdev, dev, ctrl, dataout, outlen);
583            new_req = 1;
584          }
585        break;
586      }
587
588    case USB_REQ_GET_STATUS:
589      {
590        if (ctrl->bmRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
591          {
592            goto unknowned;
593          }
594
595        break;
596      }
597
598    case USB_REQ_CLEAR_FEATURE:
599    case USB_REQ_SET_FEATURE:
600      {
601        if (ctrl->bmRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
602          {
603            goto unknowned;
604          }
605
606        break;
607      }
608
609    default:
610unknowned:
611      switch (ctrl->bmRequestType & USB_RECIP_MASK)
612        {
613        case USB_RECIP_INTERFACE:
614        case USB_RECIP_ENDPOINT:
615          (void)composite_classsetup(usb_cdev, dev, ctrl, dataout, outlen);
616          break;
617
618        default:
619          break;
620        }
621      goto success;
622    }
623
624  if (new_req)
625    {
626      value = EP_SUBMIT(dev->ep0, usb_req);
627      if (value < 0)
628        {
629          PRINT_ERR("endpoint send fail!\n");
630          usb_req->result = 0;
631          return -1;
632        }
633    }
634
635success:
636  return value;
637}
638
639static void usb_composite_disconnect(struct usbdevclass_driver_s *driver, struct usbdev_s *dev)
640{
641  struct composite_dev_s *priv;
642  int i;
643
644  /* Extract reference to private data */
645
646  priv = ((struct composite_driver_s *)driver)->dev;
647  if (priv == NULL)
648    {
649      return;
650    }
651
652  for (i = 0; i < priv->ndevices; i++)
653    {
654      CLASS_DISCONNECT(priv->device[i].dev, dev);
655    }
656}
657
658static void usb_composite_suspend(struct usbdevclass_driver_s *driver, struct usbdev_s *dev)
659{
660  (void)driver;
661  (void)dev;
662  PRINT_WARN("%s is not support now!\n", __FUNCTION__);
663}
664
665static void usb_composite_resume(struct usbdevclass_driver_s *driver, struct usbdev_s *dev)
666{
667  (void)driver;
668  (void)dev;
669  PRINT_WARN("%s is not support now!\n", __FUNCTION__);
670}
671
672static struct usbdevclass_driverops_s g_composite_driverops =
673{
674  .bind       = usb_composite_bind,       /* bind */
675  .unbind     = usb_composite_unbind,     /* unbind */
676  .setup      = usb_composite_setup,      /* setup */
677  .disconnect = usb_composite_disconnect, /* disconnect */
678  .suspend    = usb_composite_suspend,    /* suspend */
679  .resume     = usb_composite_resume,     /* resume */
680};
681
682/* probe composite device driver */
683int usbd_composite_probe(struct composite_softc *cdev)
684{
685  int ret;
686
687  if (cdev == NULL)
688    {
689      return -INVAL_ARGU;
690    }
691
692  /* probe and initiate device driver */
693  ret = composite_device_init(cdev);
694  if (ret < 0)
695    {
696      PRINT_ERR("composite device init failed!, ret:%d\n", ret);
697      return -1;
698    }
699
700  return 0;
701}
702
703static int composite_probe(device_t dev)
704{
705  return 0;
706}
707extern struct driver_module_data fcdcacm_simple_driver_mod;
708extern struct driver_module_data fconfig_simple_driver_mod;
709int composite_device_init(struct composite_softc *cdev)
710{
711  int ret;
712#ifndef FCOFNIG_FUN
713  struct driver_module_data *mod = &fcdcacm_simple_driver_mod;
714#else
715  struct driver_module_data *mod = &fconfig_simple_driver_mod;
716#endif
717  if (mod->dmd_chainevh)
718  	ret = mod->dmd_chainevh(NULL, MOD_LOAD, cdev);
719  return 0;
720}
721
722static int composite_attach(device_t dev)
723{
724  struct composite_softc *usb_cdev = device_get_softc(dev);
725  void *parnet_conext = (void *)usb_cdev;
726
727  int ret;
728
729  if (usb_cdev == NULL || parnet_conext == NULL)
730    {
731      PRINT_ERR("%s usb_cdev or parnet_conext is null!\n", __FUNCTION__);
732      return -1;
733    }
734
735  /* probe gadget drivers */
736  ret = usbd_composite_probe(usb_cdev);
737  if (ret < 0)
738    {
739      return -1;
740    }
741
742  usb_cdev->drvr.dev = &usb_cdev->dev;
743  usb_cdev->parnet_conext = parnet_conext;
744#ifndef FCOFNIG_FUN
745  usbd_start_udc();
746  ret = usbd_gadget_attach_driver(parnet_conext, &usb_cdev->drvr.drvr);
747  if (ret < 0)
748    {
749      goto detach;
750    }
751#endif
752  DPRINTF("composite attach success!\n");
753  return 0; /* Attach success */
754#ifndef FCOFNIG_FUN
755detach:
756  (void)composite_detach(dev);
757  PRINT_ERR("%s failed, err=%d!\n", __FUNCTION__, ret);
758  return -1; /* No such device or address */
759#endif
760}
761
762void composite_uninitialize(void *handle);
763static int composite_detach(device_t dev)
764{
765  struct composite_softc *usb_cdev = device_get_softc(dev);
766  void *parnet_conext = device_get_softc(device_get_parent(dev));
767  int ret;
768
769  if (usb_cdev == NULL || parnet_conext == NULL)
770    {
771      return -1;
772    }
773  PRINT_ERR("composite_detach!!!!!!!!!!!!!\n");
774  sleep(1);
775  ret = usbd_gadget_detach_driver(parnet_conext, &usb_cdev->drvr.drvr);
776  if (ret != 0)
777    {
778      PRINT_ERR("%s failed, err=%d!\n", __FUNCTION__, ret);
779      return ret;
780    }
781  composite_uninitialize(usb_cdev);
782
783  DPRINTF("%s\n", __FUNCTION__);
784  return (0);
785}
786
787/****************************************************************************
788 * Public Functions
789 ****************************************************************************/
790/****************************************************************************
791 * Name: composite_initialize
792 *
793 * Description:
794 *   Register USB composite device as configured.  This function will call
795 *   board-specific implementations in order to obtain the class objects for
796 *   each of the members of the composite.
797 *
798 * Input Parameters:
799 *   None
800 *
801 * Returned Value:
802 *   A non-NULL "handle" is returned on success.  This handle may be used
803 *   later with composite_uninitialize() in order to removed the composite
804 *   device.  This handle is the (untyped) internal representation of the
805 *   the class driver instance.
806 *
807 *   NULL is returned on any failure.
808 *
809 ****************************************************************************/
810
811int composite_initialize(struct composite_softc *softc, uint8_t ndevices,
812                         struct composite_devdesc_s *pdevices)
813{
814  struct composite_dev_s *priv;
815  struct composite_driver_s *drvr;
816  int ret;
817  int i;
818
819  /* Convenience pointers into the allocated blob */
820
821  priv = &softc->dev;
822  drvr = &softc->drvr;
823
824  /* Initialize the USB composite driver structure */
825
826  (void)memset_s(priv, sizeof(struct composite_dev_s), 0, sizeof(struct composite_dev_s));
827  priv->cfgdescsize = 0;
828  priv->ninterfaces = 0;
829
830  /* Get the constituent class driver objects */
831
832  for (i = 0; i < ndevices; i++)
833    {
834      (void)memcpy_s(&priv->device[i].compdesc, sizeof(struct composite_devdesc_s),
835                     &pdevices[i], sizeof(struct composite_devdesc_s));
836      ret = priv->device[i].compdesc.classobject(priv->device[i].compdesc.minor,
837                                                 &priv->device[i].compdesc.devinfo,
838                                                 &priv->device[i].dev);
839      if (ret < 0)
840        {
841          return -1;
842        }
843      priv->cfgdescsize += priv->device[i].compdesc.cfgdescsize;
844      priv->ninterfaces += priv->device[i].compdesc.devinfo.ninterfaces;
845    }
846  priv->ndevices = ndevices;
847
848  /* Initialize the USB class driver structure */
849
850  drvr->drvr.speed = USB_SPEED_HIGH;
851  drvr->drvr.ops   = &g_composite_driverops;
852  drvr->dev        = priv;
853
854  return 0;
855}
856
857void composite_uninitialize(void *handle)
858{
859  struct composite_softc *usb_cdev = (struct composite_softc *)handle;
860  struct composite_dev_s *cdev = &usb_cdev->dev;
861  int i;
862
863  /* First phase uninitialization each of the member classes */
864
865  for (i = 0; i < cdev->ndevices; i++)
866    {
867      cdev->device[i].compdesc.uninitialize(cdev->device[i].dev);
868    }
869}
870
871struct composite_devobj_s *usbclass_devobj_get(struct composite_dev_s *cdev, device_type type)
872{
873  int i;
874  struct composite_devdesc_s *compdesc;
875
876  for (i = 0; i < NUM_DEVICES_TO_HANDLE; i++)
877    {
878      compdesc = &cdev->device[i].compdesc;
879      if (compdesc->minor == type)
880        {
881          return &cdev->device[i];
882        }
883    }
884
885  return NULL;
886}
887
888#undef USB_DEBUG_VAR
889