Blame view
drivers/ptp/ptp_chardev.c
8.53 KB
d94ba80eb ptp: Added a bran... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * PTP 1588 clock support - character device implementation. * * Copyright (C) 2010 OMICRON electronics GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> #include <linux/posix-clock.h> #include <linux/poll.h> #include <linux/sched.h> |
c7ec0badc ptp: reduce stack... |
24 |
#include <linux/slab.h> |
719f1aa4a ptp: Add PTP_SYS_... |
25 |
#include <linux/timekeeping.h> |
d94ba80eb ptp: Added a bran... |
26 27 |
#include "ptp_private.h" |
6092315df ptp: introduce pr... |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
static int ptp_disable_pinfunc(struct ptp_clock_info *ops, enum ptp_pin_function func, unsigned int chan) { struct ptp_clock_request rq; int err = 0; memset(&rq, 0, sizeof(rq)); switch (func) { case PTP_PF_NONE: break; case PTP_PF_EXTTS: rq.type = PTP_CLK_REQ_EXTTS; rq.extts.index = chan; err = ops->enable(ops, &rq, 0); break; case PTP_PF_PEROUT: rq.type = PTP_CLK_REQ_PEROUT; rq.perout.index = chan; err = ops->enable(ops, &rq, 0); break; case PTP_PF_PHYSYNC: break; default: return -EINVAL; } return err; } int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, enum ptp_pin_function func, unsigned int chan) { struct ptp_clock_info *info = ptp->info; struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin]; unsigned int i; /* Check to see if any other pin previously had this function. */ for (i = 0; i < info->n_pins; i++) { if (info->pin_config[i].func == func && info->pin_config[i].chan == chan) { pin1 = &info->pin_config[i]; break; } } if (pin1 && i == pin) return 0; /* Check the desired function and channel. */ switch (func) { case PTP_PF_NONE: break; case PTP_PF_EXTTS: if (chan >= info->n_ext_ts) return -EINVAL; break; case PTP_PF_PEROUT: if (chan >= info->n_per_out) return -EINVAL; break; case PTP_PF_PHYSYNC: |
72df7a724 ptp: Allow reassi... |
89 90 |
if (chan != 0) return -EINVAL; |
294dc77bb ptp: fix missing ... |
91 |
break; |
6092315df ptp: introduce pr... |
92 93 94 |
default: return -EINVAL; } |
6092315df ptp: introduce pr... |
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
if (info->verify(info, pin, func, chan)) { pr_err("driver cannot use function %u on pin %u ", func, chan); return -EOPNOTSUPP; } /* Disable whatever function was previously assigned. */ if (pin1) { ptp_disable_pinfunc(info, func, chan); pin1->func = PTP_PF_NONE; pin1->chan = 0; } ptp_disable_pinfunc(info, pin2->func, pin2->chan); pin2->func = func; pin2->chan = chan; return 0; } |
d94ba80eb ptp: Added a bran... |
113 114 115 116 117 118 119 120 121 |
int ptp_open(struct posix_clock *pc, fmode_t fmode) { return 0; } long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) { struct ptp_clock_caps caps; struct ptp_clock_request req; |
c3484c275 ptp: reduce stack... |
122 |
struct ptp_sys_offset *sysoff = NULL; |
719f1aa4a ptp: Add PTP_SYS_... |
123 |
struct ptp_sys_offset_precise precise_offset; |
6092315df ptp: introduce pr... |
124 |
struct ptp_pin_desc pd; |
d94ba80eb ptp: Added a bran... |
125 126 |
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); struct ptp_clock_info *ops = ptp->info; |
215b13dd2 ptp: add an ioctl... |
127 |
struct ptp_clock_time *pct; |
e13cfcb03 ptp: use the 64 b... |
128 |
struct timespec64 ts; |
719f1aa4a ptp: Add PTP_SYS_... |
129 |
struct system_device_crosststamp xtstamp; |
d94ba80eb ptp: Added a bran... |
130 |
int enable, err = 0; |
6092315df ptp: introduce pr... |
131 |
unsigned int i, pin_index; |
d94ba80eb ptp: Added a bran... |
132 133 134 135 136 137 138 139 140 141 |
switch (cmd) { case PTP_CLOCK_GETCAPS: memset(&caps, 0, sizeof(caps)); caps.max_adj = ptp->info->max_adj; caps.n_alarm = ptp->info->n_alarm; caps.n_ext_ts = ptp->info->n_ext_ts; caps.n_per_out = ptp->info->n_per_out; caps.pps = ptp->info->pps; |
6092315df ptp: introduce pr... |
142 |
caps.n_pins = ptp->info->n_pins; |
719f1aa4a ptp: Add PTP_SYS_... |
143 |
caps.cross_timestamping = ptp->info->getcrosststamp != NULL; |
e23ef227d ptp: Return -EFAU... |
144 145 |
if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) err = -EFAULT; |
d94ba80eb ptp: Added a bran... |
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
break; case PTP_EXTTS_REQUEST: if (copy_from_user(&req.extts, (void __user *)arg, sizeof(req.extts))) { err = -EFAULT; break; } if (req.extts.index >= ops->n_ext_ts) { err = -EINVAL; break; } req.type = PTP_CLK_REQ_EXTTS; enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0; err = ops->enable(ops, &req, enable); break; case PTP_PEROUT_REQUEST: if (copy_from_user(&req.perout, (void __user *)arg, sizeof(req.perout))) { err = -EFAULT; break; } if (req.perout.index >= ops->n_per_out) { err = -EINVAL; break; } req.type = PTP_CLK_REQ_PEROUT; enable = req.perout.period.sec || req.perout.period.nsec; err = ops->enable(ops, &req, enable); break; case PTP_ENABLE_PPS: if (!capable(CAP_SYS_TIME)) return -EPERM; req.type = PTP_CLK_REQ_PPS; enable = arg ? 1 : 0; err = ops->enable(ops, &req, enable); break; |
719f1aa4a ptp: Add PTP_SYS_... |
185 186 187 188 189 190 191 192 |
case PTP_SYS_OFFSET_PRECISE: if (!ptp->info->getcrosststamp) { err = -EOPNOTSUPP; break; } err = ptp->info->getcrosststamp(ptp->info, &xtstamp); if (err) break; |
02a9079c6 drivers/ptp: Fix ... |
193 |
memset(&precise_offset, 0, sizeof(precise_offset)); |
719f1aa4a ptp: Add PTP_SYS_... |
194 195 196 197 198 199 200 201 202 203 204 205 206 |
ts = ktime_to_timespec64(xtstamp.device); precise_offset.device.sec = ts.tv_sec; precise_offset.device.nsec = ts.tv_nsec; ts = ktime_to_timespec64(xtstamp.sys_realtime); precise_offset.sys_realtime.sec = ts.tv_sec; precise_offset.sys_realtime.nsec = ts.tv_nsec; ts = ktime_to_timespec64(xtstamp.sys_monoraw); precise_offset.sys_monoraw.sec = ts.tv_sec; precise_offset.sys_monoraw.nsec = ts.tv_nsec; if (copy_to_user((void __user *)arg, &precise_offset, sizeof(precise_offset))) err = -EFAULT; break; |
215b13dd2 ptp: add an ioctl... |
207 |
case PTP_SYS_OFFSET: |
2ece068e1 ptp: use memdup_u... |
208 209 210 |
sysoff = memdup_user((void __user *)arg, sizeof(*sysoff)); if (IS_ERR(sysoff)) { err = PTR_ERR(sysoff); |
6756325a9 ptp: oops in ptp_... |
211 |
sysoff = NULL; |
215b13dd2 ptp: add an ioctl... |
212 213 |
break; } |
c3484c275 ptp: reduce stack... |
214 |
if (sysoff->n_samples > PTP_MAX_SAMPLES) { |
215b13dd2 ptp: add an ioctl... |
215 216 217 |
err = -EINVAL; break; } |
c3484c275 ptp: reduce stack... |
218 219 |
pct = &sysoff->ts[0]; for (i = 0; i < sysoff->n_samples; i++) { |
e13cfcb03 ptp: use the 64 b... |
220 |
getnstimeofday64(&ts); |
215b13dd2 ptp: add an ioctl... |
221 222 223 |
pct->sec = ts.tv_sec; pct->nsec = ts.tv_nsec; pct++; |
ed7c6317b ptp: remove 32 bi... |
224 |
ptp->info->gettime64(ptp->info, &ts); |
215b13dd2 ptp: add an ioctl... |
225 226 227 228 |
pct->sec = ts.tv_sec; pct->nsec = ts.tv_nsec; pct++; } |
e13cfcb03 ptp: use the 64 b... |
229 |
getnstimeofday64(&ts); |
215b13dd2 ptp: add an ioctl... |
230 231 |
pct->sec = ts.tv_sec; pct->nsec = ts.tv_nsec; |
c3484c275 ptp: reduce stack... |
232 |
if (copy_to_user((void __user *)arg, sysoff, sizeof(*sysoff))) |
215b13dd2 ptp: add an ioctl... |
233 234 |
err = -EFAULT; break; |
6092315df ptp: introduce pr... |
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
case PTP_PIN_GETFUNC: if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { err = -EFAULT; break; } pin_index = pd.index; if (pin_index >= ops->n_pins) { err = -EINVAL; break; } if (mutex_lock_interruptible(&ptp->pincfg_mux)) return -ERESTARTSYS; pd = ops->pin_config[pin_index]; mutex_unlock(&ptp->pincfg_mux); if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd))) err = -EFAULT; break; case PTP_PIN_SETFUNC: if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { err = -EFAULT; break; } pin_index = pd.index; if (pin_index >= ops->n_pins) { err = -EINVAL; break; } if (mutex_lock_interruptible(&ptp->pincfg_mux)) return -ERESTARTSYS; err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan); mutex_unlock(&ptp->pincfg_mux); break; |
d94ba80eb ptp: Added a bran... |
268 269 270 271 |
default: err = -ENOTTY; break; } |
c3484c275 ptp: reduce stack... |
272 273 |
kfree(sysoff); |
d94ba80eb ptp: Added a bran... |
274 275 276 277 278 279 280 281 282 283 284 |
return err; } unsigned int ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); poll_wait(fp, &ptp->tsev_wq, wait); return queue_cnt(&ptp->tsevq) ? POLLIN : 0; } |
c7ec0badc ptp: reduce stack... |
285 |
#define EXTTS_BUFSIZE (PTP_BUF_TIMESTAMPS * sizeof(struct ptp_extts_event)) |
d94ba80eb ptp: Added a bran... |
286 287 288 289 290 |
ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, size_t cnt) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); struct timestamp_event_queue *queue = &ptp->tsevq; |
c7ec0badc ptp: reduce stack... |
291 |
struct ptp_extts_event *event; |
d94ba80eb ptp: Added a bran... |
292 293 |
unsigned long flags; size_t qcnt, i; |
c7ec0badc ptp: reduce stack... |
294 |
int result; |
d94ba80eb ptp: Added a bran... |
295 296 297 |
if (cnt % sizeof(struct ptp_extts_event) != 0) return -EINVAL; |
c7ec0badc ptp: reduce stack... |
298 299 |
if (cnt > EXTTS_BUFSIZE) cnt = EXTTS_BUFSIZE; |
d94ba80eb ptp: Added a bran... |
300 301 302 303 304 305 306 307 308 309 310 |
cnt = cnt / sizeof(struct ptp_extts_event); if (mutex_lock_interruptible(&ptp->tsevq_mux)) return -ERESTARTSYS; if (wait_event_interruptible(ptp->tsev_wq, ptp->defunct || queue_cnt(queue))) { mutex_unlock(&ptp->tsevq_mux); return -ERESTARTSYS; } |
fb5a18cf7 ptp: Fix some loc... |
311 312 |
if (ptp->defunct) { mutex_unlock(&ptp->tsevq_mux); |
d94ba80eb ptp: Added a bran... |
313 |
return -ENODEV; |
fb5a18cf7 ptp: Fix some loc... |
314 |
} |
d94ba80eb ptp: Added a bran... |
315 |
|
c7ec0badc ptp: reduce stack... |
316 317 318 319 320 |
event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); if (!event) { mutex_unlock(&ptp->tsevq_mux); return -ENOMEM; } |
d94ba80eb ptp: Added a bran... |
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
spin_lock_irqsave(&queue->lock, flags); qcnt = queue_cnt(queue); if (cnt > qcnt) cnt = qcnt; for (i = 0; i < cnt; i++) { event[i] = queue->buf[queue->head]; queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; } spin_unlock_irqrestore(&queue->lock, flags); cnt = cnt * sizeof(struct ptp_extts_event); mutex_unlock(&ptp->tsevq_mux); |
c7ec0badc ptp: reduce stack... |
338 |
result = cnt; |
fb5a18cf7 ptp: Fix some loc... |
339 |
if (copy_to_user(buf, event, cnt)) |
c7ec0badc ptp: reduce stack... |
340 |
result = -EFAULT; |
d94ba80eb ptp: Added a bran... |
341 |
|
c7ec0badc ptp: reduce stack... |
342 343 |
kfree(event); return result; |
d94ba80eb ptp: Added a bran... |
344 |
} |