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