Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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, &params, 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(&params, 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");