1/* 2 * pps_parport.c -- kernel parallel port PPS client 3 * 4 * 5 * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su> 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/* 24 * TODO: 25 * implement echo over SEL pin 26 */ 27 28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 29 30#include <linux/kernel.h> 31#include <linux/module.h> 32#include <linux/init.h> 33#include <linux/irqnr.h> 34#include <linux/time.h> 35#include <linux/slab.h> 36#include <linux/parport.h> 37#include <linux/pps_kernel.h> 38 39#define DRVDESC "parallel port PPS client" 40 41/* module parameters */ 42 43#define CLEAR_WAIT_MAX 100 44#define CLEAR_WAIT_MAX_ERRORS 5 45 46static unsigned int clear_wait = 100; 47MODULE_PARM_DESC(clear_wait, 48 "Maximum number of port reads when polling for signal clear," 49 " zero turns clear edge capture off entirely"); 50module_param(clear_wait, uint, 0); 51 52 53/* internal per port structure */ 54struct pps_client_pp { 55 struct pardevice *pardev; /* parport device */ 56 struct pps_device *pps; /* PPS device */ 57 unsigned int cw; /* port clear timeout */ 58 unsigned int cw_err; /* number of timeouts */ 59}; 60 61static inline int signal_is_set(struct parport *port) 62{ 63 return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0; 64} 65 66/* parport interrupt handler */ 67static void parport_irq(void *handle) 68{ 69 struct pps_event_time ts_assert, ts_clear; 70 struct pps_client_pp *dev = handle; 71 struct parport *port = dev->pardev->port; 72 unsigned int i; 73 unsigned long flags; 74 75 /* first of all we get the time stamp... */ 76 pps_get_ts(&ts_assert); 77 78 if (dev->cw == 0) 79 /* clear edge capture disabled */ 80 goto out_assert; 81 82 /* try capture the clear edge */ 83 84 /* We have to disable interrupts here. The idea is to prevent 85 * other interrupts on the same processor to introduce random 86 * lags while polling the port. Reading from IO port is known 87 * to take approximately 1us while other interrupt handlers can 88 * take much more potentially. 89 * 90 * Interrupts won't be disabled for a long time because the 91 * number of polls is limited by clear_wait parameter which is 92 * kept rather low. So it should never be an issue. 93 */ 94 local_irq_save(flags); 95 /* check the signal (no signal means the pulse is lost this time) */ 96 if (!signal_is_set(port)) { 97 local_irq_restore(flags); 98 dev_err(dev->pps->dev, "lost the signal\n"); 99 goto out_assert; 100 } 101 102 /* poll the port until the signal is unset */ 103 for (i = dev->cw; i; i--) 104 if (!signal_is_set(port)) { 105 pps_get_ts(&ts_clear); 106 local_irq_restore(flags); 107 dev->cw_err = 0; 108 goto out_both; 109 } 110 local_irq_restore(flags); 111 112 /* timeout */ 113 dev->cw_err++; 114 if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) { 115 dev_err(dev->pps->dev, "disabled clear edge capture after %d" 116 " timeouts\n", dev->cw_err); 117 dev->cw = 0; 118 dev->cw_err = 0; 119 } 120 121out_assert: 122 /* fire assert event */ 123 pps_event(dev->pps, &ts_assert, 124 PPS_CAPTUREASSERT, NULL); 125 return; 126 127out_both: 128 /* fire assert event */ 129 pps_event(dev->pps, &ts_assert, 130 PPS_CAPTUREASSERT, NULL); 131 /* fire clear event */ 132 pps_event(dev->pps, &ts_clear, 133 PPS_CAPTURECLEAR, NULL); 134 return; 135} 136 137static void parport_attach(struct parport *port) 138{ 139 struct pps_client_pp *device; 140 struct pps_source_info info = { 141 .name = KBUILD_MODNAME, 142 .path = "", 143 .mode = PPS_CAPTUREBOTH | \ 144 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ 145 PPS_ECHOASSERT | PPS_ECHOCLEAR | \ 146 PPS_CANWAIT | PPS_TSFMT_TSPEC, 147 .owner = THIS_MODULE, 148 .dev = NULL 149 }; 150 151 device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL); 152 if (!device) { 153 pr_err("memory allocation failed, not attaching\n"); 154 return; 155 } 156 157 device->pardev = parport_register_device(port, KBUILD_MODNAME, 158 NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device); 159 if (!device->pardev) { 160 pr_err("couldn't register with %s\n", port->name); 161 goto err_free; 162 } 163 164 if (parport_claim_or_block(device->pardev) < 0) { 165 pr_err("couldn't claim %s\n", port->name); 166 goto err_unregister_dev; 167 } 168 169 device->pps = pps_register_source(&info, 170 PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR); 171 if (device->pps == NULL) { 172 pr_err("couldn't register PPS source\n"); 173 goto err_release_dev; 174 } 175 176 device->cw = clear_wait; 177 178 port->ops->enable_irq(port); 179 180 pr_info("attached to %s\n", port->name); 181 182 return; 183 184err_release_dev: 185 parport_release(device->pardev); 186err_unregister_dev: 187 parport_unregister_device(device->pardev); 188err_free: 189 kfree(device); 190} 191 192static void parport_detach(struct parport *port) 193{ 194 struct pardevice *pardev = port->cad; 195 struct pps_client_pp *device; 196 197 /* FIXME: oooh, this is ugly! */ 198 if (strcmp(pardev->name, KBUILD_MODNAME)) 199 /* not our port */ 200 return; 201 202 device = pardev->private; 203 204 port->ops->disable_irq(port); 205 pps_unregister_source(device->pps); 206 parport_release(pardev); 207 parport_unregister_device(pardev); 208 kfree(device); 209} 210 211static struct parport_driver pps_parport_driver = { 212 .name = KBUILD_MODNAME, 213 .attach = parport_attach, 214 .detach = parport_detach, 215}; 216 217/* module staff */ 218 219static int __init pps_parport_init(void) 220{ 221 int ret; 222 223 pr_info(DRVDESC "\n"); 224 225 if (clear_wait > CLEAR_WAIT_MAX) { 226 pr_err("clear_wait value should be not greater" 227 " then %d\n", CLEAR_WAIT_MAX); 228 return -EINVAL; 229 } 230 231 ret = parport_register_driver(&pps_parport_driver); 232 if (ret) { 233 pr_err("unable to register with parport\n"); 234 return ret; 235 } 236 237 return 0; 238} 239 240static void __exit pps_parport_exit(void) 241{ 242 parport_unregister_driver(&pps_parport_driver); 243} 244 245module_init(pps_parport_init); 246module_exit(pps_parport_exit); 247 248MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>"); 249MODULE_DESCRIPTION(DRVDESC); 250MODULE_LICENSE("GPL"); 251