^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * PPS core file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/idr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/cdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/pps_kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "kc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * Local variables
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static dev_t pps_devt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static struct class *pps_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static DEFINE_MUTEX(pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static DEFINE_IDR(pps_idr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Char device methods
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static __poll_t pps_cdev_poll(struct file *file, poll_table *wait)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct pps_device *pps = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) poll_wait(file, &pps->queue, wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return EPOLLIN | EPOLLRDNORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static int pps_cdev_fasync(int fd, struct file *file, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct pps_device *pps = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return fasync_helper(fd, file, on, &pps->async_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned int ev = pps->last_ev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* Manage the timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (fdata->timeout.flags & PPS_TIME_INVALID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) err = wait_event_interruptible(pps->queue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ev != pps->last_ev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long ticks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) dev_dbg(pps->dev, "timeout %lld.%09d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) (long long) fdata->timeout.sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) fdata->timeout.nsec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ticks = fdata->timeout.sec * HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ticks += fdata->timeout.nsec / (NSEC_PER_SEC / HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (ticks != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) err = wait_event_interruptible_timeout(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pps->queue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ev != pps->last_ev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ticks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (err == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Check for pending signals */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (err == -ERESTARTSYS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) dev_dbg(pps->dev, "pending signal caught\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return -EINTR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static long pps_cdev_ioctl(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct pps_device *pps = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct pps_kparams params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) void __user *uarg = (void __user *) arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) int __user *iuarg = (int __user *) arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case PPS_GETPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) dev_dbg(pps->dev, "PPS_GETPARAMS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) spin_lock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Get the current parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) params = pps->params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) spin_unlock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) err = copy_to_user(uarg, ¶ms, sizeof(struct pps_kparams));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) case PPS_SETPARAMS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) dev_dbg(pps->dev, "PPS_SETPARAMS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Check the capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (!capable(CAP_SYS_TIME))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) err = copy_from_user(¶ms, uarg, sizeof(struct pps_kparams));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev_dbg(pps->dev, "capture mode unspecified (%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) params.mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /* Check for supported capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if ((params.mode & ~pps->info.mode) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev_dbg(pps->dev, "unsupported capabilities (%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) params.mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) spin_lock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* Save the new parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pps->params = params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Restore the read only parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* section 3.3 of RFC 2783 interpreted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) dev_dbg(pps->dev, "time format unspecified (%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) params.mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pps->params.mode |= PPS_TSFMT_TSPEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (pps->info.mode & PPS_CANWAIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) pps->params.mode |= PPS_CANWAIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pps->params.api_version = PPS_API_VERS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * Clear unused fields of pps_kparams to avoid leaking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * uninitialized data of the PPS_SETPARAMS caller via
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * PPS_GETPARAMS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) pps->params.assert_off_tu.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pps->params.clear_off_tu.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) spin_unlock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) case PPS_GETCAP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) dev_dbg(pps->dev, "PPS_GETCAP\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) err = put_user(pps->info.mode, iuarg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) case PPS_FETCH: {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct pps_fdata fdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) dev_dbg(pps->dev, "PPS_FETCH\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) err = pps_cdev_pps_fetch(pps, &fdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* Return the fetched timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) spin_lock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) fdata.info.assert_sequence = pps->assert_sequence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) fdata.info.clear_sequence = pps->clear_sequence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) fdata.info.assert_tu = pps->assert_tu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) fdata.info.clear_tu = pps->clear_tu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) fdata.info.current_mode = pps->current_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) spin_unlock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case PPS_KC_BIND: {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct pps_bind_args bind_args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) dev_dbg(pps->dev, "PPS_KC_BIND\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* Check the capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!capable(CAP_SYS_TIME))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (copy_from_user(&bind_args, uarg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) sizeof(struct pps_bind_args)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Check for supported capabilities */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if ((bind_args.edge & ~pps->info.mode) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) dev_err(pps->dev, "unsupported capabilities (%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) bind_args.edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* Validate parameters roughly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) bind_args.consumer != PPS_KC_HARDPPS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dev_err(pps->dev, "invalid kernel consumer bind"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) " parameters (%x)\n", bind_args.edge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) err = pps_kc_bind(pps, &bind_args);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) #ifdef CONFIG_COMPAT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static long pps_cdev_compat_ioctl(struct file *file,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct pps_device *pps = file->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) void __user *uarg = (void __user *) arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (cmd == PPS_FETCH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) struct pps_fdata_compat compat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) struct pps_fdata fdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) dev_dbg(pps->dev, "PPS_FETCH\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) memcpy(&fdata.timeout, &compat.timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) sizeof(struct pps_ktime_compat));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) err = pps_cdev_pps_fetch(pps, &fdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* Return the fetched timestamp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) spin_lock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) compat.info.assert_sequence = pps->assert_sequence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) compat.info.clear_sequence = pps->clear_sequence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) compat.info.current_mode = pps->current_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) memcpy(&compat.info.assert_tu, &pps->assert_tu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) sizeof(struct pps_ktime_compat));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) memcpy(&compat.info.clear_tu, &pps->clear_tu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) sizeof(struct pps_ktime_compat));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) spin_unlock_irq(&pps->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return copy_to_user(uarg, &compat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return pps_cdev_ioctl(file, cmd, arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) #define pps_cdev_compat_ioctl NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int pps_cdev_open(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) struct pps_device *pps = container_of(inode->i_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct pps_device, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) file->private_data = pps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) kobject_get(&pps->dev->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int pps_cdev_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct pps_device *pps = container_of(inode->i_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct pps_device, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) kobject_put(&pps->dev->kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * Char device stuff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static const struct file_operations pps_cdev_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .llseek = no_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .poll = pps_cdev_poll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .fasync = pps_cdev_fasync,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .compat_ioctl = pps_cdev_compat_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .unlocked_ioctl = pps_cdev_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .open = pps_cdev_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .release = pps_cdev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) static void pps_device_destruct(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct pps_device *pps = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) cdev_del(&pps->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* Now we can release the ID for re-use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) pr_debug("deallocating pps%d\n", pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) mutex_lock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) idr_remove(&pps_idr, pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) mutex_unlock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) kfree(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) kfree(pps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) int pps_register_cdev(struct pps_device *pps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) dev_t devt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) mutex_lock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * Get new ID for the new PPS source. After idr_alloc() calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * the new source will be freely available into the kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (err == -ENOSPC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) pr_err("%s: too many PPS sources in the system\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) pps->info.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) goto out_unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) pps->id = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) mutex_unlock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) devt = MKDEV(MAJOR(pps_devt), pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) cdev_init(&pps->cdev, &pps_cdev_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) pps->cdev.owner = pps->info.owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) err = cdev_add(&pps->cdev, devt, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) pr_err("%s: failed to add char device %d:%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) pps->info.name, MAJOR(pps_devt), pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) goto free_idr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) "pps%d", pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (IS_ERR(pps->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) err = PTR_ERR(pps->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) goto del_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* Override the release function with our own */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) pps->dev->release = pps_device_destruct;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) MAJOR(pps_devt), pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) del_cdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) cdev_del(&pps->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) free_idr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) mutex_lock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) idr_remove(&pps_idr, pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) out_unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) mutex_unlock(&pps_idr_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) void pps_unregister_cdev(struct pps_device *pps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) pr_debug("unregistering pps%d\n", pps->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) pps->lookup_cookie = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) device_destroy(pps_class, pps->dev->devt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) * Look up a pps device by magic cookie.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * The cookie is usually a pointer to some enclosing device, but this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * code doesn't care; you should never be dereferencing it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * This is a bit of a kludge that is currently used only by the PPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) * serial line discipline. It may need to be tweaked when a second user
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) * is found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * There is no function interface for setting the lookup_cookie field.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * It's initialized to NULL when the pps device is created, and if a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * client wants to use it, just fill it in afterward.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * The cookie is automatically set to NULL in pps_unregister_source()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * so that it will not be used again, even if the pps device cannot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * be removed from the idr due to pending references holding the minor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * number in use.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) struct pps_device *pps_lookup_dev(void const *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) struct pps_device *pps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) unsigned id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) idr_for_each_entry(&pps_idr, pps, id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (cookie == pps->lookup_cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return pps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) EXPORT_SYMBOL(pps_lookup_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) * Module stuff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static void __exit pps_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) class_destroy(pps_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static int __init pps_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) pps_class = class_create(THIS_MODULE, "pps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (IS_ERR(pps_class)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) pr_err("failed to allocate class\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return PTR_ERR(pps_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) pps_class->dev_groups = pps_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) pr_err("failed to allocate char device region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) goto remove_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) "<giometti@linux.it>\n", PPS_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) remove_class:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) class_destroy(pps_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) subsys_initcall(pps_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) module_exit(pps_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) MODULE_LICENSE("GPL");