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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  
  #include <asm/current.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
  #include <asm/system.h>
55f93afd8   Chris Wright   x86_64: Untangle ...
84
  #ifdef CONFIG_X86
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  #include <asm/hpet.h>
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
87
  #ifdef CONFIG_SPARC32
75081322c   David S. Miller   sparc32: Convert ...
88
89
90
  #include <linux/of.h>
  #include <linux/of_device.h>
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
  
  static unsigned long rtc_port;
75081322c   David S. Miller   sparc32: Convert ...
93
  static int rtc_irq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  #endif
0f4d3fd8a   David Brownell   legacy rtc: remov...
95
  #ifdef	CONFIG_HPET_EMULATE_RTC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
104
  #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...
105
106
107
108
109
110
  #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...
111
112
  #define hpet_register_irq_handler(h)		({ 0; })
  #define hpet_unregister_irq_handler(h)		({ 0; })
533ffc289   Andrew Morton   [PATCH] rtc warni...
113
114
115
116
117
118
  #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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  #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...
133
134
135
  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
136
137
138
139
  #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...
140
  static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
9580d85f9   Adrian Bunk   drivers/char/rtc....
141
  static void rtc_get_rtc_time(struct rtc_time *rtc_tm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
  
  #ifdef RTC_IRQ
  static unsigned int rtc_poll(struct file *file, poll_table *wait);
  #endif
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
146
  static void get_rtc_alm_time(struct rtc_time *alm_tm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  #ifdef RTC_IRQ
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  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
164
  #endif
9cef779ec   Jan Beulich   [PATCH] RTC drive...
165
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  static int rtc_proc_open(struct inode *inode, struct file *file);
9cef779ec   Jan Beulich   [PATCH] RTC drive...
167
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
173
174
175
176
177
  
  /*
   *	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.
178
179
   * 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
180
181
182
   * 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...
183
184
185
  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
186
187
188
189
190
191
192
  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...
193
  static rtc_task_t *rtc_callback;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
  #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...
202
  static const unsigned char days_in_mo[] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
  {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...
210
  	unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  	unsigned char uip;
0b16f21f1   Peter Zijlstra   [PATCH] rtc: lock...
212
  	spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
0b16f21f1   Peter Zijlstra   [PATCH] rtc: lock...
214
  	spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
  	return uip;
  }
  
  #ifdef RTC_IRQ
  /*
0f2ed4c6b   Thomas Gleixner   [PATCH] irq-flags...
220
   *	A very tiny interrupt handler. It runs with IRQF_DISABLED set,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
   *	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....
228
  static irqreturn_t rtc_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
  {
  	/*
  	 *	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...
236
  	spin_lock(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  	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...
252
  	spin_unlock(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
  
  	/* 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...
259
  	wake_up_interruptible(&rtc_wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
261
  	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
268
269
270
271
  
  	return IRQ_HANDLED;
  }
  #endif
  
  /*
   * sysctl-tuning infrastructure.
   */
  static ctl_table rtc_table[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
  		.procname	= "max-user-freq",
  		.data		= &rtc_max_user_freq,
  		.maxlen		= sizeof(int),
  		.mode		= 0644,
6d4561110   Eric W. Biederman   sysctl: Drop & in...
276
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
278
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
  };
  
  static ctl_table rtc_root[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  		.procname	= "rtc",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
  		.mode		= 0555,
  		.child		= rtc_table,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
287
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
  };
  
  static ctl_table dev_root[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  		.procname	= "dev",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
  		.mode		= 0555,
  		.child		= rtc_root,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
296
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
  };
  
  static struct ctl_table_header *sysctl_header;
  
  static int __init init_sysctl(void)
  {
0b4d41471   Eric W. Biederman   [PATCH] sysctl: r...
303
      sysctl_header = register_sysctl_table(dev_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
      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...
325

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
  	if (rtc_has_irq == 0)
  		return -EIO;
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
328
329
330
331
332
333
334
335
336
  	/*
  	 * 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
337
338
339
340
341
342
343
344
345
346
  		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...
347
348
  
  		spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  		data = rtc_irq_data;
  		rtc_irq_data = 0;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
351
  		spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  
  		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...
366
367
368
369
370
371
372
  	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:...
373
374
  	if (!retval)
  		retval = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
   out:
cc0a8fbb7   Milind Arun Choudhary   drivers/char: use...
376
  	__set_current_state(TASK_RUNNING);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
383
384
  	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...
385
  	struct rtc_time wtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
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
  
  #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...
417
418
419
420
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
  
  		spin_lock_irqsave(&rtc_lock, flags);
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
421
  		mask_rtc_irq_bit_locked(RTC_PIE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  		if (rtc_status & RTC_TIMER_ON) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
  			rtc_status &= ~RTC_TIMER_ON;
  			del_timer(&rtc_irq_timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  		}
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
426
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
430
  		return 0;
  	}
  	case RTC_PIE_ON:	/* Allow periodic ints		*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
431
432
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
  		/*
  		 * 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...
438
  						(!capable(CAP_SYS_RESOURCE)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  			return -EACCES;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
440
  		spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  		if (!(rtc_status & RTC_TIMER_ON)) {
40565f196   Jiri Slaby   [PATCH] Char: tim...
442
443
  			mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
  					2*HZ/100);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  			rtc_status |= RTC_TIMER_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  		}
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
446
  		set_rtc_irq_bit_locked(RTC_PIE);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
447
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  		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...
470
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
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
  	}
  	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...
498
499
  							RTC_ALWAYS_BCD) {
  			if (sec < 60)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
500
  				sec = bin2bcd(sec);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
501
502
503
504
  			else
  				sec = 0xff;
  
  			if (min < 60)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
505
  				min = bin2bcd(min);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
506
507
508
509
  			else
  				min = 0xff;
  
  			if (hrs < 24)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
510
  				hrs = bin2bcd(hrs);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
511
512
  			else
  				hrs = 0xff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
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
  		}
  		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...
561

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
  			return -EINVAL;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
564
565
  		yrs -= epoch;
  		if (yrs > 255)		/* They are unsigned */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
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
  			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/...
595
596
597
598
599
600
  			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
601
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
  		}
  
  		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...
633
634
  		/* can be called from isr via rtc_control() */
  		unsigned long flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
636
  		/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
640
641
642
643
644
  		 * 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...
645
646
  		if (!kernel && (arg > rtc_max_user_freq) &&
  					!capable(CAP_SYS_RESOURCE))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
654
655
656
  			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...
657
  		rtc_freq = arg;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
658
  		spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  		if (hpet_set_periodic_freq(arg)) {
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
660
  			spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  			return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
  
  		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
  		val |= (16 - tmp);
  		CMOS_WRITE(val, RTC_FREQ_SELECT);
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
667
  		spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
  		return 0;
  	}
  #endif
  	case RTC_EPOCH_READ:	/* Read the epoch.	*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
673
  		return put_user(epoch, (unsigned long __user *)arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
675
676
  	}
  	case RTC_EPOCH_SET:	/* Set the epoch.	*/
  	{
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
677
  		/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  		 * 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...
692
693
  	return copy_to_user((void __user *)arg,
  			    &wtime, sizeof wtime) ? -EFAULT : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  }
53f1b1433   Alan Cox   rtc: push the BKL...
695
  static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  {
53f1b1433   Alan Cox   rtc: push the BKL...
697
  	long ret;
53f1b1433   Alan Cox   rtc: push the BKL...
698
  	ret = rtc_do_ioctl(cmd, arg, 0);
53f1b1433   Alan Cox   rtc: push the BKL...
699
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
706
  }
  
  /*
   *	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
707
708
  static int rtc_open(struct inode *inode, struct file *file)
  {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
709
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
711
  	if (rtc_status & RTC_IS_OPEN)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
715
716
  		goto out_busy;
  
  	rtc_status |= RTC_IS_OPEN;
  
  	rtc_irq_data = 0;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
717
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
  	return 0;
  
  out_busy:
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
721
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  	return -EBUSY;
  }
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
724
  static int rtc_fasync(int fd, struct file *filp, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
  {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
726
  	return fasync_helper(fd, filp, on, &rtc_async_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
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
  }
  
  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
756
757
  no_irq:
  #endif
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
758
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
  	rtc_irq_data = 0;
  	rtc_status &= ~RTC_IS_OPEN;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
761
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
765
  	return 0;
  }
  
  #ifdef RTC_IRQ
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
771
772
773
  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...
774
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  	l = rtc_irq_data;
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
776
  	spin_unlock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
781
782
  
  	if (l != 0)
  		return POLLIN | POLLRDNORM;
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  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...
808
  EXPORT_SYMBOL(rtc_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
  
  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...
825

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

cdee99d74   David S. Miller   [SPARC64]: Stop u...
938
  #ifdef CONFIG_SPARC32
75081322c   David S. Miller   sparc32: Convert ...
939
940
941
942
943
944
945
946
947
948
  	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
949
950
951
  			}
  		}
  	}
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
952
  	rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
955
956
957
  	printk(KERN_ERR "rtc_init: no PC rtc found
  ");
  	return -EIO;
  
  found:
75081322c   David S. Miller   sparc32: Convert ...
958
  	if (!rtc_irq) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
962
963
964
  		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...
965
  	 * PCI Slot 2 INTA# (and some INTx# in Slot 1).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
  	 */
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
967
968
  	if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc",
  			(void *)&rtc_port)) {
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
969
  		rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
971
972
973
974
975
  		printk(KERN_ERR "rtc: cannot register IRQ %d
  ", rtc_irq);
  		return -EIO;
  	}
  no_irq:
  #else
9626f1f11   Bjorn Helgaas   rtc: fall back to...
976
977
978
979
980
981
982
983
984
985
986
  	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:...
987
  	if (!r) {
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
988
989
990
  #ifdef RTC_IRQ
  		rtc_has_irq = 0;
  #endif
38e0e8c05   Maciej W. Rozycki   [PATCH] char/rtc:...
991
992
993
  		printk(KERN_ERR "rtc: I/O resource %lx is not free.
  ",
  		       (long)(RTC_PORT(0)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
997
998
  		return -EIO;
  	}
  
  #ifdef RTC_IRQ
  	if (is_hpet_enabled()) {
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
999
  		int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  		rtc_int_handler_ptr = hpet_rtc_interrupt;
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1001
1002
1003
1004
1005
1006
  		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
1007
1008
1009
  	} else {
  		rtc_int_handler_ptr = rtc_interrupt;
  	}
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1010
1011
  	if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED,
  			"rtc", NULL)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
  		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
f3e92d355   Jan Beulich   [PATCH] rtc: fx e...
1013
  		rtc_has_irq = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
  		printk(KERN_ERR "rtc: IRQ %d is not free.
  ", RTC_IRQ);
4c06be10c   Bjorn Helgaas   rtc: release corr...
1016
  		rtc_release_region();
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1017

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
  	/* 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...
1046

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
1051
1052
1053
  	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...
1054

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  	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...
1078
1079
1080
  		printk(KERN_INFO "rtc: %s epoch (%lu) detected
  ",
  			guess, epoch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
1083
1084
  #endif
  #ifdef RTC_IRQ
  	if (rtc_has_irq == 0)
  		goto no_irq2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
1086
1087
  	spin_lock_irq(&rtc_lock);
  	rtc_freq = 1024;
  	if (!hpet_set_periodic_freq(rtc_freq)) {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1088
1089
1090
1091
1092
1093
  		/*
  		 * 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
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  	}
  	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...
1106
  static void __exit rtc_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
  {
  	cleanup_sysctl();
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1109
  	remove_proc_entry("driver/rtc", NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  	misc_deregister(&rtc_dev);
cdee99d74   David S. Miller   [SPARC64]: Stop u...
1111
  #ifdef CONFIG_SPARC32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  	if (rtc_has_irq)
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1113
  		free_irq(rtc_irq, &rtc_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114
  #else
4c06be10c   Bjorn Helgaas   rtc: release corr...
1115
  	rtc_release_region();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1116
  #ifdef RTC_IRQ
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1117
  	if (rtc_has_irq) {
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1118
  		free_irq(RTC_IRQ, NULL);
f8f76481b   Bernhard Walle   rtc: use the IRQ ...
1119
1120
  		hpet_unregister_irq_handler(hpet_rtc_interrupt);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  #endif
cdee99d74   David S. Miller   [SPARC64]: Stop u...
1122
  #endif /* CONFIG_SPARC32 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
1125
1126
1127
1128
1129
  }
  
  module_init(rtc_init);
  module_exit(rtc_exit);
  
  #ifdef RTC_IRQ
  /*
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1130
   *	At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
1133
1134
1135
1136
   *	(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...
1137
   *	(You *really* shouldn't be trying to use a non-realtime system
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
   *	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...
1144
  	spin_lock_irq(&rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
  
  	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);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1162
1163
1164
1165
1166
  	if (printk_ratelimit()) {
  		printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.
  ",
  			freq);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
1169
  
  	/* Now we have new data */
  	wake_up_interruptible(&rtc_wait);
5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1170
  	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
1172
  }
  #endif
9cef779ec   Jan Beulich   [PATCH] RTC drive...
1173
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
1271
  /*
   *	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...
1272
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273

9580d85f9   Adrian Bunk   drivers/char/rtc....
1274
  static void rtc_get_rtc_time(struct rtc_time *rtc_tm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
  {
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1276
  	unsigned long uip_watchdog = jiffies, flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
1280
1281
1282
1283
  	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...
1284
  	 * can take just over 2ms. We wait 20ms. There is no need to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
  	 * 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...
1287
  	 * periodic update complete interrupts, (via ioctl) and then
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
1290
  	 * 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....
1291
1292
  	while (rtc_is_updating() != 0 &&
  	       time_before(jiffies, uip_watchdog + 2*HZ/100))
403fe5ae5   Petr Vandrovec   [PATCH] rtc: msle...
1293
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
  
  	/*
  	 * Only the values that we read from the RTC are set. We leave
b7599587f   Alan Cox   [PATCH] Allow rea...
1297
1298
1299
  	 * 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
1300
  	 */
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1301
  	spin_lock_irqsave(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
1303
1304
1305
1306
1307
  	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...
1308
1309
  	/* 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
1310
1311
1312
1313
  #ifdef CONFIG_MACH_DECSTATION
  	real_year = CMOS_READ(RTC_DEC_YEAR);
  #endif
  	ctrl = CMOS_READ(RTC_CONTROL);
0f7496462   Ingo Molnar   [PATCH] lockdep: ...
1314
  	spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315

5fd1fe9c5   Ingo Molnar   x86: clean up dri...
1316
  	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
1317
1318
1319
1320
1321
1322
1323
  		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
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
  	}
  
  #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...
1334
1335
  	rtc_tm->tm_year += epoch - 1900;
  	if (rtc_tm->tm_year <= 69)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  		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...
1355
  	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
1356
1357
1358
  		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
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
  	}
  }
  
  #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...
1372
  static void mask_rtc_irq_bit_locked(unsigned char bit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
1374
  {
  	unsigned char val;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1375
  	if (hpet_mask_rtc_irq_bit(bit))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
1379
1380
1381
1382
  	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
1383
  }
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1384
  static void set_rtc_irq_bit_locked(unsigned char bit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
  {
  	unsigned char val;
c3348760a   Takashi Iwai   [PATCH] Fix wrong...
1387
  	if (hpet_set_rtc_irq_bit(bit))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
1391
1392
1393
1394
  	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
1395
1396
1397
1398
1399
1400
  }
  #endif
  
  MODULE_AUTHOR("Paul Gortmaker");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(RTC_MINOR);