vudc_main.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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. #include <linux/device.h>
  21. #include <linux/list.h>
  22. #include <linux/module.h>
  23. #include "vudc.h"
  24. static unsigned int vudc_number = 1;
  25. module_param_named(num, vudc_number, uint, S_IRUGO);
  26. MODULE_PARM_DESC(num, "number of emulated controllers");
  27. static struct platform_driver vudc_driver = {
  28. .probe = vudc_probe,
  29. .remove = vudc_remove,
  30. .driver = {
  31. .name = GADGET_NAME,
  32. },
  33. };
  34. static struct list_head vudc_devices = LIST_HEAD_INIT(vudc_devices);
  35. static int __init init(void)
  36. {
  37. int retval = -ENOMEM;
  38. int i;
  39. struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
  40. if (usb_disabled())
  41. return -ENODEV;
  42. if (vudc_number < 1) {
  43. pr_err("Number of emulated UDC must be no less than 1");
  44. return -EINVAL;
  45. }
  46. retval = platform_driver_register(&vudc_driver);
  47. if (retval < 0)
  48. goto out;
  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. retval = platform_device_add(udc_dev->pdev);
  56. if (retval < 0) {
  57. put_vudc_device(udc_dev);
  58. goto cleanup;
  59. }
  60. list_add_tail(&udc_dev->dev_entry, &vudc_devices);
  61. if (!platform_get_drvdata(udc_dev->pdev)) {
  62. /*
  63. * The udc was added successfully but its probe
  64. * function failed for some reason.
  65. */
  66. retval = -EINVAL;
  67. goto cleanup;
  68. }
  69. }
  70. goto out;
  71. cleanup:
  72. list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
  73. list_del(&udc_dev->dev_entry);
  74. platform_device_del(udc_dev->pdev);
  75. put_vudc_device(udc_dev);
  76. }
  77. platform_driver_unregister(&vudc_driver);
  78. out:
  79. return retval;
  80. }
  81. module_init(init);
  82. static void __exit cleanup(void)
  83. {
  84. struct vudc_device *udc_dev = NULL, *udc_dev2 = NULL;
  85. list_for_each_entry_safe(udc_dev, udc_dev2, &vudc_devices, dev_entry) {
  86. list_del(&udc_dev->dev_entry);
  87. platform_device_unregister(udc_dev->pdev);
  88. put_vudc_device(udc_dev);
  89. }
  90. platform_driver_unregister(&vudc_driver);
  91. }
  92. module_exit(cleanup);
  93. MODULE_DESCRIPTION("USB over IP Device Controller");
  94. MODULE_AUTHOR("Krzysztof Opasiak, Karol Kosik, Igor Kotrasinski");
  95. MODULE_LICENSE("GPL");