1/* ----------------------------------------------------------------------------
2 * Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
3 * Description: LiteOS USB Driver Composite Devices
4 * Author: Yannik Li
5 * Create: 2021-02-21
6 * Redistribution and use in source and binary forms, with or without modification,
7 * are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without specific prior written
15 * permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * --------------------------------------------------------------------------- */
28/* ----------------------------------------------------------------------------
29 * Notice of Export Control Law
30 * ===============================================
31 * Huawei LiteOS may be subject to applicable export control laws and regulations, which might
32 * include those applicable to Huawei LiteOS of U.S. and the country in which you are located.
33 * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such
34 * applicable export control laws and regulations.
35 * --------------------------------------------------------------------------- */
36
37#include "gadget/composite.h"
38#include "gadget/cdcacm.h"
39#include "gadget/rndis.h"
40#include "f_common.h"
41
42#ifdef __cplusplus
43#if __cplusplus
44//extern "C" {
45#endif /* __cplusplus */
46#endif /* __cplusplus */
47
48#define FCONFIG_NSTRIDS                 5
49
50#define USB_ETHER_FIRST_INTERFACE_NUM   0
51#define USB_SERIAL_FIRST_INTERFACE_NUM  2
52
53extern int composite_get_config_descriptor(struct usbdev_s *dev,
54                                           struct usbdev_req_s *req, unsigned len);
55extern void modify_device_descriptor_byspeed(struct usbdev_s *dev, uint8_t *buf);
56extern int usb_composite_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev,
57                               const struct usb_device_request *ctrl, uint8_t *dataout, size_t outlen);
58
59int usbdev_fconfig_initialize(struct module *mod, int n, void *arg);
60
61/* device driver structure definition */
62
63static driver_t g_fconfig_driver_t =
64{
65  .name    = "fconfig",
66  .methods = NULL,
67  .size    = 0
68};
69
70/* private device class information */
71
72static devclass_t g_fconfig_devclass;
73DRIVER_MODULE(fconfig, simple, g_fconfig_driver_t, g_fconfig_devclass, usbdev_fconfig_initialize, 0);
74
75static struct fconfig_softc g_fconfig_softc;
76
77static int gadget_match(struct usb_obj *obj, void *match_data)
78{
79  struct composite_softc *com_s = (struct composite_softc *)match_data;
80  struct gadget_info *gi = container_of(obj, struct gadget_info, obj);
81
82  return gi->com_s == com_s;
83}
84
85static struct gadget_info *fconfig_find_gadget(struct composite_dev_s *com_dev)
86{
87  struct composite_softc *com_s = container_of(com_dev, struct composite_softc, dev);
88  struct fconfig_softc *cdev = &g_fconfig_softc;
89  struct usb_obj *obj;
90
91  obj = usbobj_find(&cdev->obj, gadget_match, com_s);
92  if (obj)
93    {
94      return container_of(obj, struct gadget_info, obj);
95    }
96
97  return NULL;
98}
99
100static void fconfig_setup_complete(struct usbdev_ep_s *ep,
101                                   struct usbdev_req_s *req)
102{
103  (void)ep;
104  if (req->result != 0)
105    {
106      dprintf("%s, result = %d\n", __func__, req->result);
107    }
108}
109
110static int fconfig_submit_ctrlreq(struct usbdev_s *dev, struct usbdev_req_s *usb_req)
111{
112  int ret;
113
114  usb_req->callback = fconfig_setup_complete;
115  ret = EP_SUBMIT(dev->ep0, usb_req);
116  if (ret < 0)
117    {
118      usb_err("%s: endpoint send fail!\n", __FUNCTION__);
119      usb_req->result = 0;
120    }
121  return ret;
122}
123
124int gadget_strings_match(struct usb_obj *obj, void *match_data)
125{
126  struct gadget_strings *strings = container_of(obj, struct gadget_strings, obj);
127  uint16_t language = *(uint16_t *)match_data;
128
129  return strings->language == language;
130}
131
132#define STRING_ID_LEN 4
133static int fconfig_mkstrdesc(struct composite_dev_s *com_dev, uint16_t language, uint8_t id, uint8_t *buf)
134{
135  struct gadget_info *gi;
136  struct usb_string_descriptor *str_desc = (struct usb_string_descriptor *)buf;
137  struct gadget_strings *dev_strings;
138  struct usb_obj *obj;
139  char lang_string[STRING_ID_LEN] = {STRING_ID_LEN, UDESC_STRING, 0x9, 0x4 };
140  int i;
141  int ret = -1;
142
143  if (id == 0 && language == 0)
144    {
145      ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, (void *)lang_string, lang_string[0]);
146      if (ret != EOK)
147        {
148          return -1;
149        }
150      return lang_string[0];
151    }
152
153  gi = fconfig_find_gadget(com_dev);
154  if (gi == NULL)
155    {
156      usb_err("%s: can not find gi\n", __FUNCTION__);
157      return -1;
158    }
159  if (id < gi->str_count)
160    {
161      obj = usbobj_find(&gi->strings, gadget_strings_match, &language);
162      if (!obj)
163        {
164          usb_err("%s: can not find the string with id = %u\n", __FUNCTION__, id);
165          return -1;
166        }
167      dev_strings = container_of(obj, struct gadget_strings, obj);
168
169      for (i = 0; dev_strings->strings[i].s != NULL; i++)
170        {
171          const char *str = dev_strings->strings[i].s;
172          if (dev_strings->strings[i].id == id)
173            {
174              errno_t ret = utf8_to_utf16le(str, buf + 2, strlen(str));
175              if (ret <= 0)
176                {
177                  usb_err("%s: memcpy_s failed, ret = %d\n", __FUNCTION__, ret);
178                  return -1;
179                }
180              str_desc->bLength = 2 + (ret * 2);
181              str_desc->bDescriptorType = UDESC_STRING;
182              return str_desc->bLength;
183            }
184        }
185    }
186  else
187    {
188      for (i = 0; i < com_dev->ndevices; i++)
189        {
190          struct usbdev_devinfo_s *devinfo = &com_dev->device[i].compdesc.devinfo;
191          if (id >= (devinfo->strbase + gi->str_count) &&
192              id < (devinfo->strbase + devinfo->nstrings + gi->str_count))
193            {
194              *buf = (uint8_t)com_dev->device[i].compdesc.minor; /* pass minor number to driver */
195              ret = com_dev->device[i].compdesc.mkstrdesc(id - devinfo->strbase - gi->str_count, buf);
196              break;
197            }
198        }
199    }
200  return ret;
201}
202
203static void fconfig_mkdevdesc(struct composite_dev_s *priv, uint8_t *buf)
204{
205  struct gadget_info *gi;
206  struct usb_device_descriptor  *dev_desc;
207  errno_t ret;
208
209  gi = fconfig_find_gadget(priv);
210  if (gi == NULL)
211    {
212      usb_err("%s: gadget info is NULL\n", __FUNCTION__);
213      return;
214    }
215
216  ret = memcpy_s(buf, USB_COMP_EP0_BUFSIZ, gi->dev_desc, sizeof(*gi->dev_desc));
217  if (ret != EOK)
218    {
219      usb_err("%s: memcpy_s fail!, ret:%d\n", __FUNCTION__, ret);
220      return;
221    }
222  dev_desc = ( struct usb_device_descriptor  *)buf;
223  dev_desc->iManufacturer += 1;
224  dev_desc->iProduct += 1;
225  dev_desc->iSerialNumber += 1;
226}
227
228static int usb_config_match(struct usb_obj *obj, void *match_data)
229{
230  struct gadget_config *cfg = container_of(obj, struct gadget_config, obj);
231  uint8_t config_num = *(uint8_t *)match_data;
232
233  return (cfg->cfg_num == config_num);
234}
235
236static struct gadget_config *fconfig_find_cfg(struct composite_dev_s *com_dev, uint32_t *string_num)
237{
238  struct composite_softc *com_s = container_of(com_dev, struct composite_softc, dev);
239  struct fconfig_softc *cdev = &g_fconfig_softc;
240  struct usb_obj *obj;
241  struct gadget_info *gi;
242  uint8_t config_num = 0;
243  struct gadget_config *cfg;
244
245  obj = usbobj_find(&cdev->obj, gadget_match, com_s);
246  if (!obj)
247    {
248      usb_err("%s: can't find gadget info\n", __FUNCTION__);
249      return NULL;
250    }
251  gi = container_of(obj, struct gadget_info, obj);
252  *string_num = gi->str_count;
253  config_num = 1;
254  obj = usbobj_find(&gi->obj, usb_config_match, &config_num);
255  if (!obj)
256    {
257      usb_err("%s: can't find the configNumber %d\n", __FUNCTION__, config_num);
258      return NULL;
259    }
260  cfg = container_of(obj, struct gadget_config, obj);
261
262  return cfg;
263}
264
265static int modify_string_index_bystrbase(uint8_t *buf, int16_t len,
266                                         uint32_t dev_str_num, int func_strbase)
267{
268  struct usb_descriptor *descriptors;
269  struct usb_interface_assoc_descriptor *iad;
270  struct usb_interface_descriptor *intf;
271  uint32_t i;
272
273  descriptors = (struct usb_descriptor *)buf;
274  i = 0;
275  while (i < len)
276    {
277      i += descriptors->bLength;
278      if (descriptors->bDescriptorType == UDESC_IFACE_ASSOC)
279        {
280          iad = (struct usb_interface_assoc_descriptor *)descriptors;
281          iad->iFunction += (uint8_t)(dev_str_num + func_strbase - 1);
282        }
283      else if (descriptors->bDescriptorType == UDESC_INTERFACE)
284        {
285          intf = (struct usb_interface_descriptor *)descriptors;
286          if (intf->bNumEndpoints > 0)
287            {
288              intf->iInterface += (uint8_t)(dev_str_num + func_strbase - 1);
289            }
290        }
291      descriptors = (struct usb_descriptor *)((char *)descriptors + descriptors->bLength);
292    }
293  return 0;
294}
295
296static int fconfig_mkcfgdesc(struct composite_dev_s *priv, uint8_t *buf)
297{
298  struct gadget_config *cfg;
299  struct usb_config_descriptor *config_desc;
300  int16_t total_len = 0;
301  int16_t len = USB_CONFIG_DESC_SIZE;
302  uint8_t *buf_tmp = buf;
303  uint32_t dev_string_num;
304  int ret, i;
305
306  cfg = fconfig_find_cfg(priv, &dev_string_num);
307  if (!cfg)
308    {
309      usb_err("%s: can't find gadget config\n", __FUNCTION__);
310      return -1;
311    }
312  ret = memcpy_s(buf_tmp, USB_COMP_EP0_BUFSIZ,
313                 (const void *)cfg->cfg_desc, (uint32_t)len);
314  if (ret != EOK)
315    {
316      usb_err("memcpy_s fail, ret:%d\n", ret);
317      return -1;
318    }
319  total_len += len;
320  buf_tmp += len;
321  for (i = 0; i < priv->ndevices; i++)
322    {
323      struct generic_driver_s *drvr = (struct generic_driver_s *)priv->device[i].dev;
324      struct generic_dev_s *dev = drvr->dev;
325      int func_strbase = priv->device[i].compdesc.devinfo.strbase;
326      uint16_t off_len = 0;
327
328      dprintf("%s,%d, raw_descs_length = %d\n", __func__, __LINE__, dev->raw_descs_length);
329      dprintf("%s,%d, fs_len = %d\n", __func__, __LINE__, dev->fs_descs_len);
330      dprintf("%s,%d, hs_len = %d\n", __func__, __LINE__, dev->hs_descs_len);
331      dprintf("%s,%d, ss_len = %d\n", __func__, __LINE__, dev->ss_descs_len);
332      dprintf("%s,%d, speed = %d\n", __func__, __LINE__, drvr->drvr.speed);
333      len = dev->fs_descs_len;
334      if (drvr->drvr.speed == USB_SPEED_HIGH)
335        {
336          off_len = dev->fs_descs_len;
337          len = dev->fs_descs_len;
338        }
339      else if (drvr->drvr.speed == USB_SPEED_SUPER)
340        {
341          off_len = dev->fs_descs_len + dev->hs_descs_len;
342          len = dev->ss_descs_len;
343        }
344
345      ret = memcpy_s(buf_tmp, (USB_COMP_EP0_BUFSIZ - total_len),
346                     (const void *)((uint8_t *)dev->raw_descs + off_len), (uint32_t)len);
347      if (ret != EOK)
348        {
349          usb_err("memcpy_s fail, ret:%d\n", ret);
350          return -1;
351        }
352      modify_string_index_bystrbase(buf_tmp, len, dev_string_num, func_strbase);
353      total_len   += len;
354      buf_tmp += len;
355    }
356  config_desc = (struct usb_config_descriptor *)buf;
357  USETW(config_desc->wTotalLength, total_len);
358  config_desc->bNumInterface = priv->ninterfaces;
359  config_desc->iConfiguration += 1;
360
361  return total_len;
362}
363
364static int fconfig_composite_setup(struct usbdevclass_driver_s *driver, struct usbdev_s *dev,
365                                   const struct usb_device_request *ctrl, uint8_t *dataout, size_t outlen)
366{
367  struct composite_driver_s *driv = (struct composite_driver_s *)driver;
368  int value   = 0;
369
370  if (driv == NULL || driv->dev == NULL || ctrl == NULL || dev == NULL)
371    {
372      usb_err("%s: invalid parameter\n", __FUNCTION__);
373      return -1;
374    }
375
376  if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR)
377    {
378      uint16_t w_value  = UGETW(ctrl->wValue);
379      uint16_t w_length = UGETW(ctrl->wLength);
380      uint16_t w_Index  = UGETW(ctrl->wIndex);
381      struct composite_dev_s *usb_cdev = driv->dev;
382      struct usbdev_req_s *usb_req = usb_cdev->ctrlreq;
383
384      usb_req->len = 0;
385      switch (w_value >> 8)
386        {
387        case UDESC_DEVICE:
388          usb_debug("UDESC_DEVICE, usb_req:%x, buf:%x\n", usb_req, usb_req->buf);
389          value = MIN(w_length, (UINT16)sizeof(struct usb_device_descriptor));
390          fconfig_mkdevdesc(usb_cdev, usb_req->buf);
391          modify_device_descriptor_byspeed(dev, usb_req->buf);
392          usb_req->len = value;
393          return fconfig_submit_ctrlreq(dev, usb_req);
394        case UDESC_CONFIG:
395          usb_debug("%s, UDESC_CONFIG, usb_req:%x, buf:%x\n", __func__, usb_req, usb_req->buf);
396          value = fconfig_mkcfgdesc(usb_cdev, usb_req->buf);
397          if (value < 0)
398            {
399              break;
400            }
401          usb_req->len = value;
402          (void)composite_get_config_descriptor(dev, usb_req, w_length);
403          dprintf("%s, UDESC_CONFIG, usb_req->len: %x\n", __func__, usb_req->len);
404          return fconfig_submit_ctrlreq(dev, usb_req);
405
406        case UDESC_STRING:
407          {
408            uint8_t strid = w_value & 0xff;
409            usb_debug("UDESC_STRING:%d\n", strid);
410            value = fconfig_mkstrdesc(usb_cdev, w_Index, strid, usb_req->buf);
411            if (value < 0)
412              {
413                usb_err("%s: make string desc error\n", __FUNCTION__);
414                return value;
415              }
416            usb_req->len = MIN(w_length, value);
417            return fconfig_submit_ctrlreq(dev, usb_req);
418          }
419        default:
420          /* will be processed by usb_composite_setup() */
421          break;
422        }
423    }
424
425  return usb_composite_setup(driver, dev, ctrl, dataout, outlen);
426}
427
428int fconfig_do_composite_initialize(struct composite_softc *softc, uint8_t ndevices,
429                                    struct composite_devdesc_s *pdevices)
430{
431  struct composite_driver_s *drvr = &softc->drvr;
432  int ret;
433
434  ret = composite_initialize(softc, ndevices, pdevices);
435  if (ret != 0)
436    {
437      return -1;
438    }
439
440  drvr->drvr.ops->setup = fconfig_composite_setup;
441  return 0;
442}
443
444int usbdev_fconfig_initialize(struct module *mod, int n, void *arg)
445{
446  struct fconfig_softc *cdev = &g_fconfig_softc;
447  struct composite_softc *com_s  = (struct composite_softc *)arg;
448  int ret;
449
450  (void)mod;
451  (void)memset_s(cdev, sizeof(*cdev), 0, sizeof(*cdev));
452  usbobj_init(&cdev->obj, "fconfig", NULL);
453
454  if (com_s == NULL)
455    {
456      usb_err("%s: com_s is null\n", __FUNCTION__);
457      return -1;
458    }
459  cdev->com_s = com_s;
460  com_s->dev.config = 1;
461  /* register fconfig device */
462  ret = fconfig_fops_init(cdev);
463  if (ret != LOS_OK)
464    {
465      usb_err("%s: create fconfig device node failed\n", __FUNCTION__);
466      return -1;
467    }
468  return 0;
469}
470
471#ifdef __cplusplus
472#if __cplusplus
473//}
474#endif /* __cplusplus */
475#endif /* __cplusplus */
476