Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
  4 * Copyright (C) 2015-2016 Samsung Electronics
  5 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
  6 *               Krzysztof Opasiak <k.opasiak@samsung.com>
  7 */
  8
  9#include <linux/device.h>
 10#include <linux/list.h>
 11#include <linux/module.h>
 12
 13#include "vudc.h"
 14
 15static unsigned int vudc_number = 1;
 16
 17module_param_named(num, vudc_number, uint, S_IRUGO);
 18MODULE_PARM_DESC(num, "number of emulated controllers");
 19
 20static struct platform_driver vudc_driver = {
 21	.probe		= vudc_probe,
 22	.remove_new	= vudc_remove,
 23	.driver		= {
 24		.name	= GADGET_NAME,
 25		.dev_groups = vudc_groups,
 26	},
 27};
 28
 29static LIST_HEAD(vudc_devices);
 30
 31static int __init vudc_init(void)
 32{
 33	int retval = -ENOMEM;
 34	int i;
 35	struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
 36
 37	if (usb_disabled())
 38		return -ENODEV;
 39
 40	if (vudc_number < 1) {
 41		pr_err("Number of emulated UDC must be no less than 1");
 42		return -EINVAL;
 43	}
 44
 45	retval = platform_driver_register(&vudc_driver);
 46	if (retval < 0)
 47		goto out;
 48
 49	for (i = 0; i < vudc_number; i++) {
 50		udc_dev = alloc_vudc_device(i);
 51		if (!udc_dev) {
 52			retval = -ENOMEM;
 53			goto cleanup;
 54		}
 55
 56		retval = platform_device_add(udc_dev->pdev);
 57		if (retval < 0) {
 58			put_vudc_device(udc_dev);
 59			goto cleanup;
 60		}
 61
 62		list_add_tail(&udc_dev->dev_entry, &vudc_devices);
 63		if (!platform_get_drvdata(udc_dev->pdev)) {
 64			/*
 65			 * The udc was added successfully but its probe
 66			 * function failed for some reason.
 67			 */
 68			retval = -EINVAL;
 69			goto cleanup;
 70		}
 71	}
 72	goto out;
 73
 74cleanup:
 75	list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
 76		list_del(&udc_dev->dev_entry);
 77		/*
 78		 * Just do platform_device_del() here, put_vudc_device()
 79		 * calls the platform_device_put()
 80		 */
 81		platform_device_del(udc_dev->pdev);
 82		put_vudc_device(udc_dev);
 83	}
 84
 85	platform_driver_unregister(&vudc_driver);
 86out:
 87	return retval;
 88}
 89module_init(vudc_init);
 90
 91static void __exit vudc_cleanup(void)
 92{
 93	struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
 94
 95	list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
 96		list_del(&udc_dev->dev_entry);
 97		/*
 98		 * Just do platform_device_del() here, put_vudc_device()
 99		 * calls the platform_device_put()
100		 */
101		platform_device_del(udc_dev->pdev);
102		put_vudc_device(udc_dev);
103	}
104	platform_driver_unregister(&vudc_driver);
105}
106module_exit(vudc_cleanup);
107
108MODULE_DESCRIPTION("USB over IP Device Controller");
109MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski");
110MODULE_LICENSE("GPL");