/* * diag.c -- Diag Gadget driver * * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "u_diag.h" /*-------------------------------------------------------------------------*/ static const char longname[] = "diag"; USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_VENDOR_NUM 0x05C6 #define DRIVER_PRODUCT_NUM 0x9091 /* string IDs are assigned dynamically */ #define STRING_DESCRIPTION_IDX USB_GADGET_FIRST_AVAIL_IDX static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), .bNumConfigurations = 1, }; static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "Qualcomm Technologies", [USB_GADGET_PRODUCT_IDX].s = "Diag Gadget", [USB_GADGET_SERIAL_IDX].s = "", { } /* end of list */ }; static struct usb_gadget_strings stringtab_dev = { .language = 0x0409, /* en-us */ .strings = strings_dev, }; static struct usb_gadget_strings *dev_strings[] = { &stringtab_dev, NULL, }; static struct usb_function_instance *fi_diag; static struct usb_function *f_diag; static int diag_gadget_unbind(struct usb_composite_dev *dev) { usb_put_function(f_diag); usb_put_function_instance(fi_diag); return 0; } static struct usb_configuration diag_config = { .label = "diag", .bConfigurationValue = 1, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .MaxPower = CONFIG_USB_GADGET_VBUS_DRAW, }; static int diag_bind_config(struct usb_configuration *c) { int status; f_diag = usb_get_function(fi_diag); if (IS_ERR(f_diag)) return PTR_ERR(f_diag); status = usb_add_function(c, f_diag); if (status < 0) { usb_put_function(f_diag); return status; } return 0; } static int diag_gadget_bind(struct usb_composite_dev *cdev) { struct diag_opts *diag_opts; int status; fi_diag = usb_get_function_instance("diag"); if (IS_ERR(fi_diag)) return PTR_ERR(fi_diag); diag_opts = container_of(fi_diag, struct diag_opts, func_inst); fi_diag->set_inst_name(fi_diag, "diag"); status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) goto put; device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; diag_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id; status = usb_add_config(cdev, &diag_config, diag_bind_config); if (status < 0) goto put; usb_composite_overwrite_options(cdev, &coverwrite); return 0; put: usb_put_function_instance(fi_diag); return status; } static struct usb_composite_driver diag_gadget_driver = { .name = (char *) longname, .dev = &device_desc, .strings = dev_strings, .max_speed = USB_SPEED_HIGH, .bind = diag_gadget_bind, .unbind = diag_gadget_unbind, }; static int diag_gadget_probe(struct platform_device *pdev) { usb_composite_probe(&diag_gadget_driver); return 0; } static int diag_gadget_remove(struct platform_device *pdev) { usb_composite_unregister(&diag_gadget_driver); return 0; } static const struct of_device_id diag_gadget_table[] = { {.compatible = "qcom,gadget-diag"}, {}, }; MODULE_DEVICE_TABLE(of, diag_gadget_table); static struct platform_driver diag_gadget_platform_driver = { .probe = diag_gadget_probe, .remove = diag_gadget_remove, .driver = { .name = "DIAG Gadget Platform", .owner = THIS_MODULE, .of_match_table = diag_gadget_table, }, }; module_platform_driver(diag_gadget_platform_driver); MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Diag Gadget Driver"); MODULE_LICENSE("Dual BSD/GPL");