Root/
1 | /* |
2 | * CMOS/NV-RAM driver for Linux |
3 | * |
4 | * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> |
5 | * idea by and with help from Richard Jelinek <rj@suse.de> |
6 | * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) |
7 | * |
8 | * This driver allows you to access the contents of the non-volatile memory in |
9 | * the mc146818rtc.h real-time clock. This chip is built into all PCs and into |
10 | * many Atari machines. In the former it's called "CMOS-RAM", in the latter |
11 | * "NVRAM" (NV stands for non-volatile). |
12 | * |
13 | * The data are supplied as a (seekable) character device, /dev/nvram. The |
14 | * size of this file is dependent on the controller. The usual size is 114, |
15 | * the number of freely available bytes in the memory (i.e., not used by the |
16 | * RTC itself). |
17 | * |
18 | * Checksums over the NVRAM contents are managed by this driver. In case of a |
19 | * bad checksum, reads and writes return -EIO. The checksum can be initialized |
20 | * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or |
21 | * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid |
22 | * again; use with care!) |
23 | * |
24 | * This file also provides some functions for other parts of the kernel that |
25 | * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}. |
26 | * Obviously this can be used only if this driver is always configured into |
27 | * the kernel and is not a module. Since the functions are used by some Atari |
28 | * drivers, this is the case on the Atari. |
29 | * |
30 | * |
31 | * 1.1 Cesar Barros: SMP locking fixes |
32 | * added changelog |
33 | * 1.2 Erik Gilling: Cobalt Networks support |
34 | * Tim Hockin: general cleanup, Cobalt support |
35 | * 1.3 Wim Van Sebroeck: convert PRINT_PROC to seq_file |
36 | */ |
37 | |
38 | #define NVRAM_VERSION "1.3" |
39 | |
40 | #include <linux/module.h> |
41 | #include <linux/nvram.h> |
42 | |
43 | #define PC 1 |
44 | #define ATARI 2 |
45 | |
46 | /* select machine configuration */ |
47 | #if defined(CONFIG_ATARI) |
48 | # define MACH ATARI |
49 | #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and ?? */ |
50 | # define MACH PC |
51 | #else |
52 | # error Cannot build nvram driver for this machine configuration. |
53 | #endif |
54 | |
55 | #if MACH == PC |
56 | |
57 | /* RTC in a PC */ |
58 | #define CHECK_DRIVER_INIT() 1 |
59 | |
60 | /* On PCs, the checksum is built only over bytes 2..31 */ |
61 | #define PC_CKS_RANGE_START 2 |
62 | #define PC_CKS_RANGE_END 31 |
63 | #define PC_CKS_LOC 32 |
64 | #define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) |
65 | |
66 | #define mach_check_checksum pc_check_checksum |
67 | #define mach_set_checksum pc_set_checksum |
68 | #define mach_proc_infos pc_proc_infos |
69 | |
70 | #endif |
71 | |
72 | #if MACH == ATARI |
73 | |
74 | /* Special parameters for RTC in Atari machines */ |
75 | #include <asm/atarihw.h> |
76 | #include <asm/atariints.h> |
77 | #define RTC_PORT(x) (TT_RTC_BAS + 2*(x)) |
78 | #define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) |
79 | |
80 | #define NVRAM_BYTES 50 |
81 | |
82 | /* On Ataris, the checksum is over all bytes except the checksum bytes |
83 | * themselves; these are at the very end */ |
84 | #define ATARI_CKS_RANGE_START 0 |
85 | #define ATARI_CKS_RANGE_END 47 |
86 | #define ATARI_CKS_LOC 48 |
87 | |
88 | #define mach_check_checksum atari_check_checksum |
89 | #define mach_set_checksum atari_set_checksum |
90 | #define mach_proc_infos atari_proc_infos |
91 | |
92 | #endif |
93 | |
94 | /* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with |
95 | * rtc_lock held. Due to the index-port/data-port design of the RTC, we |
96 | * don't want two different things trying to get to it at once. (e.g. the |
97 | * periodic 11 min sync from kernel/time/ntp.c vs. this driver.) |
98 | */ |
99 | |
100 | #include <linux/types.h> |
101 | #include <linux/errno.h> |
102 | #include <linux/miscdevice.h> |
103 | #include <linux/ioport.h> |
104 | #include <linux/fcntl.h> |
105 | #include <linux/mc146818rtc.h> |
106 | #include <linux/init.h> |
107 | #include <linux/proc_fs.h> |
108 | #include <linux/seq_file.h> |
109 | #include <linux/spinlock.h> |
110 | #include <linux/io.h> |
111 | #include <linux/uaccess.h> |
112 | #include <linux/mutex.h> |
113 | |
114 | |
115 | static DEFINE_MUTEX(nvram_mutex); |
116 | static DEFINE_SPINLOCK(nvram_state_lock); |
117 | static int nvram_open_cnt; /* #times opened */ |
118 | static int nvram_open_mode; /* special open modes */ |
119 | #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ |
120 | #define NVRAM_EXCL 2 /* opened with O_EXCL */ |
121 | |
122 | static int mach_check_checksum(void); |
123 | static void mach_set_checksum(void); |
124 | |
125 | #ifdef CONFIG_PROC_FS |
126 | static void mach_proc_infos(unsigned char *contents, struct seq_file *seq, |
127 | void *offset); |
128 | #endif |
129 | |
130 | /* |
131 | * These functions are provided to be called internally or by other parts of |
132 | * the kernel. It's up to the caller to ensure correct checksum before reading |
133 | * or after writing (needs to be done only once). |
134 | * |
135 | * It is worth noting that these functions all access bytes of general |
136 | * purpose memory in the NVRAM - that is to say, they all add the |
137 | * NVRAM_FIRST_BYTE offset. Pass them offsets into NVRAM as if you did not |
138 | * know about the RTC cruft. |
139 | */ |
140 | |
141 | unsigned char __nvram_read_byte(int i) |
142 | { |
143 | return CMOS_READ(NVRAM_FIRST_BYTE + i); |
144 | } |
145 | EXPORT_SYMBOL(__nvram_read_byte); |
146 | |
147 | unsigned char nvram_read_byte(int i) |
148 | { |
149 | unsigned long flags; |
150 | unsigned char c; |
151 | |
152 | spin_lock_irqsave(&rtc_lock, flags); |
153 | c = __nvram_read_byte(i); |
154 | spin_unlock_irqrestore(&rtc_lock, flags); |
155 | return c; |
156 | } |
157 | EXPORT_SYMBOL(nvram_read_byte); |
158 | |
159 | /* This races nicely with trying to read with checksum checking (nvram_read) */ |
160 | void __nvram_write_byte(unsigned char c, int i) |
161 | { |
162 | CMOS_WRITE(c, NVRAM_FIRST_BYTE + i); |
163 | } |
164 | EXPORT_SYMBOL(__nvram_write_byte); |
165 | |
166 | void nvram_write_byte(unsigned char c, int i) |
167 | { |
168 | unsigned long flags; |
169 | |
170 | spin_lock_irqsave(&rtc_lock, flags); |
171 | __nvram_write_byte(c, i); |
172 | spin_unlock_irqrestore(&rtc_lock, flags); |
173 | } |
174 | EXPORT_SYMBOL(nvram_write_byte); |
175 | |
176 | int __nvram_check_checksum(void) |
177 | { |
178 | return mach_check_checksum(); |
179 | } |
180 | EXPORT_SYMBOL(__nvram_check_checksum); |
181 | |
182 | int nvram_check_checksum(void) |
183 | { |
184 | unsigned long flags; |
185 | int rv; |
186 | |
187 | spin_lock_irqsave(&rtc_lock, flags); |
188 | rv = __nvram_check_checksum(); |
189 | spin_unlock_irqrestore(&rtc_lock, flags); |
190 | return rv; |
191 | } |
192 | EXPORT_SYMBOL(nvram_check_checksum); |
193 | |
194 | static void __nvram_set_checksum(void) |
195 | { |
196 | mach_set_checksum(); |
197 | } |
198 | |
199 | #if 0 |
200 | void nvram_set_checksum(void) |
201 | { |
202 | unsigned long flags; |
203 | |
204 | spin_lock_irqsave(&rtc_lock, flags); |
205 | __nvram_set_checksum(); |
206 | spin_unlock_irqrestore(&rtc_lock, flags); |
207 | } |
208 | #endif /* 0 */ |
209 | |
210 | /* |
211 | * The are the file operation function for user access to /dev/nvram |
212 | */ |
213 | |
214 | static loff_t nvram_llseek(struct file *file, loff_t offset, int origin) |
215 | { |
216 | switch (origin) { |
217 | case 0: |
218 | /* nothing to do */ |
219 | break; |
220 | case 1: |
221 | offset += file->f_pos; |
222 | break; |
223 | case 2: |
224 | offset += NVRAM_BYTES; |
225 | break; |
226 | default: |
227 | return -EINVAL; |
228 | } |
229 | |
230 | return (offset >= 0) ? (file->f_pos = offset) : -EINVAL; |
231 | } |
232 | |
233 | static ssize_t nvram_read(struct file *file, char __user *buf, |
234 | size_t count, loff_t *ppos) |
235 | { |
236 | unsigned char contents[NVRAM_BYTES]; |
237 | unsigned i = *ppos; |
238 | unsigned char *tmp; |
239 | |
240 | spin_lock_irq(&rtc_lock); |
241 | |
242 | if (!__nvram_check_checksum()) |
243 | goto checksum_err; |
244 | |
245 | for (tmp = contents; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp) |
246 | *tmp = __nvram_read_byte(i); |
247 | |
248 | spin_unlock_irq(&rtc_lock); |
249 | |
250 | if (copy_to_user(buf, contents, tmp - contents)) |
251 | return -EFAULT; |
252 | |
253 | *ppos = i; |
254 | |
255 | return tmp - contents; |
256 | |
257 | checksum_err: |
258 | spin_unlock_irq(&rtc_lock); |
259 | return -EIO; |
260 | } |
261 | |
262 | static ssize_t nvram_write(struct file *file, const char __user *buf, |
263 | size_t count, loff_t *ppos) |
264 | { |
265 | unsigned char contents[NVRAM_BYTES]; |
266 | unsigned i = *ppos; |
267 | unsigned char *tmp; |
268 | |
269 | if (i >= NVRAM_BYTES) |
270 | return 0; /* Past EOF */ |
271 | |
272 | if (count > NVRAM_BYTES - i) |
273 | count = NVRAM_BYTES - i; |
274 | if (count > NVRAM_BYTES) |
275 | return -EFAULT; /* Can't happen, but prove it to gcc */ |
276 | |
277 | if (copy_from_user(contents, buf, count)) |
278 | return -EFAULT; |
279 | |
280 | spin_lock_irq(&rtc_lock); |
281 | |
282 | if (!__nvram_check_checksum()) |
283 | goto checksum_err; |
284 | |
285 | for (tmp = contents; count--; ++i, ++tmp) |
286 | __nvram_write_byte(*tmp, i); |
287 | |
288 | __nvram_set_checksum(); |
289 | |
290 | spin_unlock_irq(&rtc_lock); |
291 | |
292 | *ppos = i; |
293 | |
294 | return tmp - contents; |
295 | |
296 | checksum_err: |
297 | spin_unlock_irq(&rtc_lock); |
298 | return -EIO; |
299 | } |
300 | |
301 | static long nvram_ioctl(struct file *file, unsigned int cmd, |
302 | unsigned long arg) |
303 | { |
304 | int i; |
305 | |
306 | switch (cmd) { |
307 | |
308 | case NVRAM_INIT: |
309 | /* initialize NVRAM contents and checksum */ |
310 | if (!capable(CAP_SYS_ADMIN)) |
311 | return -EACCES; |
312 | |
313 | mutex_lock(&nvram_mutex); |
314 | spin_lock_irq(&rtc_lock); |
315 | |
316 | for (i = 0; i < NVRAM_BYTES; ++i) |
317 | __nvram_write_byte(0, i); |
318 | __nvram_set_checksum(); |
319 | |
320 | spin_unlock_irq(&rtc_lock); |
321 | mutex_unlock(&nvram_mutex); |
322 | return 0; |
323 | |
324 | case NVRAM_SETCKS: |
325 | /* just set checksum, contents unchanged (maybe useful after |
326 | * checksum garbaged somehow...) */ |
327 | if (!capable(CAP_SYS_ADMIN)) |
328 | return -EACCES; |
329 | |
330 | mutex_lock(&nvram_mutex); |
331 | spin_lock_irq(&rtc_lock); |
332 | __nvram_set_checksum(); |
333 | spin_unlock_irq(&rtc_lock); |
334 | mutex_unlock(&nvram_mutex); |
335 | return 0; |
336 | |
337 | default: |
338 | return -ENOTTY; |
339 | } |
340 | } |
341 | |
342 | static int nvram_open(struct inode *inode, struct file *file) |
343 | { |
344 | spin_lock(&nvram_state_lock); |
345 | |
346 | if ((nvram_open_cnt && (file->f_flags & O_EXCL)) || |
347 | (nvram_open_mode & NVRAM_EXCL) || |
348 | ((file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE))) { |
349 | spin_unlock(&nvram_state_lock); |
350 | return -EBUSY; |
351 | } |
352 | |
353 | if (file->f_flags & O_EXCL) |
354 | nvram_open_mode |= NVRAM_EXCL; |
355 | if (file->f_mode & FMODE_WRITE) |
356 | nvram_open_mode |= NVRAM_WRITE; |
357 | nvram_open_cnt++; |
358 | |
359 | spin_unlock(&nvram_state_lock); |
360 | |
361 | return 0; |
362 | } |
363 | |
364 | static int nvram_release(struct inode *inode, struct file *file) |
365 | { |
366 | spin_lock(&nvram_state_lock); |
367 | |
368 | nvram_open_cnt--; |
369 | |
370 | /* if only one instance is open, clear the EXCL bit */ |
371 | if (nvram_open_mode & NVRAM_EXCL) |
372 | nvram_open_mode &= ~NVRAM_EXCL; |
373 | if (file->f_mode & FMODE_WRITE) |
374 | nvram_open_mode &= ~NVRAM_WRITE; |
375 | |
376 | spin_unlock(&nvram_state_lock); |
377 | |
378 | return 0; |
379 | } |
380 | |
381 | #ifndef CONFIG_PROC_FS |
382 | static int nvram_add_proc_fs(void) |
383 | { |
384 | return 0; |
385 | } |
386 | |
387 | #else |
388 | |
389 | static int nvram_proc_read(struct seq_file *seq, void *offset) |
390 | { |
391 | unsigned char contents[NVRAM_BYTES]; |
392 | int i = 0; |
393 | |
394 | spin_lock_irq(&rtc_lock); |
395 | for (i = 0; i < NVRAM_BYTES; ++i) |
396 | contents[i] = __nvram_read_byte(i); |
397 | spin_unlock_irq(&rtc_lock); |
398 | |
399 | mach_proc_infos(contents, seq, offset); |
400 | |
401 | return 0; |
402 | } |
403 | |
404 | static int nvram_proc_open(struct inode *inode, struct file *file) |
405 | { |
406 | return single_open(file, nvram_proc_read, NULL); |
407 | } |
408 | |
409 | static const struct file_operations nvram_proc_fops = { |
410 | .owner = THIS_MODULE, |
411 | .open = nvram_proc_open, |
412 | .read = seq_read, |
413 | .llseek = seq_lseek, |
414 | .release = single_release, |
415 | }; |
416 | |
417 | static int nvram_add_proc_fs(void) |
418 | { |
419 | if (!proc_create("driver/nvram", 0, NULL, &nvram_proc_fops)) |
420 | return -ENOMEM; |
421 | return 0; |
422 | } |
423 | |
424 | #endif /* CONFIG_PROC_FS */ |
425 | |
426 | static const struct file_operations nvram_fops = { |
427 | .owner = THIS_MODULE, |
428 | .llseek = nvram_llseek, |
429 | .read = nvram_read, |
430 | .write = nvram_write, |
431 | .unlocked_ioctl = nvram_ioctl, |
432 | .open = nvram_open, |
433 | .release = nvram_release, |
434 | }; |
435 | |
436 | static struct miscdevice nvram_dev = { |
437 | NVRAM_MINOR, |
438 | "nvram", |
439 | &nvram_fops |
440 | }; |
441 | |
442 | static int __init nvram_init(void) |
443 | { |
444 | int ret; |
445 | |
446 | /* First test whether the driver should init at all */ |
447 | if (!CHECK_DRIVER_INIT()) |
448 | return -ENODEV; |
449 | |
450 | ret = misc_register(&nvram_dev); |
451 | if (ret) { |
452 | printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", |
453 | NVRAM_MINOR); |
454 | goto out; |
455 | } |
456 | ret = nvram_add_proc_fs(); |
457 | if (ret) { |
458 | printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); |
459 | goto outmisc; |
460 | } |
461 | ret = 0; |
462 | printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); |
463 | out: |
464 | return ret; |
465 | outmisc: |
466 | misc_deregister(&nvram_dev); |
467 | goto out; |
468 | } |
469 | |
470 | static void __exit nvram_cleanup_module(void) |
471 | { |
472 | remove_proc_entry("driver/nvram", NULL); |
473 | misc_deregister(&nvram_dev); |
474 | } |
475 | |
476 | module_init(nvram_init); |
477 | module_exit(nvram_cleanup_module); |
478 | |
479 | /* |
480 | * Machine specific functions |
481 | */ |
482 | |
483 | #if MACH == PC |
484 | |
485 | static int pc_check_checksum(void) |
486 | { |
487 | int i; |
488 | unsigned short sum = 0; |
489 | unsigned short expect; |
490 | |
491 | for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) |
492 | sum += __nvram_read_byte(i); |
493 | expect = __nvram_read_byte(PC_CKS_LOC)<<8 | |
494 | __nvram_read_byte(PC_CKS_LOC+1); |
495 | return (sum & 0xffff) == expect; |
496 | } |
497 | |
498 | static void pc_set_checksum(void) |
499 | { |
500 | int i; |
501 | unsigned short sum = 0; |
502 | |
503 | for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i) |
504 | sum += __nvram_read_byte(i); |
505 | __nvram_write_byte(sum >> 8, PC_CKS_LOC); |
506 | __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1); |
507 | } |
508 | |
509 | #ifdef CONFIG_PROC_FS |
510 | |
511 | static char *floppy_types[] = { |
512 | "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M", |
513 | "3.5'' 2.88M", "3.5'' 2.88M" |
514 | }; |
515 | |
516 | static char *gfx_types[] = { |
517 | "EGA, VGA, ... (with BIOS)", |
518 | "CGA (40 cols)", |
519 | "CGA (80 cols)", |
520 | "monochrome", |
521 | }; |
522 | |
523 | static void pc_proc_infos(unsigned char *nvram, struct seq_file *seq, |
524 | void *offset) |
525 | { |
526 | int checksum; |
527 | int type; |
528 | |
529 | spin_lock_irq(&rtc_lock); |
530 | checksum = __nvram_check_checksum(); |
531 | spin_unlock_irq(&rtc_lock); |
532 | |
533 | seq_printf(seq, "Checksum status: %svalid\n", checksum ? "" : "not "); |
534 | |
535 | seq_printf(seq, "# floppies : %d\n", |
536 | (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0); |
537 | seq_printf(seq, "Floppy 0 type : "); |
538 | type = nvram[2] >> 4; |
539 | if (type < ARRAY_SIZE(floppy_types)) |
540 | seq_printf(seq, "%s\n", floppy_types[type]); |
541 | else |
542 | seq_printf(seq, "%d (unknown)\n", type); |
543 | seq_printf(seq, "Floppy 1 type : "); |
544 | type = nvram[2] & 0x0f; |
545 | if (type < ARRAY_SIZE(floppy_types)) |
546 | seq_printf(seq, "%s\n", floppy_types[type]); |
547 | else |
548 | seq_printf(seq, "%d (unknown)\n", type); |
549 | |
550 | seq_printf(seq, "HD 0 type : "); |
551 | type = nvram[4] >> 4; |
552 | if (type) |
553 | seq_printf(seq, "%02x\n", type == 0x0f ? nvram[11] : type); |
554 | else |
555 | seq_printf(seq, "none\n"); |
556 | |
557 | seq_printf(seq, "HD 1 type : "); |
558 | type = nvram[4] & 0x0f; |
559 | if (type) |
560 | seq_printf(seq, "%02x\n", type == 0x0f ? nvram[12] : type); |
561 | else |
562 | seq_printf(seq, "none\n"); |
563 | |
564 | seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", |
565 | nvram[18] | (nvram[19] << 8), |
566 | nvram[20], nvram[25], |
567 | nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8)); |
568 | seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n", |
569 | nvram[39] | (nvram[40] << 8), |
570 | nvram[41], nvram[46], |
571 | nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8)); |
572 | |
573 | seq_printf(seq, "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8)); |
574 | seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)\n", |
575 | nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8)); |
576 | |
577 | seq_printf(seq, "Gfx adapter : %s\n", |
578 | gfx_types[(nvram[6] >> 4) & 3]); |
579 | |
580 | seq_printf(seq, "FPU : %sinstalled\n", |
581 | (nvram[6] & 2) ? "" : "not "); |
582 | |
583 | return; |
584 | } |
585 | #endif |
586 | |
587 | #endif /* MACH == PC */ |
588 | |
589 | #if MACH == ATARI |
590 | |
591 | static int atari_check_checksum(void) |
592 | { |
593 | int i; |
594 | unsigned char sum = 0; |
595 | |
596 | for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) |
597 | sum += __nvram_read_byte(i); |
598 | return (__nvram_read_byte(ATARI_CKS_LOC) == (~sum & 0xff)) && |
599 | (__nvram_read_byte(ATARI_CKS_LOC + 1) == (sum & 0xff)); |
600 | } |
601 | |
602 | static void atari_set_checksum(void) |
603 | { |
604 | int i; |
605 | unsigned char sum = 0; |
606 | |
607 | for (i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i) |
608 | sum += __nvram_read_byte(i); |
609 | __nvram_write_byte(~sum, ATARI_CKS_LOC); |
610 | __nvram_write_byte(sum, ATARI_CKS_LOC + 1); |
611 | } |
612 | |
613 | #ifdef CONFIG_PROC_FS |
614 | |
615 | static struct { |
616 | unsigned char val; |
617 | char *name; |
618 | } boot_prefs[] = { |
619 | { 0x80, "TOS" }, |
620 | { 0x40, "ASV" }, |
621 | { 0x20, "NetBSD (?)" }, |
622 | { 0x10, "Linux" }, |
623 | { 0x00, "unspecified" } |
624 | }; |
625 | |
626 | static char *languages[] = { |
627 | "English (US)", |
628 | "German", |
629 | "French", |
630 | "English (UK)", |
631 | "Spanish", |
632 | "Italian", |
633 | "6 (undefined)", |
634 | "Swiss (French)", |
635 | "Swiss (German)" |
636 | }; |
637 | |
638 | static char *dateformat[] = { |
639 | "MM%cDD%cYY", |
640 | "DD%cMM%cYY", |
641 | "YY%cMM%cDD", |
642 | "YY%cDD%cMM", |
643 | "4 (undefined)", |
644 | "5 (undefined)", |
645 | "6 (undefined)", |
646 | "7 (undefined)" |
647 | }; |
648 | |
649 | static char *colors[] = { |
650 | "2", "4", "16", "256", "65536", "??", "??", "??" |
651 | }; |
652 | |
653 | static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq, |
654 | void *offset) |
655 | { |
656 | int checksum = nvram_check_checksum(); |
657 | int i; |
658 | unsigned vmode; |
659 | |
660 | seq_printf(seq, "Checksum status : %svalid\n", checksum ? "" : "not "); |
661 | |
662 | seq_printf(seq, "Boot preference : "); |
663 | for (i = ARRAY_SIZE(boot_prefs) - 1; i >= 0; --i) { |
664 | if (nvram[1] == boot_prefs[i].val) { |
665 | seq_printf(seq, "%s\n", boot_prefs[i].name); |
666 | break; |
667 | } |
668 | } |
669 | if (i < 0) |
670 | seq_printf(seq, "0x%02x (undefined)\n", nvram[1]); |
671 | |
672 | seq_printf(seq, "SCSI arbitration : %s\n", |
673 | (nvram[16] & 0x80) ? "on" : "off"); |
674 | seq_printf(seq, "SCSI host ID : "); |
675 | if (nvram[16] & 0x80) |
676 | seq_printf(seq, "%d\n", nvram[16] & 7); |
677 | else |
678 | seq_printf(seq, "n/a\n"); |
679 | |
680 | /* the following entries are defined only for the Falcon */ |
681 | if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON) |
682 | return; |
683 | |
684 | seq_printf(seq, "OS language : "); |
685 | if (nvram[6] < ARRAY_SIZE(languages)) |
686 | seq_printf(seq, "%s\n", languages[nvram[6]]); |
687 | else |
688 | seq_printf(seq, "%u (undefined)\n", nvram[6]); |
689 | seq_printf(seq, "Keyboard language: "); |
690 | if (nvram[7] < ARRAY_SIZE(languages)) |
691 | seq_printf(seq, "%s\n", languages[nvram[7]]); |
692 | else |
693 | seq_printf(seq, "%u (undefined)\n", nvram[7]); |
694 | seq_printf(seq, "Date format : "); |
695 | seq_printf(seq, dateformat[nvram[8] & 7], |
696 | nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/'); |
697 | seq_printf(seq, ", %dh clock\n", nvram[8] & 16 ? 24 : 12); |
698 | seq_printf(seq, "Boot delay : "); |
699 | if (nvram[10] == 0) |
700 | seq_printf(seq, "default"); |
701 | else |
702 | seq_printf(seq, "%ds%s\n", nvram[10], |
703 | nvram[10] < 8 ? ", no memory test" : ""); |
704 | |
705 | vmode = (nvram[14] << 8) || nvram[15]; |
706 | seq_printf(seq, |
707 | "Video mode : %s colors, %d columns, %s %s monitor\n", |
708 | colors[vmode & 7], |
709 | vmode & 8 ? 80 : 40, |
710 | vmode & 16 ? "VGA" : "TV", vmode & 32 ? "PAL" : "NTSC"); |
711 | seq_printf(seq, " %soverscan, compat. mode %s%s\n", |
712 | vmode & 64 ? "" : "no ", |
713 | vmode & 128 ? "on" : "off", |
714 | vmode & 256 ? |
715 | (vmode & 16 ? ", line doubling" : ", half screen") : ""); |
716 | |
717 | return; |
718 | } |
719 | #endif |
720 | |
721 | #endif /* MACH == ATARI */ |
722 | |
723 | MODULE_LICENSE("GPL"); |
724 | MODULE_ALIAS_MISCDEV(NVRAM_MINOR); |
725 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9