| .. | .. |
|---|
| 50 | 50 | #define KERNEL_VER bin2bcd(((LINUX_VERSION_CODE >> 8) & 0x0ff)) |
|---|
| 51 | 51 | |
|---|
| 52 | 52 | enum { |
|---|
| 53 | + AST_VHUB_STR_INDEX_MAX = 4, |
|---|
| 53 | 54 | AST_VHUB_STR_MANUF = 3, |
|---|
| 54 | 55 | AST_VHUB_STR_PRODUCT = 2, |
|---|
| 55 | 56 | AST_VHUB_STR_SERIAL = 1, |
|---|
| .. | .. |
|---|
| 72 | 73 | .bNumConfigurations = 1, |
|---|
| 73 | 74 | }; |
|---|
| 74 | 75 | |
|---|
| 75 | | -/* Patches to the above when forcing USB1 mode */ |
|---|
| 76 | | -static void ast_vhub_patch_dev_desc_usb1(struct usb_device_descriptor *desc) |
|---|
| 77 | | -{ |
|---|
| 78 | | - desc->bcdUSB = cpu_to_le16(0x0100); |
|---|
| 79 | | - desc->bDeviceProtocol = 0; |
|---|
| 80 | | -} |
|---|
| 81 | | - |
|---|
| 82 | 76 | /* |
|---|
| 83 | 77 | * Configuration descriptor: same comments as above |
|---|
| 84 | 78 | * regarding handling USB1 mode. |
|---|
| .. | .. |
|---|
| 93 | 87 | USB_DT_INTERFACE_SIZE + \ |
|---|
| 94 | 88 | USB_DT_ENDPOINT_SIZE) |
|---|
| 95 | 89 | |
|---|
| 96 | | -static const struct ast_vhub_full_cdesc { |
|---|
| 97 | | - struct usb_config_descriptor cfg; |
|---|
| 98 | | - struct usb_interface_descriptor intf; |
|---|
| 99 | | - struct usb_endpoint_descriptor ep; |
|---|
| 100 | | -} __attribute__ ((packed)) ast_vhub_conf_desc = { |
|---|
| 90 | +static const struct ast_vhub_full_cdesc ast_vhub_conf_desc = { |
|---|
| 101 | 91 | .cfg = { |
|---|
| 102 | 92 | .bLength = USB_DT_CONFIG_SIZE, |
|---|
| 103 | 93 | .bDescriptorType = USB_DT_CONFIG, |
|---|
| .. | .. |
|---|
| 266 | 256 | u8 desc_type, u16 len) |
|---|
| 267 | 257 | { |
|---|
| 268 | 258 | size_t dsize; |
|---|
| 259 | + struct ast_vhub *vhub = ep->vhub; |
|---|
| 269 | 260 | |
|---|
| 270 | 261 | EPDBG(ep, "GET_DESCRIPTOR(type:%d)\n", desc_type); |
|---|
| 271 | 262 | |
|---|
| .. | .. |
|---|
| 281 | 272 | switch(desc_type) { |
|---|
| 282 | 273 | case USB_DT_DEVICE: |
|---|
| 283 | 274 | dsize = USB_DT_DEVICE_SIZE; |
|---|
| 284 | | - memcpy(ep->buf, &ast_vhub_dev_desc, dsize); |
|---|
| 285 | | - BUILD_BUG_ON(dsize > sizeof(ast_vhub_dev_desc)); |
|---|
| 275 | + memcpy(ep->buf, &vhub->vhub_dev_desc, dsize); |
|---|
| 276 | + BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc)); |
|---|
| 286 | 277 | BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
|---|
| 287 | 278 | break; |
|---|
| 288 | 279 | case USB_DT_CONFIG: |
|---|
| 289 | 280 | dsize = AST_VHUB_CONF_DESC_SIZE; |
|---|
| 290 | | - memcpy(ep->buf, &ast_vhub_conf_desc, dsize); |
|---|
| 291 | | - BUILD_BUG_ON(dsize > sizeof(ast_vhub_conf_desc)); |
|---|
| 281 | + memcpy(ep->buf, &vhub->vhub_conf_desc, dsize); |
|---|
| 282 | + BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc)); |
|---|
| 292 | 283 | BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
|---|
| 293 | 284 | break; |
|---|
| 294 | 285 | case USB_DT_HUB: |
|---|
| 295 | 286 | dsize = AST_VHUB_HUB_DESC_SIZE; |
|---|
| 296 | | - memcpy(ep->buf, &ast_vhub_hub_desc, dsize); |
|---|
| 297 | | - BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc)); |
|---|
| 298 | | - BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
|---|
| 287 | + memcpy(ep->buf, &vhub->vhub_hub_desc, dsize); |
|---|
| 288 | + BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc)); |
|---|
| 289 | + BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET); |
|---|
| 299 | 290 | break; |
|---|
| 300 | 291 | default: |
|---|
| 301 | 292 | return std_req_stall; |
|---|
| .. | .. |
|---|
| 305 | 296 | if (len > dsize) |
|---|
| 306 | 297 | len = dsize; |
|---|
| 307 | 298 | |
|---|
| 308 | | - /* Patch it if forcing USB1 */ |
|---|
| 309 | | - if (desc_type == USB_DT_DEVICE && ep->vhub->force_usb1) |
|---|
| 310 | | - ast_vhub_patch_dev_desc_usb1(ep->buf); |
|---|
| 311 | | - |
|---|
| 312 | 299 | /* Shoot it from the EP buffer */ |
|---|
| 313 | 300 | return ast_vhub_reply(ep, NULL, len); |
|---|
| 301 | +} |
|---|
| 302 | + |
|---|
| 303 | +static struct usb_gadget_strings* |
|---|
| 304 | +ast_vhub_str_of_container(struct usb_gadget_string_container *container) |
|---|
| 305 | +{ |
|---|
| 306 | + return (struct usb_gadget_strings *)container->stash; |
|---|
| 307 | +} |
|---|
| 308 | + |
|---|
| 309 | +static int ast_vhub_collect_languages(struct ast_vhub *vhub, void *buf, |
|---|
| 310 | + size_t size) |
|---|
| 311 | +{ |
|---|
| 312 | + int rc, hdr_len, nlangs, max_langs; |
|---|
| 313 | + struct usb_gadget_strings *lang_str; |
|---|
| 314 | + struct usb_gadget_string_container *container; |
|---|
| 315 | + struct usb_string_descriptor *sdesc = buf; |
|---|
| 316 | + |
|---|
| 317 | + nlangs = 0; |
|---|
| 318 | + hdr_len = sizeof(struct usb_descriptor_header); |
|---|
| 319 | + max_langs = (size - hdr_len) / sizeof(sdesc->wData[0]); |
|---|
| 320 | + list_for_each_entry(container, &vhub->vhub_str_desc, list) { |
|---|
| 321 | + if (nlangs >= max_langs) |
|---|
| 322 | + break; |
|---|
| 323 | + |
|---|
| 324 | + lang_str = ast_vhub_str_of_container(container); |
|---|
| 325 | + sdesc->wData[nlangs++] = cpu_to_le16(lang_str->language); |
|---|
| 326 | + } |
|---|
| 327 | + |
|---|
| 328 | + rc = hdr_len + nlangs * sizeof(sdesc->wData[0]); |
|---|
| 329 | + sdesc->bLength = rc; |
|---|
| 330 | + sdesc->bDescriptorType = USB_DT_STRING; |
|---|
| 331 | + |
|---|
| 332 | + return rc; |
|---|
| 333 | +} |
|---|
| 334 | + |
|---|
| 335 | +static struct usb_gadget_strings *ast_vhub_lookup_string(struct ast_vhub *vhub, |
|---|
| 336 | + u16 lang_id) |
|---|
| 337 | +{ |
|---|
| 338 | + struct usb_gadget_strings *lang_str; |
|---|
| 339 | + struct usb_gadget_string_container *container; |
|---|
| 340 | + |
|---|
| 341 | + list_for_each_entry(container, &vhub->vhub_str_desc, list) { |
|---|
| 342 | + lang_str = ast_vhub_str_of_container(container); |
|---|
| 343 | + if (lang_str->language == lang_id) |
|---|
| 344 | + return lang_str; |
|---|
| 345 | + } |
|---|
| 346 | + |
|---|
| 347 | + return NULL; |
|---|
| 314 | 348 | } |
|---|
| 315 | 349 | |
|---|
| 316 | 350 | static int ast_vhub_rep_string(struct ast_vhub_ep *ep, |
|---|
| 317 | 351 | u8 string_id, u16 lang_id, |
|---|
| 318 | 352 | u16 len) |
|---|
| 319 | 353 | { |
|---|
| 320 | | - int rc = usb_gadget_get_string (&ast_vhub_strings, string_id, ep->buf); |
|---|
| 354 | + int rc; |
|---|
| 355 | + u8 buf[256]; |
|---|
| 356 | + struct ast_vhub *vhub = ep->vhub; |
|---|
| 357 | + struct usb_gadget_strings *lang_str; |
|---|
| 321 | 358 | |
|---|
| 322 | | - /* |
|---|
| 323 | | - * This should never happen unless we put too big strings in |
|---|
| 324 | | - * the array above |
|---|
| 325 | | - */ |
|---|
| 326 | | - BUG_ON(rc >= AST_VHUB_EP0_MAX_PACKET); |
|---|
| 359 | + if (string_id == 0) { |
|---|
| 360 | + rc = ast_vhub_collect_languages(vhub, buf, sizeof(buf)); |
|---|
| 361 | + } else { |
|---|
| 362 | + lang_str = ast_vhub_lookup_string(vhub, lang_id); |
|---|
| 363 | + if (!lang_str) |
|---|
| 364 | + return std_req_stall; |
|---|
| 327 | 365 | |
|---|
| 328 | | - if (rc < 0) |
|---|
| 366 | + rc = usb_gadget_get_string(lang_str, string_id, buf); |
|---|
| 367 | + } |
|---|
| 368 | + |
|---|
| 369 | + if (rc < 0 || rc >= AST_VHUB_EP0_MAX_PACKET) |
|---|
| 329 | 370 | return std_req_stall; |
|---|
| 330 | 371 | |
|---|
| 331 | 372 | /* Shoot it from the EP buffer */ |
|---|
| 373 | + memcpy(ep->buf, buf, rc); |
|---|
| 332 | 374 | return ast_vhub_reply(ep, NULL, min_t(u16, rc, len)); |
|---|
| 333 | 375 | } |
|---|
| 334 | 376 | |
|---|
| .. | .. |
|---|
| 449 | 491 | USB_PORT_STAT_C_OVERCURRENT | |
|---|
| 450 | 492 | USB_PORT_STAT_C_RESET | |
|---|
| 451 | 493 | USB_PORT_STAT_C_L1; |
|---|
| 452 | | - p->change |= chg; |
|---|
| 453 | 494 | |
|---|
| 495 | + /* |
|---|
| 496 | + * We only set USB_PORT_STAT_C_ENABLE if we are disabling |
|---|
| 497 | + * the port as per USB spec, otherwise MacOS gets upset |
|---|
| 498 | + */ |
|---|
| 499 | + if (p->status & USB_PORT_STAT_ENABLE) |
|---|
| 500 | + chg &= ~USB_PORT_STAT_C_ENABLE; |
|---|
| 501 | + |
|---|
| 502 | + p->change = chg; |
|---|
| 454 | 503 | ast_vhub_update_hub_ep1(vhub, port); |
|---|
| 455 | 504 | } |
|---|
| 456 | 505 | } |
|---|
| .. | .. |
|---|
| 497 | 546 | * we let the normal host wake path deal with it later. |
|---|
| 498 | 547 | */ |
|---|
| 499 | 548 | spin_lock_irqsave(&vhub->lock, flags); |
|---|
| 500 | | - for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { |
|---|
| 549 | + for (i = 0; i < vhub->max_ports; i++) { |
|---|
| 501 | 550 | struct ast_vhub_port *p = &vhub->ports[i]; |
|---|
| 502 | 551 | |
|---|
| 503 | 552 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
|---|
| .. | .. |
|---|
| 580 | 629 | struct ast_vhub *vhub = ep->vhub; |
|---|
| 581 | 630 | struct ast_vhub_port *p; |
|---|
| 582 | 631 | |
|---|
| 583 | | - if (port == 0 || port > AST_VHUB_NUM_PORTS) |
|---|
| 632 | + if (port == 0 || port > vhub->max_ports) |
|---|
| 584 | 633 | return std_req_stall; |
|---|
| 585 | 634 | port--; |
|---|
| 586 | 635 | p = &vhub->ports[port]; |
|---|
| .. | .. |
|---|
| 623 | 672 | struct ast_vhub *vhub = ep->vhub; |
|---|
| 624 | 673 | struct ast_vhub_port *p; |
|---|
| 625 | 674 | |
|---|
| 626 | | - if (port == 0 || port > AST_VHUB_NUM_PORTS) |
|---|
| 675 | + if (port == 0 || port > vhub->max_ports) |
|---|
| 627 | 676 | return std_req_stall; |
|---|
| 628 | 677 | port--; |
|---|
| 629 | 678 | p = &vhub->ports[port]; |
|---|
| .. | .. |
|---|
| 669 | 718 | struct ast_vhub *vhub = ep->vhub; |
|---|
| 670 | 719 | u16 stat, chg; |
|---|
| 671 | 720 | |
|---|
| 672 | | - if (port == 0 || port > AST_VHUB_NUM_PORTS) |
|---|
| 721 | + if (port == 0 || port > vhub->max_ports) |
|---|
| 673 | 722 | return std_req_stall; |
|---|
| 674 | 723 | port--; |
|---|
| 675 | 724 | |
|---|
| .. | .. |
|---|
| 723 | 772 | case ClearPortFeature: |
|---|
| 724 | 773 | EPDBG(ep, "ClearPortFeature(%d,%d)\n", wIndex & 0xf, wValue); |
|---|
| 725 | 774 | return ast_vhub_clr_port_feature(ep, wIndex & 0xf, wValue); |
|---|
| 775 | + case ClearTTBuffer: |
|---|
| 776 | + case ResetTT: |
|---|
| 777 | + case StopTT: |
|---|
| 778 | + return std_req_complete; |
|---|
| 779 | + case GetTTState: |
|---|
| 780 | + return ast_vhub_simple_reply(ep, 0, 0, 0, 0); |
|---|
| 726 | 781 | default: |
|---|
| 727 | 782 | EPDBG(ep, "Unknown class request\n"); |
|---|
| 728 | 783 | } |
|---|
| .. | .. |
|---|
| 744 | 799 | * Forward to unsuspended ports without changing |
|---|
| 745 | 800 | * their connection status. |
|---|
| 746 | 801 | */ |
|---|
| 747 | | - for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { |
|---|
| 802 | + for (i = 0; i < vhub->max_ports; i++) { |
|---|
| 748 | 803 | struct ast_vhub_port *p = &vhub->ports[i]; |
|---|
| 749 | 804 | |
|---|
| 750 | 805 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
|---|
| .. | .. |
|---|
| 767 | 822 | * Forward to unsuspended ports without changing |
|---|
| 768 | 823 | * their connection status. |
|---|
| 769 | 824 | */ |
|---|
| 770 | | - for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { |
|---|
| 825 | + for (i = 0; i < vhub->max_ports; i++) { |
|---|
| 771 | 826 | struct ast_vhub_port *p = &vhub->ports[i]; |
|---|
| 772 | 827 | |
|---|
| 773 | 828 | if (!(p->status & USB_PORT_STAT_SUSPEND)) |
|---|
| .. | .. |
|---|
| 801 | 856 | * Clear all port status, disable gadgets and "suspend" |
|---|
| 802 | 857 | * them. They will be woken up by a port reset. |
|---|
| 803 | 858 | */ |
|---|
| 804 | | - for (i = 0; i < AST_VHUB_NUM_PORTS; i++) { |
|---|
| 859 | + for (i = 0; i < vhub->max_ports; i++) { |
|---|
| 805 | 860 | struct ast_vhub_port *p = &vhub->ports[i]; |
|---|
| 806 | 861 | |
|---|
| 807 | 862 | /* Only keep the connected flag */ |
|---|
| .. | .. |
|---|
| 821 | 876 | writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); |
|---|
| 822 | 877 | } |
|---|
| 823 | 878 | |
|---|
| 824 | | -void ast_vhub_init_hub(struct ast_vhub *vhub) |
|---|
| 879 | +static void ast_vhub_of_parse_dev_desc(struct ast_vhub *vhub, |
|---|
| 880 | + const struct device_node *vhub_np) |
|---|
| 881 | +{ |
|---|
| 882 | + u16 id; |
|---|
| 883 | + u32 data; |
|---|
| 884 | + |
|---|
| 885 | + if (!of_property_read_u32(vhub_np, "vhub-vendor-id", &data)) { |
|---|
| 886 | + id = (u16)data; |
|---|
| 887 | + vhub->vhub_dev_desc.idVendor = cpu_to_le16(id); |
|---|
| 888 | + } |
|---|
| 889 | + if (!of_property_read_u32(vhub_np, "vhub-product-id", &data)) { |
|---|
| 890 | + id = (u16)data; |
|---|
| 891 | + vhub->vhub_dev_desc.idProduct = cpu_to_le16(id); |
|---|
| 892 | + } |
|---|
| 893 | + if (!of_property_read_u32(vhub_np, "vhub-device-revision", &data)) { |
|---|
| 894 | + id = (u16)data; |
|---|
| 895 | + vhub->vhub_dev_desc.bcdDevice = cpu_to_le16(id); |
|---|
| 896 | + } |
|---|
| 897 | +} |
|---|
| 898 | + |
|---|
| 899 | +static void ast_vhub_fixup_usb1_dev_desc(struct ast_vhub *vhub) |
|---|
| 900 | +{ |
|---|
| 901 | + vhub->vhub_dev_desc.bcdUSB = cpu_to_le16(0x0100); |
|---|
| 902 | + vhub->vhub_dev_desc.bDeviceProtocol = 0; |
|---|
| 903 | +} |
|---|
| 904 | + |
|---|
| 905 | +static struct usb_gadget_string_container* |
|---|
| 906 | +ast_vhub_str_container_alloc(struct ast_vhub *vhub) |
|---|
| 907 | +{ |
|---|
| 908 | + unsigned int size; |
|---|
| 909 | + struct usb_string *str_array; |
|---|
| 910 | + struct usb_gadget_strings *lang_str; |
|---|
| 911 | + struct usb_gadget_string_container *container; |
|---|
| 912 | + |
|---|
| 913 | + size = sizeof(*container); |
|---|
| 914 | + size += sizeof(struct usb_gadget_strings); |
|---|
| 915 | + size += sizeof(struct usb_string) * AST_VHUB_STR_INDEX_MAX; |
|---|
| 916 | + container = devm_kzalloc(&vhub->pdev->dev, size, GFP_KERNEL); |
|---|
| 917 | + if (!container) |
|---|
| 918 | + return ERR_PTR(-ENOMEM); |
|---|
| 919 | + |
|---|
| 920 | + lang_str = ast_vhub_str_of_container(container); |
|---|
| 921 | + str_array = (struct usb_string *)(lang_str + 1); |
|---|
| 922 | + lang_str->strings = str_array; |
|---|
| 923 | + return container; |
|---|
| 924 | +} |
|---|
| 925 | + |
|---|
| 926 | +static void ast_vhub_str_deep_copy(struct usb_gadget_strings *dest, |
|---|
| 927 | + const struct usb_gadget_strings *src) |
|---|
| 928 | +{ |
|---|
| 929 | + struct usb_string *src_array = src->strings; |
|---|
| 930 | + struct usb_string *dest_array = dest->strings; |
|---|
| 931 | + |
|---|
| 932 | + dest->language = src->language; |
|---|
| 933 | + if (src_array && dest_array) { |
|---|
| 934 | + do { |
|---|
| 935 | + *dest_array = *src_array; |
|---|
| 936 | + dest_array++; |
|---|
| 937 | + src_array++; |
|---|
| 938 | + } while (src_array->s); |
|---|
| 939 | + } |
|---|
| 940 | +} |
|---|
| 941 | + |
|---|
| 942 | +static int ast_vhub_str_alloc_add(struct ast_vhub *vhub, |
|---|
| 943 | + const struct usb_gadget_strings *src_str) |
|---|
| 944 | +{ |
|---|
| 945 | + struct usb_gadget_strings *dest_str; |
|---|
| 946 | + struct usb_gadget_string_container *container; |
|---|
| 947 | + |
|---|
| 948 | + container = ast_vhub_str_container_alloc(vhub); |
|---|
| 949 | + if (IS_ERR(container)) |
|---|
| 950 | + return PTR_ERR(container); |
|---|
| 951 | + |
|---|
| 952 | + dest_str = ast_vhub_str_of_container(container); |
|---|
| 953 | + ast_vhub_str_deep_copy(dest_str, src_str); |
|---|
| 954 | + list_add_tail(&container->list, &vhub->vhub_str_desc); |
|---|
| 955 | + |
|---|
| 956 | + return 0; |
|---|
| 957 | +} |
|---|
| 958 | + |
|---|
| 959 | +static const struct { |
|---|
| 960 | + const char *name; |
|---|
| 961 | + u8 id; |
|---|
| 962 | +} str_id_map[] = { |
|---|
| 963 | + {"manufacturer", AST_VHUB_STR_MANUF}, |
|---|
| 964 | + {"product", AST_VHUB_STR_PRODUCT}, |
|---|
| 965 | + {"serial-number", AST_VHUB_STR_SERIAL}, |
|---|
| 966 | + {}, |
|---|
| 967 | +}; |
|---|
| 968 | + |
|---|
| 969 | +static int ast_vhub_of_parse_str_desc(struct ast_vhub *vhub, |
|---|
| 970 | + const struct device_node *desc_np) |
|---|
| 971 | +{ |
|---|
| 972 | + u32 langid; |
|---|
| 973 | + int ret = 0; |
|---|
| 974 | + int i, offset; |
|---|
| 975 | + const char *str; |
|---|
| 976 | + struct device_node *child; |
|---|
| 977 | + struct usb_string str_array[AST_VHUB_STR_INDEX_MAX]; |
|---|
| 978 | + struct usb_gadget_strings lang_str = { |
|---|
| 979 | + .strings = (struct usb_string *)str_array, |
|---|
| 980 | + }; |
|---|
| 981 | + |
|---|
| 982 | + for_each_child_of_node(desc_np, child) { |
|---|
| 983 | + if (of_property_read_u32(child, "reg", &langid)) |
|---|
| 984 | + continue; /* no language identifier specified */ |
|---|
| 985 | + |
|---|
| 986 | + if (!usb_validate_langid(langid)) |
|---|
| 987 | + continue; /* invalid language identifier */ |
|---|
| 988 | + |
|---|
| 989 | + lang_str.language = langid; |
|---|
| 990 | + for (i = offset = 0; str_id_map[i].name; i++) { |
|---|
| 991 | + str = of_get_property(child, str_id_map[i].name, NULL); |
|---|
| 992 | + if (str) { |
|---|
| 993 | + str_array[offset].s = str; |
|---|
| 994 | + str_array[offset].id = str_id_map[i].id; |
|---|
| 995 | + offset++; |
|---|
| 996 | + } |
|---|
| 997 | + } |
|---|
| 998 | + str_array[offset].id = 0; |
|---|
| 999 | + str_array[offset].s = NULL; |
|---|
| 1000 | + |
|---|
| 1001 | + ret = ast_vhub_str_alloc_add(vhub, &lang_str); |
|---|
| 1002 | + if (ret) { |
|---|
| 1003 | + of_node_put(child); |
|---|
| 1004 | + break; |
|---|
| 1005 | + } |
|---|
| 1006 | + } |
|---|
| 1007 | + |
|---|
| 1008 | + return ret; |
|---|
| 1009 | +} |
|---|
| 1010 | + |
|---|
| 1011 | +static int ast_vhub_init_desc(struct ast_vhub *vhub) |
|---|
| 1012 | +{ |
|---|
| 1013 | + int ret; |
|---|
| 1014 | + struct device_node *desc_np; |
|---|
| 1015 | + const struct device_node *vhub_np = vhub->pdev->dev.of_node; |
|---|
| 1016 | + |
|---|
| 1017 | + /* Initialize vhub Device Descriptor. */ |
|---|
| 1018 | + memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc, |
|---|
| 1019 | + sizeof(vhub->vhub_dev_desc)); |
|---|
| 1020 | + ast_vhub_of_parse_dev_desc(vhub, vhub_np); |
|---|
| 1021 | + if (vhub->force_usb1) |
|---|
| 1022 | + ast_vhub_fixup_usb1_dev_desc(vhub); |
|---|
| 1023 | + |
|---|
| 1024 | + /* Initialize vhub Configuration Descriptor. */ |
|---|
| 1025 | + memcpy(&vhub->vhub_conf_desc, &ast_vhub_conf_desc, |
|---|
| 1026 | + sizeof(vhub->vhub_conf_desc)); |
|---|
| 1027 | + |
|---|
| 1028 | + /* Initialize vhub Hub Descriptor. */ |
|---|
| 1029 | + memcpy(&vhub->vhub_hub_desc, &ast_vhub_hub_desc, |
|---|
| 1030 | + sizeof(vhub->vhub_hub_desc)); |
|---|
| 1031 | + vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports; |
|---|
| 1032 | + |
|---|
| 1033 | + /* Initialize vhub String Descriptors. */ |
|---|
| 1034 | + INIT_LIST_HEAD(&vhub->vhub_str_desc); |
|---|
| 1035 | + desc_np = of_get_child_by_name(vhub_np, "vhub-strings"); |
|---|
| 1036 | + if (desc_np) { |
|---|
| 1037 | + ret = ast_vhub_of_parse_str_desc(vhub, desc_np); |
|---|
| 1038 | + of_node_put(desc_np); |
|---|
| 1039 | + } |
|---|
| 1040 | + else |
|---|
| 1041 | + ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings); |
|---|
| 1042 | + |
|---|
| 1043 | + return ret; |
|---|
| 1044 | +} |
|---|
| 1045 | + |
|---|
| 1046 | +int ast_vhub_init_hub(struct ast_vhub *vhub) |
|---|
| 825 | 1047 | { |
|---|
| 826 | 1048 | vhub->speed = USB_SPEED_UNKNOWN; |
|---|
| 827 | 1049 | INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); |
|---|
| 828 | | -} |
|---|
| 829 | 1050 | |
|---|
| 1051 | + return ast_vhub_init_desc(vhub); |
|---|
| 1052 | +} |
|---|