Blame view

drivers/char/nvram.c 17.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /*
   * CMOS/NV-RAM driver for Linux
   *
   * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
   * idea by and with help from Richard Jelinek <rj@suse.de>
   * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
   *
   * This driver allows you to access the contents of the non-volatile memory in
   * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
   * many Atari machines. In the former it's called "CMOS-RAM", in the latter
   * "NVRAM" (NV stands for non-volatile).
   *
   * The data are supplied as a (seekable) character device, /dev/nvram. The
   * size of this file is dependent on the controller.  The usual size is 114,
   * the number of freely available bytes in the memory (i.e., not used by the
   * RTC itself).
   *
   * Checksums over the NVRAM contents are managed by this driver. In case of a
   * bad checksum, reads and writes return -EIO. The checksum can be initialized
   * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
   * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
   * again; use with care!)
   *
   * This file also provides some functions for other parts of the kernel that
   * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
   * Obviously this can be used only if this driver is always configured into
   * the kernel and is not a module. Since the functions are used by some Atari
   * drivers, this is the case on the Atari.
   *
   *
   * 	1.1	Cesar Barros: SMP locking fixes
   * 		added changelog
   * 	1.2	Erik Gilling: Cobalt Networks support
   * 		Tim Hockin: general cleanup, Cobalt support
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
35
   * 	1.3	Wim Van Sebroeck: convert PRINT_PROC to seq_file
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
   */
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
37
  #define NVRAM_VERSION	"1.3"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
  
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
  #include <linux/nvram.h>
  
  #define PC		1
  #define ATARI		2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
  
  /* select machine configuration */
  #if defined(CONFIG_ATARI)
  #  define MACH ATARI
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
48
  #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and ?? */
ea5a3dcfd   Robert P. J. Day   COBALT: remove al...
49
  #  define MACH PC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  #else
  #  error Cannot build nvram driver for this machine configuration.
  #endif
  
  #if MACH == PC
  
  /* RTC in a PC */
  #define CHECK_DRIVER_INIT()	1
  
  /* On PCs, the checksum is built only over bytes 2..31 */
  #define PC_CKS_RANGE_START	2
  #define PC_CKS_RANGE_END	31
  #define PC_CKS_LOC		32
  #define NVRAM_BYTES		(128-NVRAM_FIRST_BYTE)
  
  #define mach_check_checksum	pc_check_checksum
  #define mach_set_checksum	pc_set_checksum
  #define mach_proc_infos		pc_proc_infos
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  #if MACH == ATARI
  
  /* Special parameters for RTC in Atari machines */
  #include <asm/atarihw.h>
  #include <asm/atariints.h>
  #define RTC_PORT(x)		(TT_RTC_BAS + 2*(x))
  #define CHECK_DRIVER_INIT()	(MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
  
  #define NVRAM_BYTES		50
  
  /* On Ataris, the checksum is over all bytes except the checksum bytes
   * themselves; these are at the very end */
  #define ATARI_CKS_RANGE_START	0
  #define ATARI_CKS_RANGE_END	47
  #define ATARI_CKS_LOC		48
  
  #define mach_check_checksum	atari_check_checksum
  #define mach_set_checksum	atari_set_checksum
  #define mach_proc_infos		atari_proc_infos
  
  #endif
  
  /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
   * rtc_lock held. Due to the index-port/data-port 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.)
   */
  
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/miscdevice.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
  #include <linux/ioport.h>
  #include <linux/fcntl.h>
  #include <linux/mc146818rtc.h>
  #include <linux/init.h>
  #include <linux/proc_fs.h>
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
106
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  #include <linux/spinlock.h>
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
108
109
  #include <linux/io.h>
  #include <linux/uaccess.h>
613655fa3   Arnd Bergmann   drivers: autoconv...
110
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  #include <asm/system.h>
613655fa3   Arnd Bergmann   drivers: autoconv...
113
  static DEFINE_MUTEX(nvram_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
123
  static DEFINE_SPINLOCK(nvram_state_lock);
  static int nvram_open_cnt;	/* #times opened */
  static int nvram_open_mode;	/* special open modes */
  #define NVRAM_WRITE		1 /* opened for writing (exclusive) */
  #define NVRAM_EXCL		2 /* opened with O_EXCL */
  
  static int mach_check_checksum(void);
  static void mach_set_checksum(void);
  
  #ifdef CONFIG_PROC_FS
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
124
125
  static void mach_proc_infos(unsigned char *contents, struct seq_file *seq,
  								void *offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
132
133
134
  #endif
  
  /*
   * These functions are provided to be called internally or by other parts of
   * the kernel. It's up to the caller to ensure correct checksum before reading
   * or after writing (needs to be done only once).
   *
   * It is worth noting that these functions all access bytes of general
   * purpose memory in the NVRAM - that is to say, they all add the
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
135
   * NVRAM_FIRST_BYTE offset.  Pass them offsets into NVRAM as if you did not
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
   * know about the RTC cruft.
   */
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
138
  unsigned char __nvram_read_byte(int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
  {
  	return CMOS_READ(NVRAM_FIRST_BYTE + i);
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
142
  EXPORT_SYMBOL(__nvram_read_byte);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143

971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
144
  unsigned char nvram_read_byte(int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
152
153
  {
  	unsigned long flags;
  	unsigned char c;
  
  	spin_lock_irqsave(&rtc_lock, flags);
  	c = __nvram_read_byte(i);
  	spin_unlock_irqrestore(&rtc_lock, flags);
  	return c;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
154
  EXPORT_SYMBOL(nvram_read_byte);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
  
  /* This races nicely with trying to read with checksum checking (nvram_read) */
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
157
  void __nvram_write_byte(unsigned char c, int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
  {
  	CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
161
  EXPORT_SYMBOL(__nvram_write_byte);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
163
  void nvram_write_byte(unsigned char c, int i)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
168
169
170
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&rtc_lock, flags);
  	__nvram_write_byte(c, i);
  	spin_unlock_irqrestore(&rtc_lock, flags);
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
171
  EXPORT_SYMBOL(nvram_write_byte);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172

971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
173
  int __nvram_check_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
  {
  	return mach_check_checksum();
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
177
  EXPORT_SYMBOL(__nvram_check_checksum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178

971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
179
  int nvram_check_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
  {
  	unsigned long flags;
  	int rv;
  
  	spin_lock_irqsave(&rtc_lock, flags);
  	rv = __nvram_check_checksum();
  	spin_unlock_irqrestore(&rtc_lock, flags);
  	return rv;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
189
  EXPORT_SYMBOL(nvram_check_checksum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190

971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
191
  static void __nvram_set_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
  {
  	mach_set_checksum();
  }
681ea4b93   Adrian Bunk   [PATCH] drivers/c...
195
  #if 0
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
196
  void nvram_set_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
202
203
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&rtc_lock, flags);
  	__nvram_set_checksum();
  	spin_unlock_irqrestore(&rtc_lock, flags);
  }
681ea4b93   Adrian Bunk   [PATCH] drivers/c...
204
  #endif  /*  0  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
  
  /*
   * The are the file operation function for user access to /dev/nvram
   */
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
209
  static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
217
218
219
220
  	switch (origin) {
  	case 0:
  		/* nothing to do */
  		break;
  	case 1:
  		offset += file->f_pos;
  		break;
  	case 2:
  		offset += NVRAM_BYTES;
  		break;
22735068d   Josef Bacik   drivers: fix up v...
221
222
  	default:
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	}
9e8ab74dd   Frederic Weisbecker   nvram: Drop the b...
224

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  	return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
227
228
  static ssize_t nvram_read(struct file *file, char __user *buf,
  						size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  {
  	unsigned char contents[NVRAM_BYTES];
  	unsigned i = *ppos;
  	unsigned char *tmp;
  
  	spin_lock_irq(&rtc_lock);
  
  	if (!__nvram_check_checksum())
  		goto checksum_err;
  
  	for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp)
  		*tmp = __nvram_read_byte(i);
  
  	spin_unlock_irq(&rtc_lock);
  
  	if (copy_to_user(buf, contents, tmp - contents))
  		return -EFAULT;
  
  	*ppos = i;
  
  	return tmp - contents;
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
250
  checksum_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
  	spin_unlock_irq(&rtc_lock);
  	return -EIO;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
254
255
  static ssize_t nvram_write(struct file *file, const char __user *buf,
  						size_t count, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  {
  	unsigned char contents[NVRAM_BYTES];
  	unsigned i = *ppos;
  	unsigned char *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

a01c78004   H. Peter Anvin   nvram: Fix write ...
261
262
263
264
265
266
267
268
269
  	if (i >= NVRAM_BYTES)
  		return 0;	/* Past EOF */
  
  	if (count > NVRAM_BYTES - i)
  		count = NVRAM_BYTES - i;
  	if (count > NVRAM_BYTES)
  		return -EFAULT;	/* Can't happen, but prove it to gcc */
  
  	if (copy_from_user(contents, buf, count))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
  		return -EFAULT;
  
  	spin_lock_irq(&rtc_lock);
  
  	if (!__nvram_check_checksum())
  		goto checksum_err;
a01c78004   H. Peter Anvin   nvram: Fix write ...
276
  	for (tmp = contents; count--; ++i, ++tmp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
281
282
283
284
285
  		__nvram_write_byte(*tmp, i);
  
  	__nvram_set_checksum();
  
  	spin_unlock_irq(&rtc_lock);
  
  	*ppos = i;
  
  	return tmp - contents;
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
286
  checksum_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
  	spin_unlock_irq(&rtc_lock);
  	return -EIO;
  }
55929332c   Arnd Bergmann   drivers: Push dow...
290
291
  static long nvram_ioctl(struct file *file, unsigned int cmd,
  			unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
  {
  	int i;
  
  	switch (cmd) {
  
  	case NVRAM_INIT:
  		/* initialize NVRAM contents and checksum */
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
613655fa3   Arnd Bergmann   drivers: autoconv...
301
  		mutex_lock(&nvram_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
  		spin_lock_irq(&rtc_lock);
  
  		for (i = 0; i < NVRAM_BYTES; ++i)
  			__nvram_write_byte(0, i);
  		__nvram_set_checksum();
  
  		spin_unlock_irq(&rtc_lock);
613655fa3   Arnd Bergmann   drivers: autoconv...
309
  		mutex_unlock(&nvram_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
  		return 0;
  
  	case NVRAM_SETCKS:
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
313
  		/* just set checksum, contents unchanged (maybe useful after
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
  		 * checksum garbaged somehow...) */
  		if (!capable(CAP_SYS_ADMIN))
  			return -EACCES;
613655fa3   Arnd Bergmann   drivers: autoconv...
317
  		mutex_lock(&nvram_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  		spin_lock_irq(&rtc_lock);
  		__nvram_set_checksum();
  		spin_unlock_irq(&rtc_lock);
613655fa3   Arnd Bergmann   drivers: autoconv...
321
  		mutex_unlock(&nvram_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
  		return 0;
  
  	default:
  		return -ENOTTY;
  	}
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
328
  static int nvram_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
  {
  	spin_lock(&nvram_state_lock);
  
  	if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
  	    (nvram_open_mode & NVRAM_EXCL) ||
aeb5d7270   Al Viro   [PATCH] introduce...
334
  	    ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
339
340
  		spin_unlock(&nvram_state_lock);
  		return -EBUSY;
  	}
  
  	if (file->f_flags & O_EXCL)
  		nvram_open_mode |= NVRAM_EXCL;
aeb5d7270   Al Viro   [PATCH] introduce...
341
  	if (file->f_mode & FMODE_WRITE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
  		nvram_open_mode |= NVRAM_WRITE;
  	nvram_open_cnt++;
  
  	spin_unlock(&nvram_state_lock);
  
  	return 0;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
349
  static int nvram_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
  {
  	spin_lock(&nvram_state_lock);
  
  	nvram_open_cnt--;
  
  	/* if only one instance is open, clear the EXCL bit */
  	if (nvram_open_mode & NVRAM_EXCL)
  		nvram_open_mode &= ~NVRAM_EXCL;
aeb5d7270   Al Viro   [PATCH] introduce...
358
  	if (file->f_mode & FMODE_WRITE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
363
364
365
366
  		nvram_open_mode &= ~NVRAM_WRITE;
  
  	spin_unlock(&nvram_state_lock);
  
  	return 0;
  }
  
  #ifndef CONFIG_PROC_FS
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
367
  static int nvram_add_proc_fs(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
  {
  	return 0;
  }
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
371

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  #else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
373
  static int nvram_proc_read(struct seq_file *seq, void *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
  {
  	unsigned char contents[NVRAM_BYTES];
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
376
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
  
  	spin_lock_irq(&rtc_lock);
  	for (i = 0; i < NVRAM_BYTES; ++i)
  		contents[i] = __nvram_read_byte(i);
  	spin_unlock_irq(&rtc_lock);
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
382
  	mach_proc_infos(contents, seq, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
384
385
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
387
388
389
  static int nvram_proc_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, nvram_proc_read, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  }
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  static const struct file_operations nvram_proc_fops = {
  	.owner		= THIS_MODULE,
  	.open		= nvram_proc_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
  
  static int nvram_add_proc_fs(void)
  {
  	if (!proc_create("driver/nvram", 0, NULL, &nvram_proc_fops))
  		return -ENOMEM;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  
  #endif /* CONFIG_PROC_FS */
62322d255   Arjan van de Ven   [PATCH] make more...
407
  static const struct file_operations nvram_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
  	.owner		= THIS_MODULE,
  	.llseek		= nvram_llseek,
  	.read		= nvram_read,
  	.write		= nvram_write,
55929332c   Arnd Bergmann   drivers: Push dow...
412
  	.unlocked_ioctl	= nvram_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
421
  	.open		= nvram_open,
  	.release	= nvram_release,
  };
  
  static struct miscdevice nvram_dev = {
  	NVRAM_MINOR,
  	"nvram",
  	&nvram_fops
  };
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
422
  static int __init nvram_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
  {
  	int ret;
  
  	/* First test whether the driver should init at all */
  	if (!CHECK_DRIVER_INIT())
e945b568e   Geert Uytterhoeven   m68k: Return -ENO...
428
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
436
  
  	ret = misc_register(&nvram_dev);
  	if (ret) {
  		printk(KERN_ERR "nvram: can't misc_register on minor=%d
  ",
  		    NVRAM_MINOR);
  		goto out;
  	}
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
437
438
  	ret = nvram_add_proc_fs();
  	if (ret) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  		printk(KERN_ERR "nvram: can't create /proc/driver/nvram
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
  		goto outmisc;
  	}
  	ret = 0;
  	printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "
  ");
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
446
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  	return ret;
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
448
  outmisc:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
  	misc_deregister(&nvram_dev);
  	goto out;
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
452
  static void __exit nvram_cleanup_module(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
458
459
460
461
462
463
464
465
  {
  	remove_proc_entry("driver/nvram", NULL);
  	misc_deregister(&nvram_dev);
  }
  
  module_init(nvram_init);
  module_exit(nvram_cleanup_module);
  
  /*
   * Machine specific functions
   */
  
  #if MACH == PC
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
466
  static int pc_check_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
472
473
474
475
  {
  	int i;
  	unsigned short sum = 0;
  	unsigned short expect;
  
  	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
  		sum += __nvram_read_byte(i);
  	expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
  	    __nvram_read_byte(PC_CKS_LOC+1);
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
476
  	return (sum & 0xffff) == expect;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
478
  static void pc_set_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  {
  	int i;
  	unsigned short sum = 0;
  
  	for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
  		sum += __nvram_read_byte(i);
  	__nvram_write_byte(sum >> 8, PC_CKS_LOC);
  	__nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
  }
  
  #ifdef CONFIG_PROC_FS
  
  static char *floppy_types[] = {
  	"none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M",
  	"3.5'' 2.88M", "3.5'' 2.88M"
  };
  
  static char *gfx_types[] = {
  	"EGA, VGA, ... (with BIOS)",
  	"CGA (40 cols)",
  	"CGA (80 cols)",
  	"monochrome",
  };
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
502
503
  static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq,
  								void *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
509
510
  {
  	int checksum;
  	int type;
  
  	spin_lock_irq(&rtc_lock);
  	checksum = __nvram_check_checksum();
  	spin_unlock_irq(&rtc_lock);
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
511
512
  	seq_printf(seq, "Checksum status: %svalid
  ", checksum ? "" : "not ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
514
515
  	seq_printf(seq, "# floppies     : %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
  	    (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
517
  	seq_printf(seq, "Floppy 0 type  : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
  	type = nvram[2] >> 4;
fe971071a   Tobias Klauser   [PATCH] drivers/c...
519
  	if (type < ARRAY_SIZE(floppy_types))
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
520
521
  		seq_printf(seq, "%s
  ", floppy_types[type]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
523
524
525
  		seq_printf(seq, "%d (unknown)
  ", type);
  	seq_printf(seq, "Floppy 1 type  : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	type = nvram[2] & 0x0f;
fe971071a   Tobias Klauser   [PATCH] drivers/c...
527
  	if (type < ARRAY_SIZE(floppy_types))
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
528
529
  		seq_printf(seq, "%s
  ", floppy_types[type]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
531
532
  		seq_printf(seq, "%d (unknown)
  ", type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
534
  	seq_printf(seq, "HD 0 type      : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
  	type = nvram[4] >> 4;
  	if (type)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
537
538
  		seq_printf(seq, "%02x
  ", type == 0x0f ? nvram[11] : type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
540
541
  		seq_printf(seq, "none
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
543
  	seq_printf(seq, "HD 1 type      : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  	type = nvram[4] & 0x0f;
  	if (type)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
546
547
  		seq_printf(seq, "%02x
  ", type == 0x0f ? nvram[12] : type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
549
550
  		seq_printf(seq, "none
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
552
553
  	seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
555
556
  	    nvram[18] | (nvram[19] << 8),
  	    nvram[20], nvram[25],
  	    nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8));
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
557
558
  	seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
  	    nvram[39] | (nvram[40] << 8),
  	    nvram[41], nvram[46],
  	    nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8));
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
562
563
564
565
  	seq_printf(seq, "DOS base memory: %d kB
  ", nvram[7] | (nvram[8] << 8));
  	seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  	    nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8));
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
567
568
569
  	seq_printf(seq, "Gfx adapter    : %s
  ",
  	    gfx_types[(nvram[6] >> 4) & 3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
571
572
  	seq_printf(seq, "FPU            : %sinstalled
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	    (nvram[6] & 2) ? "" : "not ");
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
574
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
  }
  #endif
  
  #endif /* MACH == PC */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
  #if MACH == ATARI
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
580
  static int atari_check_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
582
583
584
585
586
  {
  	int i;
  	unsigned char sum = 0;
  
  	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
  		sum += __nvram_read_byte(i);
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
587
588
  	return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) &&
  	    (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  }
971ddcf8a   Wim Van Sebroeck   [PATCH] nvram - C...
590
  static void atari_set_checksum(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
599
600
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
633
634
635
636
637
638
639
  {
  	int i;
  	unsigned char sum = 0;
  
  	for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i)
  		sum += __nvram_read_byte(i);
  	__nvram_write_byte(~sum, ATARI_CKS_LOC);
  	__nvram_write_byte(sum, ATARI_CKS_LOC + 1);
  }
  
  #ifdef CONFIG_PROC_FS
  
  static struct {
  	unsigned char val;
  	char *name;
  } boot_prefs[] = {
  	{ 0x80, "TOS" },
  	{ 0x40, "ASV" },
  	{ 0x20, "NetBSD (?)" },
  	{ 0x10, "Linux" },
  	{ 0x00, "unspecified" }
  };
  
  static char *languages[] = {
  	"English (US)",
  	"German",
  	"French",
  	"English (UK)",
  	"Spanish",
  	"Italian",
  	"6 (undefined)",
  	"Swiss (French)",
  	"Swiss (German)"
  };
  
  static char *dateformat[] = {
  	"MM%cDD%cYY",
  	"DD%cMM%cYY",
  	"YY%cMM%cDD",
  	"YY%cDD%cMM",
  	"4 (undefined)",
  	"5 (undefined)",
  	"6 (undefined)",
  	"7 (undefined)"
  };
  
  static char *colors[] = {
  	"2", "4", "16", "256", "65536", "??", "??", "??"
  };
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
640
641
  static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq,
  								void *offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
  {
  	int checksum = nvram_check_checksum();
  	int i;
  	unsigned vmode;
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
646
647
  	seq_printf(seq, "Checksum status  : %svalid
  ", checksum ? "" : "not ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
649
  	seq_printf(seq, "Boot preference  : ");
fe971071a   Tobias Klauser   [PATCH] drivers/c...
650
  	for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
  		if (nvram[1] == boot_prefs[i].val) {
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
652
653
  			seq_printf(seq, "%s
  ", boot_prefs[i].name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
  			break;
  		}
  	}
  	if (i < 0)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
658
659
  		seq_printf(seq, "0x%02x (undefined)
  ", nvram[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
661
662
  	seq_printf(seq, "SCSI arbitration : %s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  	    (nvram[16] & 0x80) ? "on" : "off");
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
664
  	seq_printf(seq, "SCSI host ID     : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  	if (nvram[16] & 0x80)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
666
667
  		seq_printf(seq, "%d
  ", nvram[16] & 7);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
669
670
  		seq_printf(seq, "n/a
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
672
673
  
  	/* the following entries are defined only for the Falcon */
  	if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
674
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675

8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
676
  	seq_printf(seq, "OS language      : ");
fe971071a   Tobias Klauser   [PATCH] drivers/c...
677
  	if (nvram[6] < ARRAY_SIZE(languages))
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
678
679
  		seq_printf(seq, "%s
  ", languages[nvram[6]]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
681
682
683
  		seq_printf(seq, "%u (undefined)
  ", nvram[6]);
  	seq_printf(seq, "Keyboard language: ");
fe971071a   Tobias Klauser   [PATCH] drivers/c...
684
  	if (nvram[7] < ARRAY_SIZE(languages))
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
685
686
  		seq_printf(seq, "%s
  ", languages[nvram[7]]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
688
689
690
691
  		seq_printf(seq, "%u (undefined)
  ", nvram[7]);
  	seq_printf(seq, "Date format      : ");
  	seq_printf(seq, dateformat[nvram[8] & 7],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  	    nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/');
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
693
694
695
  	seq_printf(seq, ", %dh clock
  ", nvram[8] & 16 ? 24 : 12);
  	seq_printf(seq, "Boot delay       : ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  	if (nvram[10] == 0)
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
697
  		seq_printf(seq, "default");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  	else
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
699
700
  		seq_printf(seq, "%ds%s
  ", nvram[10],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
  		    nvram[10] < 8 ? ", no memory test" : "");
  
  	vmode = (nvram[14] << 8) || nvram[15];
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
704
705
706
  	seq_printf(seq,
  	    "Video mode       : %s colors, %d columns, %s %s monitor
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
  	    colors[vmode & 7],
  	    vmode & 8 ? 80 : 40,
  	    vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC");
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
710
711
  	seq_printf(seq, "                   %soverscan, compat. mode %s%s
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
715
  	    vmode & 64 ? "" : "no ",
  	    vmode & 128 ? "on" : "off",
  	    vmode & 256 ?
  	    (vmode & 16 ? ", line doubling" : ", half screen") : "");
8587b33f4   Wim Van Sebroeck   [PATCH] nvram - c...
716
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
721
722
  }
  #endif
  
  #endif /* MACH == ATARI */
  
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  MODULE_ALIAS_MISCDEV(NVRAM_MINOR);