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