cmdline.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Test driver for GNSS. This driver requires the serdev binding and protocol
  4. * type to be specified on the module command line.
  5. *
  6. * Copyright 2019 Google LLC
  7. */
  8. #include <linux/device.h>
  9. #include <linux/gnss.h>
  10. #include <linux/module.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/serdev.h>
  13. #include <linux/slab.h>
  14. #include <linux/string.h>
  15. #include "serial.h"
  16. #define GNSS_CMDLINE_MODULE_NAME "gnss-cmdline"
  17. #define gnss_cmdline_err(...) \
  18. pr_err(GNSS_CMDLINE_MODULE_NAME ": " __VA_ARGS__)
  19. static char *serdev;
  20. module_param(serdev, charp, 0644);
  21. MODULE_PARM_DESC(serdev, "serial device to wrap");
  22. static int type;
  23. module_param(type, int, 0644);
  24. MODULE_PARM_DESC(serdev, "GNSS protocol type (see 'enum gnss_type')");
  25. static struct serdev_device *serdev_device;
  26. static int name_match(struct device *dev, void *data)
  27. {
  28. return strstr(dev_name(dev), data) != NULL;
  29. }
  30. static int __init gnss_cmdline_init(void)
  31. {
  32. struct device *serial_dev, *port_dev, *serdev_dev;
  33. char *driver_name, *port_name, *serdev_name;
  34. char *serdev_dup, *serdev_dup_sep;
  35. struct gnss_serial *gserial;
  36. int err = -ENODEV;
  37. /* User did not set the serdev module parameter */
  38. if (!serdev)
  39. return 0;
  40. if (type < 0 || type >= GNSS_TYPE_COUNT) {
  41. gnss_cmdline_err("invalid gnss type '%d'\n", type);
  42. return -EINVAL;
  43. }
  44. serdev_dup = serdev_dup_sep = kstrdup(serdev, GFP_KERNEL);
  45. if (!serdev_dup)
  46. return -ENOMEM;
  47. driver_name = strsep(&serdev_dup_sep, "/");
  48. if (!driver_name) {
  49. gnss_cmdline_err("driver name missing\n");
  50. goto err_free_serdev_dup;
  51. }
  52. port_name = strsep(&serdev_dup_sep, "/");
  53. if (!port_name) {
  54. gnss_cmdline_err("port name missing\n");
  55. goto err_free_serdev_dup;
  56. }
  57. serdev_name = strsep(&serdev_dup_sep, "/");
  58. if (!serdev_name) {
  59. gnss_cmdline_err("serdev name missing\n");
  60. goto err_free_serdev_dup;
  61. }
  62. /* Find the driver device instance (e.g. serial8250) */
  63. serial_dev = bus_find_device_by_name(&platform_bus_type,
  64. NULL, driver_name);
  65. if (!serial_dev) {
  66. gnss_cmdline_err("no device '%s'\n", driver_name);
  67. goto err_free_serdev_dup;
  68. }
  69. /* Find the port device instance (e.g. serial0) */
  70. port_dev = device_find_child(serial_dev, port_name, name_match);
  71. if (!port_dev) {
  72. gnss_cmdline_err("no port '%s'\n", port_name);
  73. goto err_free_serdev_dup;
  74. }
  75. /* Find the serdev device instance (e.g. serial0-0) */
  76. serdev_dev = device_find_child(port_dev, serdev_name, name_match);
  77. if (!serdev_dev) {
  78. gnss_cmdline_err("no serdev '%s'\n", serdev_name);
  79. goto err_free_serdev_dup;
  80. }
  81. gserial = gnss_serial_allocate(to_serdev_device(serdev_dev), 0);
  82. if (IS_ERR(gserial)) {
  83. err = PTR_ERR(gserial);
  84. goto err_free_serdev_dup;
  85. }
  86. gserial->gdev->type = type;
  87. err = gnss_serial_register(gserial);
  88. if (err) {
  89. gnss_serial_free(gserial);
  90. goto err_free_serdev_dup;
  91. }
  92. serdev_device = to_serdev_device(serdev_dev);
  93. err = 0;
  94. err_free_serdev_dup:
  95. kfree(serdev_dup);
  96. return err;
  97. }
  98. static void __exit gnss_cmdline_exit(void)
  99. {
  100. struct gnss_serial *gserial;
  101. if (!serdev_device)
  102. return;
  103. gserial = serdev_device_get_drvdata(serdev_device);
  104. gnss_serial_deregister(gserial);
  105. gnss_serial_free(gserial);
  106. }
  107. module_init(gnss_cmdline_init);
  108. module_exit(gnss_cmdline_exit);
  109. MODULE_AUTHOR("Alistair Delva <adelva@google.com>");
  110. MODULE_DESCRIPTION("GNSS command line driver");
  111. MODULE_LICENSE("GPL v2");