LCOV - code coverage report
Current view: top level - drivers/ptp - ptp_sysfs.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 22 147 15.0 %
Date: 2022-04-01 14:35:51 Functions: 3 16 18.8 %
Branches: 16 74 21.6 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * PTP 1588 clock support - sysfs interface.
       4                 :            :  *
       5                 :            :  * Copyright (C) 2010 OMICRON electronics GmbH
       6                 :            :  */
       7                 :            : #include <linux/capability.h>
       8                 :            : #include <linux/slab.h>
       9                 :            : 
      10                 :            : #include "ptp_private.h"
      11                 :            : 
      12                 :         30 : static ssize_t clock_name_show(struct device *dev,
      13                 :            :                                struct device_attribute *attr, char *page)
      14                 :            : {
      15                 :         30 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
      16                 :         30 :         return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
      17                 :            : }
      18                 :            : static DEVICE_ATTR_RO(clock_name);
      19                 :            : 
      20                 :            : #define PTP_SHOW_INT(name, var)                                         \
      21                 :            : static ssize_t var##_show(struct device *dev,                           \
      22                 :            :                            struct device_attribute *attr, char *page)   \
      23                 :            : {                                                                       \
      24                 :            :         struct ptp_clock *ptp = dev_get_drvdata(dev);                   \
      25                 :            :         return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var);     \
      26                 :            : }                                                                       \
      27                 :            : static DEVICE_ATTR(name, 0444, var##_show, NULL);
      28                 :            : 
      29                 :          0 : PTP_SHOW_INT(max_adjustment, max_adj);
      30                 :          0 : PTP_SHOW_INT(n_alarms, n_alarm);
      31                 :          0 : PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
      32                 :          0 : PTP_SHOW_INT(n_periodic_outputs, n_per_out);
      33                 :          0 : PTP_SHOW_INT(n_programmable_pins, n_pins);
      34                 :          0 : PTP_SHOW_INT(pps_available, pps);
      35                 :            : 
      36                 :          0 : static ssize_t extts_enable_store(struct device *dev,
      37                 :            :                                   struct device_attribute *attr,
      38                 :            :                                   const char *buf, size_t count)
      39                 :            : {
      40         [ #  # ]:          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
      41                 :          0 :         struct ptp_clock_info *ops = ptp->info;
      42                 :          0 :         struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
      43                 :          0 :         int cnt, enable;
      44                 :          0 :         int err = -EINVAL;
      45                 :            : 
      46                 :          0 :         cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
      47         [ #  # ]:          0 :         if (cnt != 2)
      48                 :          0 :                 goto out;
      49         [ #  # ]:          0 :         if (req.extts.index >= ops->n_ext_ts)
      50                 :          0 :                 goto out;
      51                 :            : 
      52                 :          0 :         err = ops->enable(ops, &req, enable ? 1 : 0);
      53         [ #  # ]:          0 :         if (err)
      54                 :          0 :                 goto out;
      55                 :            : 
      56                 :          0 :         return count;
      57                 :          0 : out:
      58                 :          0 :         return err;
      59                 :            : }
      60                 :            : static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
      61                 :            : 
      62                 :          0 : static ssize_t extts_fifo_show(struct device *dev,
      63                 :            :                                struct device_attribute *attr, char *page)
      64                 :            : {
      65                 :          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
      66                 :          0 :         struct timestamp_event_queue *queue = &ptp->tsevq;
      67                 :          0 :         struct ptp_extts_event event;
      68                 :          0 :         unsigned long flags;
      69                 :          0 :         size_t qcnt;
      70                 :          0 :         int cnt = 0;
      71                 :            : 
      72                 :          0 :         memset(&event, 0, sizeof(event));
      73                 :            : 
      74         [ #  # ]:          0 :         if (mutex_lock_interruptible(&ptp->tsevq_mux))
      75                 :            :                 return -ERESTARTSYS;
      76                 :            : 
      77                 :          0 :         spin_lock_irqsave(&queue->lock, flags);
      78         [ #  # ]:          0 :         qcnt = queue_cnt(queue);
      79         [ #  # ]:          0 :         if (qcnt) {
      80                 :          0 :                 event = queue->buf[queue->head];
      81                 :          0 :                 queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
      82                 :            :         }
      83                 :          0 :         spin_unlock_irqrestore(&queue->lock, flags);
      84                 :            : 
      85         [ #  # ]:          0 :         if (!qcnt)
      86                 :          0 :                 goto out;
      87                 :            : 
      88                 :          0 :         cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
      89                 :            :                        event.index, event.t.sec, event.t.nsec);
      90                 :          0 : out:
      91                 :          0 :         mutex_unlock(&ptp->tsevq_mux);
      92                 :          0 :         return cnt;
      93                 :            : }
      94                 :            : static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
      95                 :            : 
      96                 :          0 : static ssize_t period_store(struct device *dev,
      97                 :            :                             struct device_attribute *attr,
      98                 :            :                             const char *buf, size_t count)
      99                 :            : {
     100         [ #  # ]:          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
     101                 :          0 :         struct ptp_clock_info *ops = ptp->info;
     102                 :          0 :         struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
     103                 :          0 :         int cnt, enable, err = -EINVAL;
     104                 :            : 
     105                 :          0 :         cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
     106                 :            :                      &req.perout.start.sec, &req.perout.start.nsec,
     107                 :            :                      &req.perout.period.sec, &req.perout.period.nsec);
     108         [ #  # ]:          0 :         if (cnt != 5)
     109                 :          0 :                 goto out;
     110         [ #  # ]:          0 :         if (req.perout.index >= ops->n_per_out)
     111                 :          0 :                 goto out;
     112                 :            : 
     113   [ #  #  #  # ]:          0 :         enable = req.perout.period.sec || req.perout.period.nsec;
     114                 :          0 :         err = ops->enable(ops, &req, enable);
     115         [ #  # ]:          0 :         if (err)
     116                 :          0 :                 goto out;
     117                 :            : 
     118                 :          0 :         return count;
     119                 :          0 : out:
     120                 :          0 :         return err;
     121                 :            : }
     122                 :            : static DEVICE_ATTR(period, 0220, NULL, period_store);
     123                 :            : 
     124                 :          0 : static ssize_t pps_enable_store(struct device *dev,
     125                 :            :                                 struct device_attribute *attr,
     126                 :            :                                 const char *buf, size_t count)
     127                 :            : {
     128                 :          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
     129                 :          0 :         struct ptp_clock_info *ops = ptp->info;
     130                 :          0 :         struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
     131                 :          0 :         int cnt, enable;
     132                 :          0 :         int err = -EINVAL;
     133                 :            : 
     134         [ #  # ]:          0 :         if (!capable(CAP_SYS_TIME))
     135                 :            :                 return -EPERM;
     136                 :            : 
     137                 :          0 :         cnt = sscanf(buf, "%d", &enable);
     138         [ #  # ]:          0 :         if (cnt != 1)
     139                 :          0 :                 goto out;
     140                 :            : 
     141                 :          0 :         err = ops->enable(ops, &req, enable ? 1 : 0);
     142         [ #  # ]:          0 :         if (err)
     143                 :          0 :                 goto out;
     144                 :            : 
     145                 :          0 :         return count;
     146                 :          0 : out:
     147                 :          0 :         return err;
     148                 :            : }
     149                 :            : static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
     150                 :            : 
     151                 :            : static struct attribute *ptp_attrs[] = {
     152                 :            :         &dev_attr_clock_name.attr,
     153                 :            : 
     154                 :            :         &dev_attr_max_adjustment.attr,
     155                 :            :         &dev_attr_n_alarms.attr,
     156                 :            :         &dev_attr_n_external_timestamps.attr,
     157                 :            :         &dev_attr_n_periodic_outputs.attr,
     158                 :            :         &dev_attr_n_programmable_pins.attr,
     159                 :            :         &dev_attr_pps_available.attr,
     160                 :            : 
     161                 :            :         &dev_attr_extts_enable.attr,
     162                 :            :         &dev_attr_fifo.attr,
     163                 :            :         &dev_attr_period.attr,
     164                 :            :         &dev_attr_pps_enable.attr,
     165                 :            :         NULL
     166                 :            : };
     167                 :            : 
     168                 :        330 : static umode_t ptp_is_attribute_visible(struct kobject *kobj,
     169                 :            :                                         struct attribute *attr, int n)
     170                 :            : {
     171         [ +  + ]:        330 :         struct device *dev = kobj_to_dev(kobj);
     172         [ +  + ]:        330 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
     173                 :        330 :         struct ptp_clock_info *info = ptp->info;
     174                 :        330 :         umode_t mode = attr->mode;
     175                 :            : 
     176   [ +  +  +  + ]:        330 :         if (attr == &dev_attr_extts_enable.attr ||
     177                 :            :             attr == &dev_attr_fifo.attr) {
     178         [ +  - ]:         60 :                 if (!info->n_ext_ts)
     179                 :         60 :                         mode = 0;
     180         [ +  + ]:        270 :         } else if (attr == &dev_attr_period.attr) {
     181         [ +  - ]:         30 :                 if (!info->n_per_out)
     182                 :         30 :                         mode = 0;
     183         [ +  + ]:        240 :         } else if (attr == &dev_attr_pps_enable.attr) {
     184         [ +  - ]:         30 :                 if (!info->pps)
     185                 :         30 :                         mode = 0;
     186                 :            :         }
     187                 :            : 
     188                 :        330 :         return mode;
     189                 :            : }
     190                 :            : 
     191                 :            : static const struct attribute_group ptp_group = {
     192                 :            :         .is_visible     = ptp_is_attribute_visible,
     193                 :            :         .attrs          = ptp_attrs,
     194                 :            : };
     195                 :            : 
     196                 :            : const struct attribute_group *ptp_groups[] = {
     197                 :            :         &ptp_group,
     198                 :            :         NULL
     199                 :            : };
     200                 :            : 
     201                 :            : static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
     202                 :            : {
     203                 :            :         int i;
     204                 :            :         for (i = 0; i < ptp->info->n_pins; i++) {
     205                 :            :                 if (!strcmp(ptp->info->pin_config[i].name, name))
     206                 :            :                         return i;
     207                 :            :         }
     208                 :            :         return -1;
     209                 :            : }
     210                 :            : 
     211                 :          0 : static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr,
     212                 :            :                             char *page)
     213                 :            : {
     214                 :          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
     215                 :          0 :         unsigned int func, chan;
     216                 :          0 :         int index;
     217                 :            : 
     218                 :          0 :         index = ptp_pin_name2index(ptp, attr->attr.name);
     219         [ #  # ]:          0 :         if (index < 0)
     220                 :            :                 return -EINVAL;
     221                 :            : 
     222         [ #  # ]:          0 :         if (mutex_lock_interruptible(&ptp->pincfg_mux))
     223                 :            :                 return -ERESTARTSYS;
     224                 :            : 
     225                 :          0 :         func = ptp->info->pin_config[index].func;
     226                 :          0 :         chan = ptp->info->pin_config[index].chan;
     227                 :            : 
     228                 :          0 :         mutex_unlock(&ptp->pincfg_mux);
     229                 :            : 
     230                 :          0 :         return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan);
     231                 :            : }
     232                 :            : 
     233                 :          0 : static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr,
     234                 :            :                              const char *buf, size_t count)
     235                 :            : {
     236         [ #  # ]:          0 :         struct ptp_clock *ptp = dev_get_drvdata(dev);
     237                 :          0 :         unsigned int func, chan;
     238                 :          0 :         int cnt, err, index;
     239                 :            : 
     240                 :          0 :         cnt = sscanf(buf, "%u %u", &func, &chan);
     241         [ #  # ]:          0 :         if (cnt != 2)
     242                 :            :                 return -EINVAL;
     243                 :            : 
     244                 :          0 :         index = ptp_pin_name2index(ptp, attr->attr.name);
     245         [ #  # ]:          0 :         if (index < 0)
     246                 :            :                 return -EINVAL;
     247                 :            : 
     248         [ #  # ]:          0 :         if (mutex_lock_interruptible(&ptp->pincfg_mux))
     249                 :            :                 return -ERESTARTSYS;
     250                 :          0 :         err = ptp_set_pinfunc(ptp, index, func, chan);
     251                 :          0 :         mutex_unlock(&ptp->pincfg_mux);
     252         [ #  # ]:          0 :         if (err)
     253                 :          0 :                 return err;
     254                 :            : 
     255                 :          0 :         return count;
     256                 :            : }
     257                 :            : 
     258                 :         30 : int ptp_populate_pin_groups(struct ptp_clock *ptp)
     259                 :            : {
     260                 :         30 :         struct ptp_clock_info *info = ptp->info;
     261                 :         30 :         int err = -ENOMEM, i, n_pins = info->n_pins;
     262                 :            : 
     263         [ -  + ]:         30 :         if (!n_pins)
     264                 :            :                 return 0;
     265                 :            : 
     266                 :          0 :         ptp->pin_dev_attr = kcalloc(n_pins, sizeof(*ptp->pin_dev_attr),
     267                 :            :                                     GFP_KERNEL);
     268         [ #  # ]:          0 :         if (!ptp->pin_dev_attr)
     269                 :          0 :                 goto no_dev_attr;
     270                 :            : 
     271                 :          0 :         ptp->pin_attr = kcalloc(1 + n_pins, sizeof(*ptp->pin_attr), GFP_KERNEL);
     272         [ #  # ]:          0 :         if (!ptp->pin_attr)
     273                 :          0 :                 goto no_pin_attr;
     274                 :            : 
     275         [ #  # ]:          0 :         for (i = 0; i < n_pins; i++) {
     276                 :          0 :                 struct device_attribute *da = &ptp->pin_dev_attr[i];
     277                 :          0 :                 sysfs_attr_init(&da->attr);
     278                 :          0 :                 da->attr.name = info->pin_config[i].name;
     279                 :          0 :                 da->attr.mode = 0644;
     280                 :          0 :                 da->show = ptp_pin_show;
     281                 :          0 :                 da->store = ptp_pin_store;
     282                 :          0 :                 ptp->pin_attr[i] = &da->attr;
     283                 :            :         }
     284                 :            : 
     285                 :          0 :         ptp->pin_attr_group.name = "pins";
     286                 :          0 :         ptp->pin_attr_group.attrs = ptp->pin_attr;
     287                 :            : 
     288                 :          0 :         ptp->pin_attr_groups[0] = &ptp->pin_attr_group;
     289                 :            : 
     290                 :          0 :         return 0;
     291                 :            : 
     292                 :            : no_pin_attr:
     293                 :          0 :         kfree(ptp->pin_dev_attr);
     294                 :            : no_dev_attr:
     295                 :            :         return err;
     296                 :            : }
     297                 :            : 
     298                 :          0 : void ptp_cleanup_pin_groups(struct ptp_clock *ptp)
     299                 :            : {
     300                 :          0 :         kfree(ptp->pin_attr);
     301                 :          0 :         kfree(ptp->pin_dev_attr);
     302                 :          0 : }

Generated by: LCOV version 1.14