Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
0004  * Copyright (C) 2015-2016 Samsung Electronics
0005  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
0006  *               Krzysztof Opasiak <k.opasiak@samsung.com>
0007  */
0008 
0009 #include <linux/device.h>
0010 #include <linux/list.h>
0011 #include <linux/module.h>
0012 
0013 #include "vudc.h"
0014 
0015 static unsigned int vudc_number = 1;
0016 
0017 module_param_named(num, vudc_number, uint, S_IRUGO);
0018 MODULE_PARM_DESC(num, "number of emulated controllers");
0019 
0020 static struct platform_driver vudc_driver = {
0021     .probe      = vudc_probe,
0022     .remove     = vudc_remove,
0023     .driver     = {
0024         .name   = GADGET_NAME,
0025         .dev_groups = vudc_groups,
0026     },
0027 };
0028 
0029 static LIST_HEAD(vudc_devices);
0030 
0031 static int __init vudc_init(void)
0032 {
0033     int retval = -ENOMEM;
0034     int i;
0035     struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
0036 
0037     if (usb_disabled())
0038         return -ENODEV;
0039 
0040     if (vudc_number < 1) {
0041         pr_err("Number of emulated UDC must be no less than 1");
0042         return -EINVAL;
0043     }
0044 
0045     retval = platform_driver_register(&vudc_driver);
0046     if (retval < 0)
0047         goto out;
0048 
0049     for (i = 0; i < vudc_number; i++) {
0050         udc_dev = alloc_vudc_device(i);
0051         if (!udc_dev) {
0052             retval = -ENOMEM;
0053             goto cleanup;
0054         }
0055 
0056         retval = platform_device_add(udc_dev->pdev);
0057         if (retval < 0) {
0058             put_vudc_device(udc_dev);
0059             goto cleanup;
0060         }
0061 
0062         list_add_tail(&udc_dev->dev_entry, &vudc_devices);
0063         if (!platform_get_drvdata(udc_dev->pdev)) {
0064             /*
0065              * The udc was added successfully but its probe
0066              * function failed for some reason.
0067              */
0068             retval = -EINVAL;
0069             goto cleanup;
0070         }
0071     }
0072     goto out;
0073 
0074 cleanup:
0075     list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
0076         list_del(&udc_dev->dev_entry);
0077         /*
0078          * Just do platform_device_del() here, put_vudc_device()
0079          * calls the platform_device_put()
0080          */
0081         platform_device_del(udc_dev->pdev);
0082         put_vudc_device(udc_dev);
0083     }
0084 
0085     platform_driver_unregister(&vudc_driver);
0086 out:
0087     return retval;
0088 }
0089 module_init(vudc_init);
0090 
0091 static void __exit vudc_cleanup(void)
0092 {
0093     struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
0094 
0095     list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
0096         list_del(&udc_dev->dev_entry);
0097         /*
0098          * Just do platform_device_del() here, put_vudc_device()
0099          * calls the platform_device_put()
0100          */
0101         platform_device_del(udc_dev->pdev);
0102         put_vudc_device(udc_dev);
0103     }
0104     platform_driver_unregister(&vudc_driver);
0105 }
0106 module_exit(vudc_cleanup);
0107 
0108 MODULE_DESCRIPTION("USB over IP Device Controller");
0109 MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski");
0110 MODULE_LICENSE("GPL");