kapi.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * kernel API
  3. *
  4. *
  5. * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it>
  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, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/init.h>
  25. #include <linux/sched.h>
  26. #include <linux/time.h>
  27. #include <linux/spinlock.h>
  28. #include <linux/fs.h>
  29. #include <linux/pps_kernel.h>
  30. #include <linux/slab.h>
  31. /*
  32. * Local functions
  33. */
  34. static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
  35. {
  36. ts->nsec += offset->nsec;
  37. while (ts->nsec >= NSEC_PER_SEC) {
  38. ts->nsec -= NSEC_PER_SEC;
  39. ts->sec++;
  40. }
  41. while (ts->nsec < 0) {
  42. ts->nsec += NSEC_PER_SEC;
  43. ts->sec--;
  44. }
  45. ts->sec += offset->sec;
  46. }
  47. /*
  48. * Exported functions
  49. */
  50. /* pps_register_source - add a PPS source in the system
  51. * @info: the PPS info struct
  52. * @default_params: the default PPS parameters of the new source
  53. *
  54. * This function is used to add a new PPS source in the system. The new
  55. * source is described by info's fields and it will have, as default PPS
  56. * parameters, the ones specified into default_params.
  57. *
  58. * The function returns, in case of success, the PPS device. Otherwise NULL.
  59. */
  60. struct pps_device *pps_register_source(struct pps_source_info *info,
  61. int default_params)
  62. {
  63. struct pps_device *pps;
  64. int err;
  65. /* Sanity checks */
  66. if ((info->mode & default_params) != default_params) {
  67. pr_err("%s: unsupported default parameters\n",
  68. info->name);
  69. err = -EINVAL;
  70. goto pps_register_source_exit;
  71. }
  72. if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
  73. info->echo == NULL) {
  74. pr_err("%s: echo function is not defined\n",
  75. info->name);
  76. err = -EINVAL;
  77. goto pps_register_source_exit;
  78. }
  79. if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
  80. pr_err("%s: unspecified time format\n",
  81. info->name);
  82. err = -EINVAL;
  83. goto pps_register_source_exit;
  84. }
  85. /* Allocate memory for the new PPS source struct */
  86. pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
  87. if (pps == NULL) {
  88. err = -ENOMEM;
  89. goto pps_register_source_exit;
  90. }
  91. /* These initializations must be done before calling idr_get_new()
  92. * in order to avoid reces into pps_event().
  93. */
  94. pps->params.api_version = PPS_API_VERS;
  95. pps->params.mode = default_params;
  96. pps->info = *info;
  97. init_waitqueue_head(&pps->queue);
  98. spin_lock_init(&pps->lock);
  99. /* Create the char device */
  100. err = pps_register_cdev(pps);
  101. if (err < 0) {
  102. pr_err("%s: unable to create char device\n",
  103. info->name);
  104. goto kfree_pps;
  105. }
  106. dev_info(pps->dev, "new PPS source %s\n", info->name);
  107. return pps;
  108. kfree_pps:
  109. kfree(pps);
  110. pps_register_source_exit:
  111. pr_err("%s: unable to register source\n", info->name);
  112. return NULL;
  113. }
  114. EXPORT_SYMBOL(pps_register_source);
  115. /* pps_unregister_source - remove a PPS source from the system
  116. * @pps: the PPS source
  117. *
  118. * This function is used to remove a previously registered PPS source from
  119. * the system.
  120. */
  121. void pps_unregister_source(struct pps_device *pps)
  122. {
  123. pps_unregister_cdev(pps);
  124. /* don't have to kfree(pps) here because it will be done on
  125. * device destruction */
  126. }
  127. EXPORT_SYMBOL(pps_unregister_source);
  128. /* pps_event - register a PPS event into the system
  129. * @pps: the PPS device
  130. * @ts: the event timestamp
  131. * @event: the event type
  132. * @data: userdef pointer
  133. *
  134. * This function is used by each PPS client in order to register a new
  135. * PPS event into the system (it's usually called inside an IRQ handler).
  136. *
  137. * If an echo function is associated with the PPS device it will be called
  138. * as:
  139. * pps->info.echo(pps, event, data);
  140. */
  141. void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
  142. void *data)
  143. {
  144. unsigned long flags;
  145. int captured = 0;
  146. struct pps_ktime ts_real;
  147. if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
  148. dev_err(pps->dev, "unknown event (%x)\n", event);
  149. return;
  150. }
  151. dev_dbg(pps->dev, "PPS event at %ld.%09ld\n",
  152. ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
  153. timespec_to_pps_ktime(&ts_real, ts->ts_real);
  154. spin_lock_irqsave(&pps->lock, flags);
  155. /* Must call the echo function? */
  156. if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
  157. pps->info.echo(pps, event, data);
  158. /* Check the event */
  159. pps->current_mode = pps->params.mode;
  160. if ((event & PPS_CAPTUREASSERT) &
  161. (pps->params.mode & PPS_CAPTUREASSERT)) {
  162. /* We have to add an offset? */
  163. if (pps->params.mode & PPS_OFFSETASSERT)
  164. pps_add_offset(&ts_real,
  165. &pps->params.assert_off_tu);
  166. /* Save the time stamp */
  167. pps->assert_tu = ts_real;
  168. pps->assert_sequence++;
  169. dev_dbg(pps->dev, "capture assert seq #%u\n",
  170. pps->assert_sequence);
  171. captured = ~0;
  172. }
  173. if ((event & PPS_CAPTURECLEAR) &
  174. (pps->params.mode & PPS_CAPTURECLEAR)) {
  175. /* We have to add an offset? */
  176. if (pps->params.mode & PPS_OFFSETCLEAR)
  177. pps_add_offset(&ts_real,
  178. &pps->params.clear_off_tu);
  179. /* Save the time stamp */
  180. pps->clear_tu = ts_real;
  181. pps->clear_sequence++;
  182. dev_dbg(pps->dev, "capture clear seq #%u\n",
  183. pps->clear_sequence);
  184. captured = ~0;
  185. }
  186. /* Wake up if captured something */
  187. if (captured) {
  188. pps->last_ev++;
  189. wake_up_interruptible_all(&pps->queue);
  190. kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
  191. }
  192. spin_unlock_irqrestore(&pps->lock, flags);
  193. }
  194. EXPORT_SYMBOL(pps_event);