• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
3   * Copyright (C) 2015-2016 Samsung Electronics
4   *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
5   *               Krzysztof Opasiak <k.opasiak@samsung.com>
6   *
7   * This program is free software; you can redistribute it and/or modify
8   * it under the terms of the GNU General Public License as published by
9   * the Free Software Foundation; either version 2 of the License, or
10   * (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with this program. If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  #include <linux/device.h>
22  #include <linux/list.h>
23  #include <linux/module.h>
24  
25  #include "vudc.h"
26  
27  static unsigned int vudc_number = 1;
28  
29  module_param_named(num, vudc_number, uint, S_IRUGO);
30  MODULE_PARM_DESC(num, "number of emulated controllers");
31  
32  static struct platform_driver vudc_driver = {
33  	.probe		= vudc_probe,
34  	.remove		= vudc_remove,
35  	.driver		= {
36  		.name	= GADGET_NAME,
37  	},
38  };
39  
40  static struct list_head vudc_devices = LIST_HEAD_INIT(vudc_devices);
41  
init(void)42  static int __init init(void)
43  {
44  	int retval = -ENOMEM;
45  	int i;
46  	struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
47  
48  	if (usb_disabled())
49  		return -ENODEV;
50  
51  	if (vudc_number < 1) {
52  		pr_err("Number of emulated UDC must be no less than 1");
53  		return -EINVAL;
54  	}
55  
56  	retval = platform_driver_register(&vudc_driver);
57  	if (retval < 0)
58  		goto out;
59  
60  	for (i = 0; i < vudc_number; i++) {
61  		udc_dev = alloc_vudc_device(i);
62  		if (!udc_dev) {
63  			retval = -ENOMEM;
64  			goto cleanup;
65  		}
66  
67  		retval = platform_device_add(udc_dev->pdev);
68  		if (retval < 0) {
69  			put_vudc_device(udc_dev);
70  			goto cleanup;
71  		}
72  
73  		list_add_tail(&udc_dev->dev_entry, &vudc_devices);
74  		if (!platform_get_drvdata(udc_dev->pdev)) {
75  			/*
76  			 * The udc was added successfully but its probe
77  			 * function failed for some reason.
78  			 */
79  			retval = -EINVAL;
80  			goto cleanup;
81  		}
82  	}
83  	goto out;
84  
85  cleanup:
86  	list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
87  		list_del(&udc_dev->dev_entry);
88  		/*
89  		 * Just do platform_device_del() here, put_vudc_device()
90  		 * calls the platform_device_put()
91  		 */
92  		platform_device_del(udc_dev->pdev);
93  		put_vudc_device(udc_dev);
94  	}
95  
96  	platform_driver_unregister(&vudc_driver);
97  out:
98  	return retval;
99  }
100  module_init(init);
101  
cleanup(void)102  static void __exit cleanup(void)
103  {
104  	struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
105  
106  	list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
107  		list_del(&udc_dev->dev_entry);
108  		/*
109  		 * Just do platform_device_del() here, put_vudc_device()
110  		 * calls the platform_device_put()
111  		 */
112  		platform_device_del(udc_dev->pdev);
113  		put_vudc_device(udc_dev);
114  	}
115  	platform_driver_unregister(&vudc_driver);
116  }
117  module_exit(cleanup);
118  
119  MODULE_DESCRIPTION("USB over IP Device Controller");
120  MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski");
121  MODULE_LICENSE("GPL");
122