Blame view

drivers/char/rtc.c 33.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
2
   *	Real Time Clock interface for Linux
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   *	Copyright (C) 1996 Paul Gortmaker
   *
   *	This driver allows use of the real time clock (built into
   *	nearly all computers) from user space. It exports the /dev/rtc
   *	interface supporting various ioctl() and also the
   *	/proc/driver/rtc pseudo-file for status information.
   *
   *	The ioctls can be used to set the interrupt behaviour and
   *	generation rate from the RTC via IRQ 8. Then the /dev/rtc
   *	interface can be used to make use of these timer interrupts,
   *	be they interval or alarm based.
   *
   *	The /dev/rtc interface will block on reads until an interrupt
   *	has been received. If a RTC interrupt has already happened,
   *	it will output an unsigned long and then block. The output value
   *	contains the interrupt status in the low byte and the number of
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
20
   *	interrupts since the last read in the remaining high bytes. The
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
   *	/dev/rtc interface can also be used with the select(2) call.
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
   *	Based on other minimal char device drivers, like Alan's
   *	watchdog, Ted's random, etc. etc.
   *
   *	1.07	Paul Gortmaker.
   *	1.08	Miquel van Smoorenburg: disallow certain things on the
   *		DEC Alpha as the CMOS clock is also used for other things.
   *	1.09	Nikita Schmidt: epoch support and some Alpha cleanup.
   *	1.09a	Pete Zaitcev: Sun SPARC
   *	1.09b	Jeff Garzik: Modularize, init cleanup
   *	1.09c	Jeff Garzik: SMP cleanup
12a0a703b   Ralf Baechle   [RTC] Consistentl...
38
   *	1.10	Paul Barton-Davis: add support for async I/O
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
   *	1.10a	Andrea Arcangeli: Alpha updates
   *	1.10b	Andrew Morton: SMP lock fix
   *	1.10c	Cesar Barros: SMP locking fixes and cleanup
   *	1.10d	Paul Gortmaker: delete paranoia check in rtc_exit
   *	1.10e	Maciej W. Rozycki: Handle DECstation's year weirdness.
12a0a703b   Ralf Baechle   [RTC] Consistentl...
44
   *	1.11	Takashi Iwai: Kernel access functions
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
   *			      rtc_register/rtc_unregister/rtc_control
   *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
   *	1.12	Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
   *		CONFIG_HPET_EMULATE_RTC
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
49
   *	1.12a	Maciej W. Rozycki: Handle memory-mapped chips properly.
b7599587f   Alan Cox   [PATCH] Allow rea...
50
   *	1.12ac	Alan Cox: Allow read access to the day of week register
048cd5888   David John   RTC: Remove the BKL.
51
   *	1.12b	David John: Remove calls to the BKL.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
   */
048cd5888   David John   RTC: Remove the BKL.
53
  #define RTC_VERSION		"1.12b"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
  /*
   *	Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
   *	interrupts disabled. Due to the index-port/data-port (0x70/0x71)
   *	design of the RTC, we don't want two different things trying to
   *	get to it at once. (e.g. the periodic 11 min sync from time.c vs.
   *	this driver.)
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/types.h>
  #include <linux/miscdevice.h>
  #include <linux/ioport.h>
  #include <linux/fcntl.h>
  #include <linux/mc146818rtc.h>
  #include <linux/init.h>
  #include <linux/poll.h>
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/spinlock.h>
86ae13b00   Ingo Molnar   headers: Fix buil...
75
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
  #include <linux/sysctl.h>
  #include <linux/wait.h>
  #include <linux/bcd.h>
47f176fda   Luca Falavigna   [PATCH] Using msl...
79
  #include <linux/delay.h>
53f1b1433   Alan Cox   rtc: push the BKL...
80
  #include <linux/uaccess.h>
a28ee477e   Christian Dietrich   drivers/char/rtc:...
81
  #include <linux/ratelimit.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  
  #include <asm/current.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  #include <asm/system.h>
55f93afd8   Chris Wright   x86_64: Untangle ...
85
  #ifdef CONFIG_X86
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  #include <asm/hpet.h>
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
88
  #ifdef CONFIG_SPARC32
75081322c   David S. Miller   sparc32: Convert ...
89
90
91
  #include <linux/of.h>
  #include <linux/of_device.h>
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
  
  static unsigned long rtc_port;
75081322c   David S. Miller   sparc32: Convert ...
94
  static int rtc_irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  #endif
0f4d3fd8a   David Brownell   legacy rtc: remov...
96
  #ifdef	CONFIG_HPET_EMULATE_RTC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
102
103
104
105
  #undef	RTC_IRQ
  #endif
  
  #ifdef RTC_IRQ
  static int rtc_has_irq = 1;
  #endif
  
  #ifndef CONFIG_HPET_EMULATE_RTC
  #define is_hpet_enabled()			0
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
106
107
108
109
110
111
  #define hpet_set_alarm_time(hrs, min, sec)	0
  #define hpet_set_periodic_freq(arg)		0
  #define hpet_mask_rtc_irq_bit(arg)		0
  #define hpet_set_rtc_irq_bit(arg)		0
  #define hpet_rtc_timer_init()			do { } while (0)
  #define hpet_rtc_dropped_irq()			0
32fa45868   David Howells   Fix hpet_(un)regi...
112
113
  #define hpet_register_irq_handler(h)		({ 0; })
  #define hpet_unregister_irq_handler(h)		({ 0; })
533ffc289   Andrew Morton   [PATCH] rtc warni...
114
115
116
117
118
119
  #ifdef RTC_IRQ
  static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
  {
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  #endif
  
  /*
   *	We sponge a minor off of the misc major. No need slurping
   *	up another valuable major dev number for this. If you add
   *	an ioctl, make sure you don't conflict with SPARC's RTC
   *	ioctls.
   */
  
  static struct fasync_struct *rtc_async_queue;
  
  static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
  
  #ifdef RTC_IRQ
40565f196   Jiri Slaby   [PATCH] Char: tim...
134
135
136
  static void rtc_dropped_irq(unsigned long data);
  
  static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
  #endif
  
  static ssize_t rtc_read(struct file *file, char __user *buf,
  			size_t count, loff_t *ppos);
53f1b1433   Alan Cox   rtc: push the BKL...
141
  static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
9580d85f9   Adrian Bunk   drivers/char/rtc....
142
  static void rtc_get_rtc_time(struct rtc_time *rtc_tm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
  
  #ifdef RTC_IRQ
  static unsigned int rtc_poll(struct file *file, poll_table *wait);
  #endif
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
147
  static void get_rtc_alm_time(struct rtc_time *alm_tm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  #ifdef RTC_IRQ
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  static void set_rtc_irq_bit_locked(unsigned char bit);
  static void mask_rtc_irq_bit_locked(unsigned char bit);
  
  static inline void set_rtc_irq_bit(unsigned char bit)
  {
  	spin_lock_irq(&rtc_lock);
  	set_rtc_irq_bit_locked(bit);
  	spin_unlock_irq(&rtc_lock);
  }
  
  static void mask_rtc_irq_bit(unsigned char bit)
  {
  	spin_lock_irq(&rtc_lock);
  	mask_rtc_irq_bit_locked(bit);
  	spin_unlock_irq(&rtc_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  #endif
9cef779ec   Jan Beulich   [PATCH] RTC drive...
166
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  static int rtc_proc_open(struct inode *inode, struct file *file);
9cef779ec   Jan Beulich   [PATCH] RTC drive...
168
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
176
177
178
  
  /*
   *	Bits in rtc_status. (6 bits of room for future expansion)
   */
  
  #define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
  #define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
  
  /*
   * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
048cd5888   David John   RTC: Remove the BKL.
179
180
   * protected by the spin lock rtc_lock. However, ioctl can still disable the
   * timer in rtc_status and then with del_timer after the interrupt has read
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
   * rtc_status but before mod_timer is called, which would then reenable the
   * timer (but you would need to have an awful timing before you'd trip on it)
   */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
184
185
186
  static unsigned long rtc_status;	/* bitmapped status byte.	*/
  static unsigned long rtc_freq;		/* Current periodic IRQ rate	*/
  static unsigned long rtc_irq_data;	/* our output to the world	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
  static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
  
  #ifdef RTC_IRQ
  /*
   * rtc_task_lock nests inside rtc_lock.
   */
  static DEFINE_SPINLOCK(rtc_task_lock);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
194
  static rtc_task_t *rtc_callback;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
200
201
202
  #endif
  
  /*
   *	If this driver ever becomes modularised, it will be really nice
   *	to make the epoch retain its value across module reload...
   */
  
  static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
203
  static const unsigned char days_in_mo[] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
210
  {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  
  /*
   * Returns true if a clock update is in progress
   */
  static inline unsigned char rtc_is_updating(void)
  {
0b16f21f1   Peter Zijlstra   [PATCH] rtc: lock...
211
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  	unsigned char uip;
0b16f21f1   Peter Zijlstra   [PATCH] rtc: lock...
213
  	spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
0b16f21f1   Peter Zijlstra   [PATCH] rtc: lock...
215
  	spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
  	return uip;
  }
  
  #ifdef RTC_IRQ
  /*
0f2ed4c6b   Thomas Gleixner   [PATCH] irq-flags...
221
   *	A very tiny interrupt handler. It runs with IRQF_DISABLED set,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
   *	but there is possibility of conflicting with the set_rtc_mmss()
   *	call (the rtc irq and the timer irq can easily run at the same
   *	time in two different CPUs). So we need to serialize
   *	accesses to the chip with the rtc_lock spinlock that each
   *	architecture should implement in the timer code.
   *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
   */
9580d85f9   Adrian Bunk   drivers/char/rtc....
229
  static irqreturn_t rtc_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
232
233
234
235
236
  {
  	/*
  	 *	Can be an alarm interrupt, update complete interrupt,
  	 *	or a periodic interrupt. We store the status in the
  	 *	low byte and the number of interrupts received since
  	 *	the last read in the remainder of rtc_irq_data.
  	 */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
237
  	spin_lock(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  	rtc_irq_data += 0x100;
  	rtc_irq_data &= ~0xff;
  	if (is_hpet_enabled()) {
  		/*
  		 * In this case it is HPET RTC interrupt handler
  		 * calling us, with the interrupt information
  		 * passed as arg1, instead of irq.
  		 */
  		rtc_irq_data |= (unsigned long)irq & 0xF0;
  	} else {
  		rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
  	}
  
  	if (rtc_status & RTC_TIMER_ON)
  		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
253
  	spin_unlock(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
  
  	/* Now do the rest of the actions */
  	spin_lock(&rtc_task_lock);
  	if (rtc_callback)
  		rtc_callback->func(rtc_callback->private_data);
  	spin_unlock(&rtc_task_lock);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
260
  	wake_up_interruptible(&rtc_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
262
  	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
270
271
272
  
  	return IRQ_HANDLED;
  }
  #endif
  
  /*
   * sysctl-tuning infrastructure.
   */
  static ctl_table rtc_table[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
  		.procname	= "max-user-freq",
  		.data		= &rtc_max_user_freq,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d4561110   Eric W. Biederman   sysctl: Drop & in...
277
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
279
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  };
  
  static ctl_table rtc_root[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  		.procname	= "rtc",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
  		.mode		= 0555,
  		.child		= rtc_table,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
288
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
  };
  
  static ctl_table dev_root[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  		.procname	= "dev",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
  		.mode		= 0555,
  		.child		= rtc_root,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
297
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
301
302
303
  };
  
  static struct ctl_table_header *sysctl_header;
  
  static int __init init_sysctl(void)
  {
0b4d41471   Eric W. Biederman   [PATCH] sysctl: r...
304
      sysctl_header = register_sysctl_table(dev_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
      return 0;
  }
  
  static void __exit cleanup_sysctl(void)
  {
      unregister_sysctl_table(sysctl_header);
  }
  
  /*
   *	Now all the various file operations that we export.
   */
  
  static ssize_t rtc_read(struct file *file, char __user *buf,
  			size_t count, loff_t *ppos)
  {
  #ifndef RTC_IRQ
  	return -EIO;
  #else
  	DECLARE_WAITQUEUE(wait, current);
  	unsigned long data;
  	ssize_t retval;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
326

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  	if (rtc_has_irq == 0)
  		return -EIO;
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
329
330
331
332
333
334
335
336
337
  	/*
  	 * Historically this function used to assume that sizeof(unsigned long)
  	 * is the same in userspace and kernelspace.  This lead to problems
  	 * for configurations with multiple ABIs such a the MIPS o32 and 64
  	 * ABIs supported on the same kernel.  So now we support read of both
  	 * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
  	 * userspace ABI.
  	 */
  	if (count != sizeof(unsigned int) && count !=  sizeof(unsigned long))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
342
343
344
345
346
347
  		return -EINVAL;
  
  	add_wait_queue(&rtc_wait, &wait);
  
  	do {
  		/* First make it right. Then make it fast. Putting this whole
  		 * block within the parentheses of a while would be too
  		 * confusing. And no, xchg() is not the answer. */
  
  		__set_current_state(TASK_INTERRUPTIBLE);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
348
349
  
  		spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
  		data = rtc_irq_data;
  		rtc_irq_data = 0;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
352
  		spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
358
359
360
361
362
363
364
365
366
  
  		if (data != 0)
  			break;
  
  		if (file->f_flags & O_NONBLOCK) {
  			retval = -EAGAIN;
  			goto out;
  		}
  		if (signal_pending(current)) {
  			retval = -ERESTARTSYS;
  			goto out;
  		}
  		schedule();
  	} while (1);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
367
368
369
370
371
372
373
  	if (count == sizeof(unsigned int)) {
  		retval = put_user(data,
  				  (unsigned int __user *)buf) ?: sizeof(int);
  	} else {
  		retval = put_user(data,
  				  (unsigned long __user *)buf) ?: sizeof(long);
  	}
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
374
375
  	if (!retval)
  		retval = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
   out:
cc0a8fbb7   Milind Arun Choudhary   drivers/char: use...
377
  	__set_current_state(TASK_RUNNING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
  	remove_wait_queue(&rtc_wait, &wait);
  
  	return retval;
  #endif
  }
  
  static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
  {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
386
  	struct rtc_time wtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
  
  #ifdef RTC_IRQ
  	if (rtc_has_irq == 0) {
  		switch (cmd) {
  		case RTC_AIE_OFF:
  		case RTC_AIE_ON:
  		case RTC_PIE_OFF:
  		case RTC_PIE_ON:
  		case RTC_UIE_OFF:
  		case RTC_UIE_ON:
  		case RTC_IRQP_READ:
  		case RTC_IRQP_SET:
  			return -EINVAL;
  		};
  	}
  #endif
  
  	switch (cmd) {
  #ifdef RTC_IRQ
  	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
  	{
  		mask_rtc_irq_bit(RTC_AIE);
  		return 0;
  	}
  	case RTC_AIE_ON:	/* Allow alarm interrupts.	*/
  	{
  		set_rtc_irq_bit(RTC_AIE);
  		return 0;
  	}
  	case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
418
419
420
421
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
  
  		spin_lock_irqsave(&rtc_lock, flags);
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
422
  		mask_rtc_irq_bit_locked(RTC_PIE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  		if (rtc_status & RTC_TIMER_ON) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  			rtc_status &= ~RTC_TIMER_ON;
  			del_timer(&rtc_irq_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  		}
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
427
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
431
  		return 0;
  	}
  	case RTC_PIE_ON:	/* Allow periodic ints		*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
432
433
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
  		/*
  		 * We don't really want Joe User enabling more
  		 * than 64Hz of interrupts on a multi-user machine.
  		 */
  		if (!kernel && (rtc_freq > rtc_max_user_freq) &&
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
439
  						(!capable(CAP_SYS_RESOURCE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  			return -EACCES;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
441
  		spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  		if (!(rtc_status & RTC_TIMER_ON)) {
40565f196   Jiri Slaby   [PATCH] Char: tim...
443
444
  			mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
  					2*HZ/100);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  			rtc_status |= RTC_TIMER_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  		}
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
447
  		set_rtc_irq_bit_locked(RTC_PIE);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
448
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  		return 0;
  	}
  	case RTC_UIE_OFF:	/* Mask ints from RTC updates.	*/
  	{
  		mask_rtc_irq_bit(RTC_UIE);
  		return 0;
  	}
  	case RTC_UIE_ON:	/* Allow ints for RTC updates.	*/
  	{
  		set_rtc_irq_bit(RTC_UIE);
  		return 0;
  	}
  #endif
  	case RTC_ALM_READ:	/* Read the present alarm time */
  	{
  		/*
  		 * This returns a struct rtc_time. Reading >= 0xc0
  		 * means "don't care" or "match all". Only the tm_hour,
  		 * tm_min, and tm_sec values are filled in.
  		 */
  		memset(&wtime, 0, sizeof(struct rtc_time));
  		get_rtc_alm_time(&wtime);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
471
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  	}
  	case RTC_ALM_SET:	/* Store a time into the alarm */
  	{
  		/*
  		 * This expects a struct rtc_time. Writing 0xff means
  		 * "don't care" or "match all". Only the tm_hour,
  		 * tm_min and tm_sec are used.
  		 */
  		unsigned char hrs, min, sec;
  		struct rtc_time alm_tm;
  
  		if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg,
  				   sizeof(struct rtc_time)))
  			return -EFAULT;
  
  		hrs = alm_tm.tm_hour;
  		min = alm_tm.tm_min;
  		sec = alm_tm.tm_sec;
  
  		spin_lock_irq(&rtc_lock);
  		if (hpet_set_alarm_time(hrs, min, sec)) {
  			/*
  			 * Fallthru and set alarm time in CMOS too,
  			 * so that we will get proper value in RTC_ALM_READ
  			 */
  		}
  		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
499
500
  							RTC_ALWAYS_BCD) {
  			if (sec < 60)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
501
  				sec = bin2bcd(sec);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
502
503
504
505
  			else
  				sec = 0xff;
  
  			if (min < 60)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
506
  				min = bin2bcd(min);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
507
508
509
510
  			else
  				min = 0xff;
  
  			if (hrs < 24)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
511
  				hrs = bin2bcd(hrs);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
512
513
  			else
  				hrs = 0xff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  		}
  		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
  		CMOS_WRITE(min, RTC_MINUTES_ALARM);
  		CMOS_WRITE(sec, RTC_SECONDS_ALARM);
  		spin_unlock_irq(&rtc_lock);
  
  		return 0;
  	}
  	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
  	{
  		memset(&wtime, 0, sizeof(struct rtc_time));
  		rtc_get_rtc_time(&wtime);
  		break;
  	}
  	case RTC_SET_TIME:	/* Set the RTC */
  	{
  		struct rtc_time rtc_tm;
  		unsigned char mon, day, hrs, min, sec, leap_yr;
  		unsigned char save_control, save_freq_select;
  		unsigned int yrs;
  #ifdef CONFIG_MACH_DECSTATION
  		unsigned int real_yrs;
  #endif
  
  		if (!capable(CAP_SYS_TIME))
  			return -EACCES;
  
  		if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg,
  				   sizeof(struct rtc_time)))
  			return -EFAULT;
  
  		yrs = rtc_tm.tm_year + 1900;
  		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
  		day = rtc_tm.tm_mday;
  		hrs = rtc_tm.tm_hour;
  		min = rtc_tm.tm_min;
  		sec = rtc_tm.tm_sec;
  
  		if (yrs < 1970)
  			return -EINVAL;
  
  		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
  
  		if ((mon > 12) || (day == 0))
  			return -EINVAL;
  
  		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
  			return -EINVAL;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
562

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
  		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
  			return -EINVAL;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
565
566
  		yrs -= epoch;
  		if (yrs > 255)		/* They are unsigned */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  			return -EINVAL;
  
  		spin_lock_irq(&rtc_lock);
  #ifdef CONFIG_MACH_DECSTATION
  		real_yrs = yrs;
  		yrs = 72;
  
  		/*
  		 * We want to keep the year set to 73 until March
  		 * for non-leap years, so that Feb, 29th is handled
  		 * correctly.
  		 */
  		if (!leap_yr && mon < 3) {
  			real_yrs--;
  			yrs = 73;
  		}
  #endif
  		/* These limits and adjustments are independent of
  		 * whether the chip is in binary mode or not.
  		 */
  		if (yrs > 169) {
  			spin_unlock_irq(&rtc_lock);
  			return -EINVAL;
  		}
  		if (yrs >= 100)
  			yrs -= 100;
  
  		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
  		    || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
596
597
598
599
600
601
  			sec = bin2bcd(sec);
  			min = bin2bcd(min);
  			hrs = bin2bcd(hrs);
  			day = bin2bcd(day);
  			mon = bin2bcd(mon);
  			yrs = bin2bcd(yrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  		}
  
  		save_control = CMOS_READ(RTC_CONTROL);
  		CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
  		save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
  		CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
  
  #ifdef CONFIG_MACH_DECSTATION
  		CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
  #endif
  		CMOS_WRITE(yrs, RTC_YEAR);
  		CMOS_WRITE(mon, RTC_MONTH);
  		CMOS_WRITE(day, RTC_DAY_OF_MONTH);
  		CMOS_WRITE(hrs, RTC_HOURS);
  		CMOS_WRITE(min, RTC_MINUTES);
  		CMOS_WRITE(sec, RTC_SECONDS);
  
  		CMOS_WRITE(save_control, RTC_CONTROL);
  		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
  
  		spin_unlock_irq(&rtc_lock);
  		return 0;
  	}
  #ifdef RTC_IRQ
  	case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
  	{
  		return put_user(rtc_freq, (unsigned long __user *)arg);
  	}
  	case RTC_IRQP_SET:	/* Set periodic IRQ rate.	*/
  	{
  		int tmp = 0;
  		unsigned char val;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
634
635
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
637
  		/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
644
645
  		 * The max we can do is 8192Hz.
  		 */
  		if ((arg < 2) || (arg > 8192))
  			return -EINVAL;
  		/*
  		 * We don't really want Joe User generating more
  		 * than 64Hz of interrupts on a multi-user machine.
  		 */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
646
647
  		if (!kernel && (arg > rtc_max_user_freq) &&
  					!capable(CAP_SYS_RESOURCE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
  			return -EACCES;
  
  		while (arg > (1<<tmp))
  			tmp++;
  
  		/*
  		 * Check that the input was really a power of 2.
  		 */
  		if (arg != (1<<tmp))
  			return -EINVAL;
61ca9daa2   Paul Gortmaker   rtc: fix reported...
658
  		rtc_freq = arg;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
659
  		spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  		if (hpet_set_periodic_freq(arg)) {
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
661
  			spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
  
  		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
  		val |= (16 - tmp);
  		CMOS_WRITE(val, RTC_FREQ_SELECT);
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
668
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
  		return 0;
  	}
  #endif
  	case RTC_EPOCH_READ:	/* Read the epoch.	*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
674
  		return put_user(epoch, (unsigned long __user *)arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
677
  	}
  	case RTC_EPOCH_SET:	/* Set the epoch.	*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
678
  		/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
683
684
685
686
687
688
689
690
691
692
  		 * There were no RTC clocks before 1900.
  		 */
  		if (arg < 1900)
  			return -EINVAL;
  
  		if (!capable(CAP_SYS_TIME))
  			return -EACCES;
  
  		epoch = arg;
  		return 0;
  	}
  	default:
  		return -ENOTTY;
  	}
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
693
694
  	return copy_to_user((void __user *)arg,
  			    &wtime, sizeof wtime) ? -EFAULT : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  }
53f1b1433   Alan Cox   rtc: push the BKL...
696
  static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  {
53f1b1433   Alan Cox   rtc: push the BKL...
698
  	long ret;
53f1b1433   Alan Cox   rtc: push the BKL...
699
  	ret = rtc_do_ioctl(cmd, arg, 0);
53f1b1433   Alan Cox   rtc: push the BKL...
700
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
706
707
  }
  
  /*
   *	We enforce only one user at a time here with the open/close.
   *	Also clear the previous interrupt data on an open, and clean
   *	up things on a close.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
  static int rtc_open(struct inode *inode, struct file *file)
  {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
710
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
712
  	if (rtc_status & RTC_IS_OPEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
  		goto out_busy;
  
  	rtc_status |= RTC_IS_OPEN;
  
  	rtc_irq_data = 0;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
718
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
  	return 0;
  
  out_busy:
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
722
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
  	return -EBUSY;
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
725
  static int rtc_fasync(int fd, struct file *filp, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
  {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
727
  	return fasync_helper(fd, filp, on, &rtc_async_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
  }
  
  static int rtc_release(struct inode *inode, struct file *file)
  {
  #ifdef RTC_IRQ
  	unsigned char tmp;
  
  	if (rtc_has_irq == 0)
  		goto no_irq;
  
  	/*
  	 * Turn off all interrupts once the device is no longer
  	 * in use, and clear the data.
  	 */
  
  	spin_lock_irq(&rtc_lock);
  	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
  		tmp = CMOS_READ(RTC_CONTROL);
  		tmp &=  ~RTC_PIE;
  		tmp &=  ~RTC_AIE;
  		tmp &=  ~RTC_UIE;
  		CMOS_WRITE(tmp, RTC_CONTROL);
  		CMOS_READ(RTC_INTR_FLAGS);
  	}
  	if (rtc_status & RTC_TIMER_ON) {
  		rtc_status &= ~RTC_TIMER_ON;
  		del_timer(&rtc_irq_timer);
  	}
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  no_irq:
  #endif
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
759
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  	rtc_irq_data = 0;
  	rtc_status &= ~RTC_IS_OPEN;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
762
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
  	return 0;
  }
  
  #ifdef RTC_IRQ
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
  static unsigned int rtc_poll(struct file *file, poll_table *wait)
  {
  	unsigned long l;
  
  	if (rtc_has_irq == 0)
  		return 0;
  
  	poll_wait(file, &rtc_wait, wait);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
775
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  	l = rtc_irq_data;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
777
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
779
780
781
782
783
  
  	if (l != 0)
  		return POLLIN | POLLRDNORM;
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  int rtc_register(rtc_task_t *task)
  {
  #ifndef RTC_IRQ
  	return -EIO;
  #else
  	if (task == NULL || task->func == NULL)
  		return -EINVAL;
  	spin_lock_irq(&rtc_lock);
  	if (rtc_status & RTC_IS_OPEN) {
  		spin_unlock_irq(&rtc_lock);
  		return -EBUSY;
  	}
  	spin_lock(&rtc_task_lock);
  	if (rtc_callback) {
  		spin_unlock(&rtc_task_lock);
  		spin_unlock_irq(&rtc_lock);
  		return -EBUSY;
  	}
  	rtc_status |= RTC_IS_OPEN;
  	rtc_callback = task;
  	spin_unlock(&rtc_task_lock);
  	spin_unlock_irq(&rtc_lock);
  	return 0;
  #endif
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
809
  EXPORT_SYMBOL(rtc_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
  
  int rtc_unregister(rtc_task_t *task)
  {
  #ifndef RTC_IRQ
  	return -EIO;
  #else
  	unsigned char tmp;
  
  	spin_lock_irq(&rtc_lock);
  	spin_lock(&rtc_task_lock);
  	if (rtc_callback != task) {
  		spin_unlock(&rtc_task_lock);
  		spin_unlock_irq(&rtc_lock);
  		return -ENXIO;
  	}
  	rtc_callback = NULL;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
826

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  	/* disable controls */
  	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
  		tmp = CMOS_READ(RTC_CONTROL);
  		tmp &= ~RTC_PIE;
  		tmp &= ~RTC_AIE;
  		tmp &= ~RTC_UIE;
  		CMOS_WRITE(tmp, RTC_CONTROL);
  		CMOS_READ(RTC_INTR_FLAGS);
  	}
  	if (rtc_status & RTC_TIMER_ON) {
  		rtc_status &= ~RTC_TIMER_ON;
  		del_timer(&rtc_irq_timer);
  	}
  	rtc_status &= ~RTC_IS_OPEN;
  	spin_unlock(&rtc_task_lock);
  	spin_unlock_irq(&rtc_lock);
  	return 0;
  #endif
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
846
  EXPORT_SYMBOL(rtc_unregister);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
850
851
852
  
  int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
  {
  #ifndef RTC_IRQ
  	return -EIO;
  #else
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
853
854
855
856
  	unsigned long flags;
  	if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
  		return -EINVAL;
  	spin_lock_irqsave(&rtc_task_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  	if (rtc_callback != task) {
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
858
  		spin_unlock_irqrestore(&rtc_task_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  		return -ENXIO;
  	}
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
861
  	spin_unlock_irqrestore(&rtc_task_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
  	return rtc_do_ioctl(cmd, arg, 1);
  #endif
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
865
  EXPORT_SYMBOL(rtc_control);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
868
869
  
  /*
   *	The various file operations we support.
   */
62322d255   Arjan van de Ven   [PATCH] make more...
870
  static const struct file_operations rtc_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
876
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.read		= rtc_read,
  #ifdef RTC_IRQ
  	.poll		= rtc_poll,
  #endif
53f1b1433   Alan Cox   rtc: push the BKL...
877
  	.unlocked_ioctl	= rtc_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
884
885
886
887
  	.open		= rtc_open,
  	.release	= rtc_release,
  	.fasync		= rtc_fasync,
  };
  
  static struct miscdevice rtc_dev = {
  	.minor		= RTC_MINOR,
  	.name		= "rtc",
  	.fops		= &rtc_fops,
  };
9cef779ec   Jan Beulich   [PATCH] RTC drive...
888
  #ifdef CONFIG_PROC_FS
62322d255   Arjan van de Ven   [PATCH] make more...
889
  static const struct file_operations rtc_proc_fops = {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
890
891
892
893
894
  	.owner		= THIS_MODULE,
  	.open		= rtc_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  #endif
9626f1f11   Bjorn Helgaas   rtc: fall back to...
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  static resource_size_t rtc_size;
  
  static struct resource * __init rtc_request_region(resource_size_t size)
  {
  	struct resource *r;
  
  	if (RTC_IOMAPPED)
  		r = request_region(RTC_PORT(0), size, "rtc");
  	else
  		r = request_mem_region(RTC_PORT(0), size, "rtc");
  
  	if (r)
  		rtc_size = size;
  
  	return r;
  }
4c06be10c   Bjorn Helgaas   rtc: release corr...
913
914
915
  static void rtc_release_region(void)
  {
  	if (RTC_IOMAPPED)
9626f1f11   Bjorn Helgaas   rtc: fall back to...
916
  		release_region(RTC_PORT(0), rtc_size);
4c06be10c   Bjorn Helgaas   rtc: release corr...
917
  	else
9626f1f11   Bjorn Helgaas   rtc: fall back to...
918
  		release_mem_region(RTC_PORT(0), rtc_size);
4c06be10c   Bjorn Helgaas   rtc: release corr...
919
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
  static int __init rtc_init(void)
  {
9cef779ec   Jan Beulich   [PATCH] RTC drive...
922
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  	struct proc_dir_entry *ent;
9cef779ec   Jan Beulich   [PATCH] RTC drive...
924
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
  #if defined(__alpha__) || defined(__mips__)
  	unsigned int year, ctrl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
  	char *guess = NULL;
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
929
  #ifdef CONFIG_SPARC32
75081322c   David S. Miller   sparc32: Convert ...
930
  	struct device_node *ebus_dp;
2dc115813   Grant Likely   of/device: Replac...
931
  	struct platform_device *op;
9cef779ec   Jan Beulich   [PATCH] RTC drive...
932
  #else
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
933
  	void *r;
9cef779ec   Jan Beulich   [PATCH] RTC drive...
934
935
936
  #ifdef RTC_IRQ
  	irq_handler_t rtc_int_handler_ptr;
  #endif
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
937
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938

cdee99d74   David S. Miller   [SPARC64]: Stop u...
939
  #ifdef CONFIG_SPARC32
75081322c   David S. Miller   sparc32: Convert ...
940
941
942
943
944
945
946
947
948
949
  	for_each_node_by_name(ebus_dp, "ebus") {
  		struct device_node *dp;
  		for (dp = ebus_dp; dp; dp = dp->sibling) {
  			if (!strcmp(dp->name, "rtc")) {
  				op = of_find_device_by_node(dp);
  				if (op) {
  					rtc_port = op->resource[0].start;
  					rtc_irq = op->irqs[0];
  					goto found;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
  			}
  		}
  	}
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
953
  	rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
958
  	printk(KERN_ERR "rtc_init: no PC rtc found
  ");
  	return -EIO;
  
  found:
75081322c   David S. Miller   sparc32: Convert ...
959
  	if (!rtc_irq) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
  		rtc_has_irq = 0;
  		goto no_irq;
  	}
  
  	/*
  	 * XXX Interrupt pin #7 in Espresso is shared between RTC and
53d0fc27a   David S. Miller   [RTC]: Use SA_SHI...
966
  	 * PCI Slot 2 INTA# (and some INTx# in Slot 1).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
  	 */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
968
969
  	if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc",
  			(void *)&rtc_port)) {
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
970
  		rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
973
974
975
976
  		printk(KERN_ERR "rtc: cannot register IRQ %d
  ", rtc_irq);
  		return -EIO;
  	}
  no_irq:
  #else
9626f1f11   Bjorn Helgaas   rtc: fall back to...
977
978
979
980
981
982
983
984
985
986
987
  	r = rtc_request_region(RTC_IO_EXTENT);
  
  	/*
  	 * If we've already requested a smaller range (for example, because
  	 * PNPBIOS or ACPI told us how the device is configured), the request
  	 * above might fail because it's too big.
  	 *
  	 * If so, request just the range we actually use.
  	 */
  	if (!r)
  		r = rtc_request_region(RTC_IO_EXTENT_USED);
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
988
  	if (!r) {
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
989
990
991
  #ifdef RTC_IRQ
  		rtc_has_irq = 0;
  #endif
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
992
993
994
  		printk(KERN_ERR "rtc: I/O resource %lx is not free.
  ",
  		       (long)(RTC_PORT(0)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
998
999
  		return -EIO;
  	}
  
  #ifdef RTC_IRQ
  	if (is_hpet_enabled()) {
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1000
  		int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
  		rtc_int_handler_ptr = hpet_rtc_interrupt;
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1002
1003
1004
1005
1006
1007
  		err = hpet_register_irq_handler(rtc_interrupt);
  		if (err != 0) {
  			printk(KERN_WARNING "hpet_register_irq_handler failed "
  					"in rtc_init().");
  			return err;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
  	} else {
  		rtc_int_handler_ptr = rtc_interrupt;
  	}
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1011
1012
  	if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED,
  			"rtc", NULL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
  		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
1014
  		rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
  		printk(KERN_ERR "rtc: IRQ %d is not free.
  ", RTC_IRQ);
4c06be10c   Bjorn Helgaas   rtc: release corr...
1017
  		rtc_release_region();
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1018

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
1021
1022
1023
  		return -EIO;
  	}
  	hpet_rtc_timer_init();
  
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
1024
  #endif /* CONFIG_SPARC32 vs. others */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
1026
1027
1028
  
  	if (misc_register(&rtc_dev)) {
  #ifdef RTC_IRQ
  		free_irq(RTC_IRQ, NULL);
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1029
  		hpet_unregister_irq_handler(rtc_interrupt);
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
1030
  		rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  #endif
4c06be10c   Bjorn Helgaas   rtc: release corr...
1032
  		rtc_release_region();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
  		return -ENODEV;
  	}
9cef779ec   Jan Beulich   [PATCH] RTC drive...
1035
  #ifdef CONFIG_PROC_FS
1b5022173   Denis V. Lunev   drivers: use non-...
1036
1037
  	ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops);
  	if (!ent)
9cef779ec   Jan Beulich   [PATCH] RTC drive...
1038
1039
  		printk(KERN_WARNING "rtc: Failed to register with procfs.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
  
  #if defined(__alpha__) || defined(__mips__)
  	rtc_freq = HZ;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1044

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  	/* Each operating system on an Alpha uses its own epoch.
  	   Let's try to guess which one we are using now. */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1047

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
  	if (rtc_is_updating() != 0)
47f176fda   Luca Falavigna   [PATCH] Using msl...
1049
  		msleep(20);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1050

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
1052
1053
1054
  	spin_lock_irq(&rtc_lock);
  	year = CMOS_READ(RTC_YEAR);
  	ctrl = CMOS_READ(RTC_CONTROL);
  	spin_unlock_irq(&rtc_lock);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1055

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
  	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
1057
  		year = bcd2bin(year);       /* This should never happen... */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1058

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  	if (year < 20) {
  		epoch = 2000;
  		guess = "SRM (post-2000)";
  	} else if (year >= 20 && year < 48) {
  		epoch = 1980;
  		guess = "ARC console";
  	} else if (year >= 48 && year < 72) {
  		epoch = 1952;
  		guess = "Digital UNIX";
  #if defined(__mips__)
  	} else if (year >= 72 && year < 74) {
  		epoch = 2000;
  		guess = "Digital DECstation";
  #else
  	} else if (year >= 70) {
  		epoch = 1900;
  		guess = "Standard PC (1900)";
  #endif
  	}
  	if (guess)
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1079
1080
1081
  		printk(KERN_INFO "rtc: %s epoch (%lu) detected
  ",
  			guess, epoch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
1084
1085
  #endif
  #ifdef RTC_IRQ
  	if (rtc_has_irq == 0)
  		goto no_irq2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086
1087
1088
  	spin_lock_irq(&rtc_lock);
  	rtc_freq = 1024;
  	if (!hpet_set_periodic_freq(rtc_freq)) {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1089
1090
1091
1092
1093
1094
  		/*
  		 * Initialize periodic frequency to CMOS reset default,
  		 * which is 1024Hz
  		 */
  		CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06),
  			   RTC_FREQ_SELECT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	}
  	spin_unlock_irq(&rtc_lock);
  no_irq2:
  #endif
  
  	(void) init_sysctl();
  
  	printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "
  ");
  
  	return 0;
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1107
  static void __exit rtc_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
1109
  {
  	cleanup_sysctl();
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1110
  	remove_proc_entry("driver/rtc", NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
  	misc_deregister(&rtc_dev);
cdee99d74   David S. Miller   [SPARC64]: Stop u...
1112
  #ifdef CONFIG_SPARC32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
  	if (rtc_has_irq)
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1114
  		free_irq(rtc_irq, &rtc_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
  #else
4c06be10c   Bjorn Helgaas   rtc: release corr...
1116
  	rtc_release_region();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117
  #ifdef RTC_IRQ
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1118
  	if (rtc_has_irq) {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1119
  		free_irq(RTC_IRQ, NULL);
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1120
1121
  		hpet_unregister_irq_handler(hpet_rtc_interrupt);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
1123
  #endif /* CONFIG_SPARC32 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
1126
1127
1128
1129
1130
  }
  
  module_init(rtc_init);
  module_exit(rtc_exit);
  
  #ifdef RTC_IRQ
  /*
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1131
   *	At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
1136
1137
   *	(usually during an IDE disk interrupt, with IRQ unmasking off)
   *	Since the interrupt handler doesn't get called, the IRQ status
   *	byte doesn't get read, and the RTC stops generating interrupts.
   *	A timer is set, and will call this function if/when that happens.
   *	To get it out of this stalled state, we just read the status.
   *	At least a jiffy of interrupts (rtc_freq/HZ) will have been lost.
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1138
   *	(You *really* shouldn't be trying to use a non-realtime system
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
1142
1143
1144
   *	for something that requires a steady > 1KHz signal anyways.)
   */
  
  static void rtc_dropped_irq(unsigned long data)
  {
  	unsigned long freq;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1145
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  
  	if (hpet_rtc_dropped_irq()) {
  		spin_unlock_irq(&rtc_lock);
  		return;
  	}
  
  	/* Just in case someone disabled the timer from behind our back... */
  	if (rtc_status & RTC_TIMER_ON)
  		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
  
  	rtc_irq_data += ((rtc_freq/HZ)<<8);
  	rtc_irq_data &= ~0xff;
  	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
  
  	freq = rtc_freq;
  
  	spin_unlock_irq(&rtc_lock);
a28ee477e   Christian Dietrich   drivers/char/rtc:...
1163
1164
1165
  	printk_ratelimited(KERN_WARNING "rtc: lost some interrupts at %ldHz.
  ",
  			   freq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
  
  	/* Now we have new data */
  	wake_up_interruptible(&rtc_wait);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1169
  	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
  }
  #endif
9cef779ec   Jan Beulich   [PATCH] RTC drive...
1172
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
  /*
   *	Info exported via "/proc/driver/rtc".
   */
  
  static int rtc_proc_show(struct seq_file *seq, void *v)
  {
  #define YN(bit) ((ctrl & bit) ? "yes" : "no")
  #define NY(bit) ((ctrl & bit) ? "no" : "yes")
  	struct rtc_time tm;
  	unsigned char batt, ctrl;
  	unsigned long freq;
  
  	spin_lock_irq(&rtc_lock);
  	batt = CMOS_READ(RTC_VALID) & RTC_VRT;
  	ctrl = CMOS_READ(RTC_CONTROL);
  	freq = rtc_freq;
  	spin_unlock_irq(&rtc_lock);
  
  
  	rtc_get_rtc_time(&tm);
  
  	/*
  	 * There is no way to tell if the luser has the RTC set for local
  	 * time or for Universal Standard Time (GMT). Probably local though.
  	 */
  	seq_printf(seq,
  		   "rtc_time\t: %02d:%02d:%02d
  "
  		   "rtc_date\t: %04d-%02d-%02d
  "
  		   "rtc_epoch\t: %04lu
  ",
  		   tm.tm_hour, tm.tm_min, tm.tm_sec,
  		   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
  
  	get_rtc_alm_time(&tm);
  
  	/*
  	 * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
  	 * match any value for that particular field. Values that are
  	 * greater than a valid time, but less than 0xc0 shouldn't appear.
  	 */
  	seq_puts(seq, "alarm\t\t: ");
  	if (tm.tm_hour <= 24)
  		seq_printf(seq, "%02d:", tm.tm_hour);
  	else
  		seq_puts(seq, "**:");
  
  	if (tm.tm_min <= 59)
  		seq_printf(seq, "%02d:", tm.tm_min);
  	else
  		seq_puts(seq, "**:");
  
  	if (tm.tm_sec <= 59)
  		seq_printf(seq, "%02d
  ", tm.tm_sec);
  	else
  		seq_puts(seq, "**
  ");
  
  	seq_printf(seq,
  		   "DST_enable\t: %s
  "
  		   "BCD\t\t: %s
  "
  		   "24hr\t\t: %s
  "
  		   "square_wave\t: %s
  "
  		   "alarm_IRQ\t: %s
  "
  		   "update_IRQ\t: %s
  "
  		   "periodic_IRQ\t: %s
  "
  		   "periodic_freq\t: %ld
  "
  		   "batt_status\t: %s
  ",
  		   YN(RTC_DST_EN),
  		   NY(RTC_DM_BINARY),
  		   YN(RTC_24H),
  		   YN(RTC_SQWE),
  		   YN(RTC_AIE),
  		   YN(RTC_UIE),
  		   YN(RTC_PIE),
  		   freq,
  		   batt ? "okay" : "dead");
  
  	return  0;
  #undef YN
  #undef NY
  }
  
  static int rtc_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, rtc_proc_show, NULL);
  }
9cef779ec   Jan Beulich   [PATCH] RTC drive...
1271
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272

9580d85f9   Adrian Bunk   drivers/char/rtc....
1273
  static void rtc_get_rtc_time(struct rtc_time *rtc_tm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
  {
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1275
  	unsigned long uip_watchdog = jiffies, flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
1280
1281
1282
  	unsigned char ctrl;
  #ifdef CONFIG_MACH_DECSTATION
  	unsigned int real_year;
  #endif
  
  	/*
  	 * read RTC once any update in progress is done. The update
47f176fda   Luca Falavigna   [PATCH] Using msl...
1283
  	 * can take just over 2ms. We wait 20ms. There is no need to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
  	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
  	 * If you need to know *exactly* when a second has started, enable
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1286
  	 * periodic update complete interrupts, (via ioctl) and then
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
1288
1289
  	 * immediately read /dev/rtc which will block until you get the IRQ.
  	 * Once the read clears, read the RTC time (again via ioctl). Easy.
  	 */
dca03a515   Julia Lawall   drivers/char/rtc....
1290
1291
  	while (rtc_is_updating() != 0 &&
  	       time_before(jiffies, uip_watchdog + 2*HZ/100))
403fe5ae5   Petr Vandrovec   [PATCH] rtc: msle...
1292
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
1294
1295
  
  	/*
  	 * Only the values that we read from the RTC are set. We leave
b7599587f   Alan Cox   [PATCH] Allow rea...
1296
1297
1298
  	 * tm_wday, tm_yday and tm_isdst untouched. Note that while the
  	 * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is
  	 * only updated by the RTC when initially set to a non-zero value.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
  	 */
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1300
  	spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
1303
1304
1305
1306
  	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
  	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
  	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
  	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
  	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
  	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
b7599587f   Alan Cox   [PATCH] Allow rea...
1307
1308
  	/* Only set from 2.6.16 onwards */
  	rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1309
1310
1311
1312
  #ifdef CONFIG_MACH_DECSTATION
  	real_year = CMOS_READ(RTC_DEC_YEAR);
  #endif
  	ctrl = CMOS_READ(RTC_CONTROL);
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1313
  	spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1314

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1315
  	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
1316
1317
1318
1319
1320
1321
1322
  		rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
  		rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
  		rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
  		rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
  		rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
  		rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
  		rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  	}
  
  #ifdef CONFIG_MACH_DECSTATION
  	rtc_tm->tm_year += real_year - 72;
  #endif
  
  	/*
  	 * Account for differences between how the RTC uses the values
  	 * and how they are defined in a struct rtc_time;
  	 */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1333
1334
  	rtc_tm->tm_year += epoch - 1900;
  	if (rtc_tm->tm_year <= 69)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  		rtc_tm->tm_year += 100;
  
  	rtc_tm->tm_mon--;
  }
  
  static void get_rtc_alm_time(struct rtc_time *alm_tm)
  {
  	unsigned char ctrl;
  
  	/*
  	 * Only the values that we read from the RTC are set. That
  	 * means only tm_hour, tm_min, and tm_sec.
  	 */
  	spin_lock_irq(&rtc_lock);
  	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
  	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
  	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
  	ctrl = CMOS_READ(RTC_CONTROL);
  	spin_unlock_irq(&rtc_lock);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1354
  	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
1355
1356
1357
  		alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
  		alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
  		alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
  	}
  }
  
  #ifdef RTC_IRQ
  /*
   * Used to disable/enable interrupts for any one of UIE, AIE, PIE.
   * Rumour has it that if you frob the interrupt enable/disable
   * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to
   * ensure you actually start getting interrupts. Probably for
   * compatibility with older/broken chipset RTC implementations.
   * We also clear out any old irq data after an ioctl() that
   * meddles with the interrupt enable/disable bits.
   */
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1371
  static void mask_rtc_irq_bit_locked(unsigned char bit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372
1373
  {
  	unsigned char val;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1374
  	if (hpet_mask_rtc_irq_bit(bit))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
1378
1379
1380
1381
  	val = CMOS_READ(RTC_CONTROL);
  	val &=  ~bit;
  	CMOS_WRITE(val, RTC_CONTROL);
  	CMOS_READ(RTC_INTR_FLAGS);
  
  	rtc_irq_data = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
  }
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1383
  static void set_rtc_irq_bit_locked(unsigned char bit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
  {
  	unsigned char val;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1386
  	if (hpet_set_rtc_irq_bit(bit))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
1389
1390
1391
1392
1393
  	val = CMOS_READ(RTC_CONTROL);
  	val |= bit;
  	CMOS_WRITE(val, RTC_CONTROL);
  	CMOS_READ(RTC_INTR_FLAGS);
  
  	rtc_irq_data = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
  }
  #endif
  
  MODULE_AUTHOR("Paul Gortmaker");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(RTC_MINOR);