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