Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
pps
clients
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,
123
PPS_CAPTUREASSERT
,
NULL
);
124
return
;
125
126
out_both:
127
/* fire assert event */
128
pps_event
(dev->
pps
, &ts_assert,
129
PPS_CAPTUREASSERT
,
NULL
);
130
/* fire clear event */
131
pps_event
(dev->
pps
, &ts_clear,
132
PPS_CAPTURECLEAR
,
NULL
);
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,
169
PPS_CAPTUREBOTH
|
PPS_OFFSETASSERT
|
PPS_OFFSETCLEAR
);
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:
186
parport_unregister_device
(device->
pardev
);
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);
206
parport_unregister_device
(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]
>"
);
248
MODULE_DESCRIPTION
(
DRVDESC
);
249
MODULE_LICENSE
(
"GPL"
);
Generated on Thu Jan 10 2013 14:16:13 for Linux Kernel by
1.8.2