linux/drivers/ptp/ptp_sysfs.c
<<
>>
Prefs
   1/*
   2 * PTP 1588 clock support - sysfs interface.
   3 *
   4 * Copyright (C) 2010 OMICRON electronics GmbH
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 */
  20#include <linux/capability.h>
  21
  22#include "ptp_private.h"
  23
  24static ssize_t clock_name_show(struct device *dev,
  25                               struct device_attribute *attr, char *page)
  26{
  27        struct ptp_clock *ptp = dev_get_drvdata(dev);
  28        return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
  29}
  30static DEVICE_ATTR(clock_name, 0444, clock_name_show, NULL);
  31
  32#define PTP_SHOW_INT(name, var)                                         \
  33static ssize_t var##_show(struct device *dev,                           \
  34                           struct device_attribute *attr, char *page)   \
  35{                                                                       \
  36        struct ptp_clock *ptp = dev_get_drvdata(dev);                   \
  37        return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var);     \
  38}                                                                       \
  39static DEVICE_ATTR(name, 0444, var##_show, NULL);
  40
  41PTP_SHOW_INT(max_adjustment, max_adj);
  42PTP_SHOW_INT(n_alarms, n_alarm);
  43PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
  44PTP_SHOW_INT(n_periodic_outputs, n_per_out);
  45PTP_SHOW_INT(pps_available, pps);
  46
  47static struct attribute *ptp_attrs[] = {
  48        &dev_attr_clock_name.attr,
  49        &dev_attr_max_adjustment.attr,
  50        &dev_attr_n_alarms.attr,
  51        &dev_attr_n_external_timestamps.attr,
  52        &dev_attr_n_periodic_outputs.attr,
  53        &dev_attr_pps_available.attr,
  54        NULL,
  55};
  56
  57static const struct attribute_group ptp_group = {
  58        .attrs = ptp_attrs,
  59};
  60
  61const struct attribute_group *ptp_groups[] = {
  62        &ptp_group,
  63        NULL,
  64};
  65
  66
  67static ssize_t extts_enable_store(struct device *dev,
  68                                  struct device_attribute *attr,
  69                                  const char *buf, size_t count)
  70{
  71        struct ptp_clock *ptp = dev_get_drvdata(dev);
  72        struct ptp_clock_info *ops = ptp->info;
  73        struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
  74        int cnt, enable;
  75        int err = -EINVAL;
  76
  77        cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
  78        if (cnt != 2)
  79                goto out;
  80        if (req.extts.index >= ops->n_ext_ts)
  81                goto out;
  82
  83        err = ops->enable(ops, &req, enable ? 1 : 0);
  84        if (err)
  85                goto out;
  86
  87        return count;
  88out:
  89        return err;
  90}
  91
  92static ssize_t extts_fifo_show(struct device *dev,
  93                               struct device_attribute *attr, char *page)
  94{
  95        struct ptp_clock *ptp = dev_get_drvdata(dev);
  96        struct timestamp_event_queue *queue = &ptp->tsevq;
  97        struct ptp_extts_event event;
  98        unsigned long flags;
  99        size_t qcnt;
 100        int cnt = 0;
 101
 102        memset(&event, 0, sizeof(event));
 103
 104        if (mutex_lock_interruptible(&ptp->tsevq_mux))
 105                return -ERESTARTSYS;
 106
 107        spin_lock_irqsave(&queue->lock, flags);
 108        qcnt = queue_cnt(queue);
 109        if (qcnt) {
 110                event = queue->buf[queue->head];
 111                queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
 112        }
 113        spin_unlock_irqrestore(&queue->lock, flags);
 114
 115        if (!qcnt)
 116                goto out;
 117
 118        cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
 119                       event.index, event.t.sec, event.t.nsec);
 120out:
 121        mutex_unlock(&ptp->tsevq_mux);
 122        return cnt;
 123}
 124
 125static ssize_t period_store(struct device *dev,
 126                            struct device_attribute *attr,
 127                            const char *buf, size_t count)
 128{
 129        struct ptp_clock *ptp = dev_get_drvdata(dev);
 130        struct ptp_clock_info *ops = ptp->info;
 131        struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
 132        int cnt, enable, err = -EINVAL;
 133
 134        cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
 135                     &req.perout.start.sec, &req.perout.start.nsec,
 136                     &req.perout.period.sec, &req.perout.period.nsec);
 137        if (cnt != 5)
 138                goto out;
 139        if (req.perout.index >= ops->n_per_out)
 140                goto out;
 141
 142        enable = req.perout.period.sec || req.perout.period.nsec;
 143        err = ops->enable(ops, &req, enable);
 144        if (err)
 145                goto out;
 146
 147        return count;
 148out:
 149        return err;
 150}
 151
 152static ssize_t pps_enable_store(struct device *dev,
 153                                struct device_attribute *attr,
 154                                const char *buf, size_t count)
 155{
 156        struct ptp_clock *ptp = dev_get_drvdata(dev);
 157        struct ptp_clock_info *ops = ptp->info;
 158        struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
 159        int cnt, enable;
 160        int err = -EINVAL;
 161
 162        if (!capable(CAP_SYS_TIME))
 163                return -EPERM;
 164
 165        cnt = sscanf(buf, "%d", &enable);
 166        if (cnt != 1)
 167                goto out;
 168
 169        err = ops->enable(ops, &req, enable ? 1 : 0);
 170        if (err)
 171                goto out;
 172
 173        return count;
 174out:
 175        return err;
 176}
 177
 178static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
 179static DEVICE_ATTR(fifo,         0444, extts_fifo_show, NULL);
 180static DEVICE_ATTR(period,       0220, NULL, period_store);
 181static DEVICE_ATTR(pps_enable,   0220, NULL, pps_enable_store);
 182
 183int ptp_cleanup_sysfs(struct ptp_clock *ptp)
 184{
 185        struct device *dev = ptp->dev;
 186        struct ptp_clock_info *info = ptp->info;
 187
 188        if (info->n_ext_ts) {
 189                device_remove_file(dev, &dev_attr_extts_enable);
 190                device_remove_file(dev, &dev_attr_fifo);
 191        }
 192        if (info->n_per_out)
 193                device_remove_file(dev, &dev_attr_period);
 194
 195        if (info->pps)
 196                device_remove_file(dev, &dev_attr_pps_enable);
 197
 198        return 0;
 199}
 200
 201int ptp_populate_sysfs(struct ptp_clock *ptp)
 202{
 203        struct device *dev = ptp->dev;
 204        struct ptp_clock_info *info = ptp->info;
 205        int err;
 206
 207        if (info->n_ext_ts) {
 208                err = device_create_file(dev, &dev_attr_extts_enable);
 209                if (err)
 210                        goto out1;
 211                err = device_create_file(dev, &dev_attr_fifo);
 212                if (err)
 213                        goto out2;
 214        }
 215        if (info->n_per_out) {
 216                err = device_create_file(dev, &dev_attr_period);
 217                if (err)
 218                        goto out3;
 219        }
 220        if (info->pps) {
 221                err = device_create_file(dev, &dev_attr_pps_enable);
 222                if (err)
 223                        goto out4;
 224        }
 225        return 0;
 226out4:
 227        if (info->n_per_out)
 228                device_remove_file(dev, &dev_attr_period);
 229out3:
 230        if (info->n_ext_ts)
 231                device_remove_file(dev, &dev_attr_fifo);
 232out2:
 233        if (info->n_ext_ts)
 234                device_remove_file(dev, &dev_attr_extts_enable);
 235out1:
 236        return err;
 237}
 238
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.