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