root/drivers/pps/clients/pps_parport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. signal_is_set
  2. parport_irq
  3. parport_attach
  4. parport_detach
  5. pps_parport_init
  6. pps_parport_exit

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

/* [<][>][^][v][top][bottom][index][help] */