kapi.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. #include <linux/kernel.h>
  22. #include <linux/module.h>
  23. #include <linux/init.h>
  24. #include <linux/sched.h>
  25. #include <linux/time.h>
  26. #include <linux/spinlock.h>
  27. #include <linux/idr.h>
  28. #include <linux/fs.h>
  29. #include <linux/pps_kernel.h>
  30. /*
  31. * Global variables
  32. */
  33. DEFINE_SPINLOCK(pps_idr_lock);
  34. DEFINE_IDR(pps_idr);
  35. /*
  36. * Local functions
  37. */
  38. static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
  39. {
  40. ts->nsec += offset->nsec;
  41. while (ts->nsec >= NSEC_PER_SEC) {
  42. ts->nsec -= NSEC_PER_SEC;
  43. ts->sec++;
  44. }
  45. while (ts->nsec < 0) {
  46. ts->nsec += NSEC_PER_SEC;
  47. ts->sec--;
  48. }
  49. ts->sec += offset->sec;
  50. }
  51. /*
  52. * Exported functions
  53. */
  54. /* pps_get_source - find a PPS source
  55. * @source: the PPS source ID.
  56. *
  57. * This function is used to find an already registered PPS source into the
  58. * system.
  59. *
  60. * The function returns NULL if found nothing, otherwise it returns a pointer
  61. * to the PPS source data struct (the refcounter is incremented by 1).
  62. */
  63. struct pps_device *pps_get_source(int source)
  64. {
  65. struct pps_device *pps;
  66. unsigned long flags;
  67. spin_lock_irqsave(&pps_idr_lock, flags);
  68. pps = idr_find(&pps_idr, source);
  69. if (pps != NULL)
  70. atomic_inc(&pps->usage);
  71. spin_unlock_irqrestore(&pps_idr_lock, flags);
  72. return pps;
  73. }
  74. /* pps_put_source - free the PPS source data
  75. * @pps: a pointer to the PPS source.
  76. *
  77. * This function is used to free a PPS data struct if its refcount is 0.
  78. */
  79. void pps_put_source(struct pps_device *pps)
  80. {
  81. unsigned long flags;
  82. spin_lock_irqsave(&pps_idr_lock, flags);
  83. BUG_ON(atomic_read(&pps->usage) == 0);
  84. if (!atomic_dec_and_test(&pps->usage)) {
  85. pps = NULL;
  86. goto exit;
  87. }
  88. /* No more reference to the PPS source. We can safely remove the
  89. * PPS data struct.
  90. */
  91. idr_remove(&pps_idr, pps->id);
  92. exit:
  93. spin_unlock_irqrestore(&pps_idr_lock, flags);
  94. kfree(pps);
  95. }
  96. /* pps_register_source - add a PPS source in the system
  97. * @info: the PPS info struct
  98. * @default_params: the default PPS parameters of the new source
  99. *
  100. * This function is used to add a new PPS source in the system. The new
  101. * source is described by info's fields and it will have, as default PPS
  102. * parameters, the ones specified into default_params.
  103. *
  104. * The function returns, in case of success, the PPS source ID.
  105. */
  106. int pps_register_source(struct pps_source_info *info, int default_params)
  107. {
  108. struct pps_device *pps;
  109. int id;
  110. int err;
  111. /* Sanity checks */
  112. if ((info->mode & default_params) != default_params) {
  113. printk(KERN_ERR "pps: %s: unsupported default parameters\n",
  114. info->name);
  115. err = -EINVAL;
  116. goto pps_register_source_exit;
  117. }
  118. if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
  119. info->echo == NULL) {
  120. printk(KERN_ERR "pps: %s: echo function is not defined\n",
  121. info->name);
  122. err = -EINVAL;
  123. goto pps_register_source_exit;
  124. }
  125. if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
  126. printk(KERN_ERR "pps: %s: unspecified time format\n",
  127. info->name);
  128. err = -EINVAL;
  129. goto pps_register_source_exit;
  130. }
  131. /* Allocate memory for the new PPS source struct */
  132. pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
  133. if (pps == NULL) {
  134. err = -ENOMEM;
  135. goto pps_register_source_exit;
  136. }
  137. /* These initializations must be done before calling idr_get_new()
  138. * in order to avoid reces into pps_event().
  139. */
  140. pps->params.api_version = PPS_API_VERS;
  141. pps->params.mode = default_params;
  142. pps->info = *info;
  143. init_waitqueue_head(&pps->queue);
  144. spin_lock_init(&pps->lock);
  145. atomic_set(&pps->usage, 1);
  146. /* Get new ID for the new PPS source */
  147. if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
  148. err = -ENOMEM;
  149. goto kfree_pps;
  150. }
  151. spin_lock_irq(&pps_idr_lock);
  152. /* Now really allocate the PPS source.
  153. * After idr_get_new() calling the new source will be freely available
  154. * into the kernel.
  155. */
  156. err = idr_get_new(&pps_idr, pps, &id);
  157. if (err < 0) {
  158. spin_unlock_irq(&pps_idr_lock);
  159. goto kfree_pps;
  160. }
  161. id = id & MAX_ID_MASK;
  162. if (id >= PPS_MAX_SOURCES) {
  163. spin_unlock_irq(&pps_idr_lock);
  164. printk(KERN_ERR "pps: %s: too many PPS sources in the system\n",
  165. info->name);
  166. err = -EBUSY;
  167. goto free_idr;
  168. }
  169. pps->id = id;
  170. spin_unlock_irq(&pps_idr_lock);
  171. /* Create the char device */
  172. err = pps_register_cdev(pps);
  173. if (err < 0) {
  174. printk(KERN_ERR "pps: %s: unable to create char device\n",
  175. info->name);
  176. goto free_idr;
  177. }
  178. pr_info("new PPS source %s at ID %d\n", info->name, id);
  179. return id;
  180. free_idr:
  181. spin_lock_irq(&pps_idr_lock);
  182. idr_remove(&pps_idr, id);
  183. spin_unlock_irq(&pps_idr_lock);
  184. kfree_pps:
  185. kfree(pps);
  186. pps_register_source_exit:
  187. printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
  188. return err;
  189. }
  190. EXPORT_SYMBOL(pps_register_source);
  191. /* pps_unregister_source - remove a PPS source from the system
  192. * @source: the PPS source ID
  193. *
  194. * This function is used to remove a previously registered PPS source from
  195. * the system.
  196. */
  197. void pps_unregister_source(int source)
  198. {
  199. struct pps_device *pps;
  200. spin_lock_irq(&pps_idr_lock);
  201. pps = idr_find(&pps_idr, source);
  202. if (!pps) {
  203. BUG();
  204. spin_unlock_irq(&pps_idr_lock);
  205. return;
  206. }
  207. spin_unlock_irq(&pps_idr_lock);
  208. pps_unregister_cdev(pps);
  209. pps_put_source(pps);
  210. }
  211. EXPORT_SYMBOL(pps_unregister_source);
  212. /* pps_event - register a PPS event into the system
  213. * @source: the PPS source ID
  214. * @ts: the event timestamp
  215. * @event: the event type
  216. * @data: userdef pointer
  217. *
  218. * This function is used by each PPS client in order to register a new
  219. * PPS event into the system (it's usually called inside an IRQ handler).
  220. *
  221. * If an echo function is associated with the PPS source it will be called
  222. * as:
  223. * pps->info.echo(source, event, data);
  224. */
  225. void pps_event(int source, struct pps_ktime *ts, int event, void *data)
  226. {
  227. struct pps_device *pps;
  228. unsigned long flags;
  229. if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
  230. printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
  231. event, source);
  232. return;
  233. }
  234. pps = pps_get_source(source);
  235. if (!pps)
  236. return;
  237. pr_debug("PPS event on source %d at %llu.%06u\n",
  238. pps->id, (unsigned long long) ts->sec, ts->nsec);
  239. spin_lock_irqsave(&pps->lock, flags);
  240. /* Must call the echo function? */
  241. if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
  242. pps->info.echo(source, event, data);
  243. /* Check the event */
  244. pps->current_mode = pps->params.mode;
  245. if (event & PPS_CAPTUREASSERT) {
  246. /* We have to add an offset? */
  247. if (pps->params.mode & PPS_OFFSETASSERT)
  248. pps_add_offset(ts, &pps->params.assert_off_tu);
  249. /* Save the time stamp */
  250. pps->assert_tu = *ts;
  251. pps->assert_sequence++;
  252. pr_debug("capture assert seq #%u for source %d\n",
  253. pps->assert_sequence, source);
  254. }
  255. if (event & PPS_CAPTURECLEAR) {
  256. /* We have to add an offset? */
  257. if (pps->params.mode & PPS_OFFSETCLEAR)
  258. pps_add_offset(ts, &pps->params.clear_off_tu);
  259. /* Save the time stamp */
  260. pps->clear_tu = *ts;
  261. pps->clear_sequence++;
  262. pr_debug("capture clear seq #%u for source %d\n",
  263. pps->clear_sequence, source);
  264. }
  265. pps->go = ~0;
  266. wake_up_interruptible(&pps->queue);
  267. kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
  268. spin_unlock_irqrestore(&pps->lock, flags);
  269. /* Now we can release the PPS source for (possible) deregistration */
  270. pps_put_source(pps);
  271. }
  272. EXPORT_SYMBOL(pps_event);