123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
- * Copyright (C) 2015-2016 Samsung Electronics
- * Igor Kotrasinski <i.kotrasinsk@samsung.com>
- * Krzysztof Opasiak <k.opasiak@samsung.com>
- */
- #include <linux/device.h>
- #include <linux/list.h>
- #include <linux/module.h>
- #include "vudc.h"
- static unsigned int vudc_number = 1;
- module_param_named(num, vudc_number, uint, S_IRUGO);
- MODULE_PARM_DESC(num, "number of emulated controllers");
- static struct platform_driver vudc_driver = {
- .probe = vudc_probe,
- .remove = vudc_remove,
- .driver = {
- .name = GADGET_NAME,
- },
- };
- static struct list_head vudc_devices = LIST_HEAD_INIT(vudc_devices);
- static int __init init(void)
- {
- int retval = -ENOMEM;
- int i;
- struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
- if (usb_disabled())
- return -ENODEV;
- if (vudc_number < 1) {
- pr_err("Number of emulated UDC must be no less than 1");
- return -EINVAL;
- }
- retval = platform_driver_register(&vudc_driver);
- if (retval < 0)
- goto out;
- for (i = 0; i < vudc_number; i++) {
- udc_dev = alloc_vudc_device(i);
- if (!udc_dev) {
- retval = -ENOMEM;
- goto cleanup;
- }
- retval = platform_device_add(udc_dev->pdev);
- if (retval < 0) {
- put_vudc_device(udc_dev);
- goto cleanup;
- }
- list_add_tail(&udc_dev->dev_entry, &vudc_devices);
- if (!platform_get_drvdata(udc_dev->pdev)) {
- /*
- * The udc was added successfully but its probe
- * function failed for some reason.
- */
- retval = -EINVAL;
- goto cleanup;
- }
- }
- goto out;
- cleanup:
- list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
- list_del(&udc_dev->dev_entry);
- /*
- * Just do platform_device_del() here, put_vudc_device()
- * calls the platform_device_put()
- */
- platform_device_del(udc_dev->pdev);
- put_vudc_device(udc_dev);
- }
- platform_driver_unregister(&vudc_driver);
- out:
- return retval;
- }
- module_init(init);
- static void __exit cleanup(void)
- {
- struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
- list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
- list_del(&udc_dev->dev_entry);
- /*
- * Just do platform_device_del() here, put_vudc_device()
- * calls the platform_device_put()
- */
- platform_device_del(udc_dev->pdev);
- put_vudc_device(udc_dev);
- }
- platform_driver_unregister(&vudc_driver);
- }
- module_exit(cleanup);
- MODULE_DESCRIPTION("USB over IP Device Controller");
- MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski");
- MODULE_LICENSE("GPL");
|