rtc-dev.c 9.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * RTC subsystem, dev interface
 *
 * Copyright (C) 2005 Tower Technologies
 * Author: Alessandro Zummo <a.zummo@towertech.it>
 *
 * based on arch/arm/common/rtctime.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
*/

#include <linux/module.h>
#include <linux/rtc.h>
16
#include <linux/sched.h>
17
#include "rtc-core.h"
18 19 20 21 22 23 24 25 26 27

static dev_t rtc_devt;

#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */

static int rtc_dev_open(struct inode *inode, struct file *file)
{
	int err;
	struct rtc_device *rtc = container_of(inode->i_cdev,
					struct rtc_device, char_dev);
28
	const struct rtc_class_ops *ops = rtc->ops;
29

30 31
	if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
		return -EBUSY;
32

33
	file->private_data = rtc;
34

35
	err = ops->open ? ops->open(rtc->dev.parent) : 0;
36 37 38 39 40
	if (err == 0) {
		spin_lock_irq(&rtc->irq_lock);
		rtc->irq_data = 0;
		spin_unlock_irq(&rtc->irq_lock);

41
		return 0;
42 43
	}

J
Jiri Kosina 已提交
44
	/* something has gone wrong */
45
	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
46 47 48 49 50 51 52
	return err;
}


static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
53
	struct rtc_device *rtc = file->private_data;
54 55 56 57 58

	DECLARE_WAITQUEUE(wait, current);
	unsigned long data;
	ssize_t ret;

59
	if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
		return -EINVAL;

	add_wait_queue(&rtc->irq_queue, &wait);
	do {
		__set_current_state(TASK_INTERRUPTIBLE);

		spin_lock_irq(&rtc->irq_lock);
		data = rtc->irq_data;
		rtc->irq_data = 0;
		spin_unlock_irq(&rtc->irq_lock);

		if (data != 0) {
			ret = 0;
			break;
		}
		if (file->f_flags & O_NONBLOCK) {
			ret = -EAGAIN;
			break;
		}
		if (signal_pending(current)) {
			ret = -ERESTARTSYS;
			break;
		}
		schedule();
	} while (1);
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&rtc->irq_queue, &wait);

	if (ret == 0) {
		/* Check for any data updates */
		if (rtc->ops->read_callback)
91
			data = rtc->ops->read_callback(rtc->dev.parent,
92 93 94 95 96 97 98 99 100
						       data);

		if (sizeof(int) != sizeof(long) &&
		    count == sizeof(unsigned int))
			ret = put_user(data, (unsigned int __user *)buf) ?:
				sizeof(unsigned int);
		else
			ret = put_user(data, (unsigned long __user *)buf) ?:
				sizeof(unsigned long);
101 102 103 104 105 106
	}
	return ret;
}

static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
{
107
	struct rtc_device *rtc = file->private_data;
108 109 110 111 112 113 114 115 116
	unsigned long data;

	poll_wait(file, &rtc->irq_queue, wait);

	data = rtc->irq_data;

	return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
}

D
David Brownell 已提交
117
static long rtc_dev_ioctl(struct file *file,
118 119 120
		unsigned int cmd, unsigned long arg)
{
	int err = 0;
121
	struct rtc_device *rtc = file->private_data;
122
	const struct rtc_class_ops *ops = rtc->ops;
123 124 125 126
	struct rtc_time tm;
	struct rtc_wkalrm alarm;
	void __user *uarg = (void __user *) arg;

D
David Brownell 已提交
127 128
	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
129
		return err;
D
David Brownell 已提交
130

131
	/* check that the calling task has appropriate permissions
132 133 134 135 136 137 138
	 * for certain ioctls. doing this check here is useful
	 * to avoid duplicate code in each driver.
	 */
	switch (cmd) {
	case RTC_EPOCH_SET:
	case RTC_SET_TIME:
		if (!capable(CAP_SYS_TIME))
D
David Brownell 已提交
139
			err = -EACCES;
140 141 142 143
		break;

	case RTC_IRQP_SET:
		if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
D
David Brownell 已提交
144
			err = -EACCES;
145 146 147
		break;

	case RTC_PIE_ON:
148 149
		if (rtc->irq_freq > rtc->max_user_freq &&
				!capable(CAP_SYS_RESOURCE))
D
David Brownell 已提交
150
			err = -EACCES;
151 152 153
		break;
	}

D
David Brownell 已提交
154 155 156
	if (err)
		goto done;

157 158
	/* try the driver's ioctl interface */
	if (ops->ioctl) {
159
		err = ops->ioctl(rtc->dev.parent, cmd, arg);
D
David Brownell 已提交
160 161
		if (err != -ENOIOCTLCMD) {
			mutex_unlock(&rtc->ops_lock);
162
			return err;
D
David Brownell 已提交
163
		}
164 165 166 167
	}

	/* if the driver does not provide the ioctl interface
	 * or if that particular ioctl was not implemented
168
	 * (-ENOIOCTLCMD), we will try to emulate here.
D
David Brownell 已提交
169 170 171 172 173 174 175 176 177
	 *
	 * Drivers *SHOULD NOT* provide ioctl implementations
	 * for these requests.  Instead, provide methods to
	 * support the following code, so that the RTC's main
	 * features are accessible without using ioctls.
	 *
	 * RTC and alarm times will be in UTC, by preference,
	 * but dual-booting with MS-Windows implies RTCs must
	 * use the local wall clock time.
178 179 180 181
	 */

	switch (cmd) {
	case RTC_ALM_READ:
D
David Brownell 已提交
182 183
		mutex_unlock(&rtc->ops_lock);

184
		err = rtc_read_alarm(rtc, &alarm);
185 186 187 188
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
D
David Brownell 已提交
189 190
			err = -EFAULT;
		return err;
191 192

	case RTC_ALM_SET:
D
David Brownell 已提交
193 194
		mutex_unlock(&rtc->ops_lock);

195 196 197 198 199 200 201 202
		if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
			return -EFAULT;

		alarm.enabled = 0;
		alarm.pending = 0;
		alarm.time.tm_wday = -1;
		alarm.time.tm_yday = -1;
		alarm.time.tm_isdst = -1;
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241

		/* RTC_ALM_SET alarms may be up to 24 hours in the future.
		 * Rather than expecting every RTC to implement "don't care"
		 * for day/month/year fields, just force the alarm to have
		 * the right values for those fields.
		 *
		 * RTC_WKALM_SET should be used instead.  Not only does it
		 * eliminate the need for a separate RTC_AIE_ON call, it
		 * doesn't have the "alarm 23:59:59 in the future" race.
		 *
		 * NOTE:  some legacy code may have used invalid fields as
		 * wildcards, exposing hardware "periodic alarm" capabilities.
		 * Not supported here.
		 */
		{
			unsigned long now, then;

			err = rtc_read_time(rtc, &tm);
			if (err < 0)
				return err;
			rtc_tm_to_time(&tm, &now);

			alarm.time.tm_mday = tm.tm_mday;
			alarm.time.tm_mon = tm.tm_mon;
			alarm.time.tm_year = tm.tm_year;
			err  = rtc_valid_tm(&alarm.time);
			if (err < 0)
				return err;
			rtc_tm_to_time(&alarm.time, &then);

			/* alarm may need to wrap into tomorrow */
			if (then < now) {
				rtc_time_to_tm(now + 24 * 60 * 60, &tm);
				alarm.time.tm_mday = tm.tm_mday;
				alarm.time.tm_mon = tm.tm_mon;
				alarm.time.tm_year = tm.tm_year;
			}
		}

D
David Brownell 已提交
242
		return rtc_set_alarm(rtc, &alarm);
243 244

	case RTC_RD_TIME:
D
David Brownell 已提交
245 246
		mutex_unlock(&rtc->ops_lock);

247
		err = rtc_read_time(rtc, &tm);
248 249 250 251
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &tm, sizeof(tm)))
D
David Brownell 已提交
252 253
			err = -EFAULT;
		return err;
254 255

	case RTC_SET_TIME:
D
David Brownell 已提交
256 257
		mutex_unlock(&rtc->ops_lock);

258 259 260
		if (copy_from_user(&tm, uarg, sizeof(tm)))
			return -EFAULT;

D
David Brownell 已提交
261
		return rtc_set_time(rtc, &tm);
262

A
Alessandro Zummo 已提交
263 264 265 266 267 268
	case RTC_PIE_ON:
		err = rtc_irq_set_state(rtc, NULL, 1);
		break;

	case RTC_PIE_OFF:
		err = rtc_irq_set_state(rtc, NULL, 0);
269 270
		break;

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	case RTC_AIE_ON:
		mutex_unlock(&rtc->ops_lock);
		return rtc_alarm_irq_enable(rtc, 1);

	case RTC_AIE_OFF:
		mutex_unlock(&rtc->ops_lock);
		return rtc_alarm_irq_enable(rtc, 0);

	case RTC_UIE_ON:
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 1);

	case RTC_UIE_OFF:
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 0);

287
	case RTC_IRQP_SET:
A
Alessandro Zummo 已提交
288 289 290 291 292
		err = rtc_irq_set_freq(rtc, NULL, arg);
		break;

	case RTC_IRQP_READ:
		err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
293 294
		break;

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
#if 0
	case RTC_EPOCH_SET:
#ifndef rtc_epoch
		/*
		 * There were no RTC clocks before 1900.
		 */
		if (arg < 1900) {
			err = -EINVAL;
			break;
		}
		rtc_epoch = arg;
		err = 0;
#endif
		break;

	case RTC_EPOCH_READ:
		err = put_user(rtc_epoch, (unsigned long __user *)uarg);
		break;
#endif
	case RTC_WKALM_SET:
D
David Brownell 已提交
315
		mutex_unlock(&rtc->ops_lock);
316 317 318
		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
			return -EFAULT;

D
David Brownell 已提交
319
		return rtc_set_alarm(rtc, &alarm);
320 321

	case RTC_WKALM_RD:
D
David Brownell 已提交
322
		mutex_unlock(&rtc->ops_lock);
323
		err = rtc_read_alarm(rtc, &alarm);
324 325 326 327
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &alarm, sizeof(alarm)))
D
David Brownell 已提交
328 329
			err = -EFAULT;
		return err;
330 331

	default:
332
		err = -ENOTTY;
333 334 335
		break;
	}

D
David Brownell 已提交
336 337
done:
	mutex_unlock(&rtc->ops_lock);
338 339 340
	return err;
}

341 342 343 344 345 346
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
	struct rtc_device *rtc = file->private_data;
	return fasync_helper(fd, file, on, &rtc->async_queue);
}

347 348
static int rtc_dev_release(struct inode *inode, struct file *file)
{
349
	struct rtc_device *rtc = file->private_data;
350

351 352 353 354 355 356 357 358
	/* We shut down the repeating IRQs that userspace enabled,
	 * since nothing is listening to them.
	 *  - Update (UIE) ... currently only managed through ioctls
	 *  - Periodic (PIE) ... also used through rtc_*() interface calls
	 *
	 * Leave the alarm alone; it may be set to trigger a system wakeup
	 * later, or be used by kernel code, and is a one-shot event anyway.
	 */
359 360

	/* Keep ioctl until all drivers are converted */
361
	rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
362
	rtc_update_irq_enable(rtc, 0);
363 364
	rtc_irq_set_state(rtc, NULL, 0);

365
	if (rtc->ops->release)
366
		rtc->ops->release(rtc->dev.parent);
367

368
	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
369 370 371
	return 0;
}

372
static const struct file_operations rtc_dev_fops = {
373 374 375 376
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= rtc_dev_read,
	.poll		= rtc_dev_poll,
D
David Brownell 已提交
377
	.unlocked_ioctl	= rtc_dev_ioctl,
378 379 380 381 382 383 384
	.open		= rtc_dev_open,
	.release	= rtc_dev_release,
	.fasync		= rtc_dev_fasync,
};

/* insertion/removal hooks */

385
void rtc_dev_prepare(struct rtc_device *rtc)
386
{
387 388
	if (!rtc_devt)
		return;
389 390

	if (rtc->id >= RTC_DEV_MAX) {
391 392
		pr_debug("%s: too many RTC devices\n", rtc->name);
		return;
393 394
	}

395
	rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
396

397 398
	cdev_init(&rtc->char_dev, &rtc_dev_fops);
	rtc->char_dev.owner = rtc->owner;
399
}
400

401 402
void rtc_dev_add_device(struct rtc_device *rtc)
{
403
	if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
404 405 406 407
		printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
			rtc->name, MAJOR(rtc_devt), rtc->id);
	else
		pr_debug("%s: dev (%d:%d)\n", rtc->name,
408 409 410
			MAJOR(rtc_devt), rtc->id);
}

411
void rtc_dev_del_device(struct rtc_device *rtc)
412
{
413
	if (rtc->dev.devt)
414 415 416
		cdev_del(&rtc->char_dev);
}

417
void __init rtc_dev_init(void)
418 419 420 421
{
	int err;

	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
422
	if (err < 0)
423 424 425 426
		printk(KERN_ERR "%s: failed to allocate char dev region\n",
			__FILE__);
}

427
void __exit rtc_dev_exit(void)
428
{
429 430
	if (rtc_devt)
		unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
431
}