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