vudc_main.c 2.5 KB

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