root/lm-sensors/branches/lm-sensors-3.0.0/prog/dump/isadump.c @ 4545

Revision 4545, 7.7 KB (checked in by khali, 7 years ago)

Add some more warning flags, and fix these warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    isadump.c - isadump, a user-space program to dump ISA registers
3    Copyright (C) 2000  Frodo Looijaard <frodol@dds.nl>, and
4                        Mark D. Studebaker <mdsxyz123@yahoo.com>
5    Copyright (C) 2004  The lm_sensors group
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/*
23        Typical usage:
24        isadump 0x295 0x296             Basic winbond dump using address/data registers
25        isadump 0x295 0x296 2           Winbond dump, bank 2
26        isadump 0x2e 0x2f 0x09          Super-I/O, logical device 9
27        isadump -f 0x5000               Flat address space dump like for Via 686a
28        isadump -f 0xecf0 0x10 1        PC87366, temperature channel 2
29*/
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include "util.h"
36#include "superio.h"
37
38
39/* To keep glibc2 happy */
40#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ >= 0
41#include <sys/io.h>
42#else
43#include <asm/io.h>
44#endif
45
46#ifdef __powerpc__
47unsigned long isa_io_base = 0; /* XXX for now */
48#endif /* __powerpc__ */
49
50static void help(void)
51{
52        fprintf(stderr,
53                "Syntax for I2C-like access:\n"
54                "  isadump [-y] [-k V1,V2...] ADDRREG DATAREG [BANK [BANKREG]]\n"
55                "Syntax for flat address space:\n"
56                "  isadump [-y] -f ADDRESS [RANGE [BANK [BANKREG]]]\n");
57}
58
59static int default_bankreg(int flat, int addrreg, int datareg)
60{
61        if (flat) {
62                return 0x09; /* Works for National Semiconductor
63                                Super-IO chips */
64        }
65
66        if ((addrreg == 0x2e && datareg == 0x2f)
67         || (addrreg == 0x4e && datareg == 0x4f)) {
68                return 0x07; /* Works for all Super-I/O chips */
69        }
70       
71        return 0x4e; /* Works for Winbond ISA chips, default */
72}
73
74static int set_bank(int flat, int addrreg, int datareg, int bank, int bankreg)
75{
76        int oldbank;
77
78        if (flat) {
79                oldbank = inb(addrreg+bankreg);
80                outb(bank, addrreg+bankreg);
81        } else {
82                outb(bankreg, addrreg);
83                oldbank = inb(datareg);
84                outb(bank, datareg);
85        }
86
87        return oldbank;
88}
89
90int main(int argc, char *argv[])
91{
92        int addrreg;        /* address in flat mode */
93        int datareg = 0;    /* unused in flat mode */
94        int range = 256;    /* can be changed only in flat mode */
95        int bank = -1;      /* -1 means no bank operation */
96        int bankreg;
97        int oldbank = 0;
98        int i, j, res;
99        int flags = 0;
100        int flat = 0, yes = 0;
101        char *end;
102        unsigned char enter_key[SUPERIO_MAX_KEY+1];
103
104        enter_key[0] = 0;
105
106        /* handle (optional) flags first */
107        while (1+flags < argc && argv[1+flags][0] == '-') {
108                switch (argv[1+flags][1]) {
109                case 'f': flat = 1; break;
110                case 'y': yes = 1; break;
111                case 'k':
112                        if (2+flags >= argc
113                         || superio_parse_key(enter_key, argv[2+flags]) < 0) {
114                                fprintf(stderr, "Invalid or missing key\n");
115                                help();
116                                exit(1);
117                        }
118                        flags++;
119                        break;
120                default:
121                        fprintf(stderr, "Warning: Unsupported flag "
122                                "\"-%c\"!\n", argv[1+flags][1]);
123                        help();
124                        exit(1);
125                }
126                flags++;
127        }
128
129        /* key is never needed in flat mode */
130        if (flat && enter_key[0]) {
131                fprintf(stderr, "Error: Cannot use key in flat mode\n");
132                exit(1);
133        }
134
135        /* verify that the argument count is correct */
136        if ((!flat && argc < 1+flags+2)
137         || (flat && argc < 1+flags+1)) {
138                help();
139                exit(1);
140        }
141
142        addrreg = strtol(argv[1+flags], &end, 0);
143        if (*end) {
144                fprintf(stderr, "Error: Invalid address!\n");
145                help();
146                exit(1);
147        }
148        if (addrreg < 0 || addrreg > (flat?0xffff:0x3fff)) {
149                fprintf(stderr, "Error: Address out of range "
150                        "(0x0000-0x%04x)!\n", flat?0xffff:0x3fff);
151                help();
152                exit(1);
153        }
154
155        if (flat) {
156                if (1+flags+1 < argc) {
157                        range = strtol(argv[1+flags+1], &end, 0);
158                        if (*end || range <= 0 || range > 0x100
159                         || range & 0xf) {
160                                fprintf(stderr, "Error: Invalid range!\n"
161                                        "Hint: Must be a multiple of 16 no "
162                                        "greater than 256.\n");
163                                help();
164                                exit(1);
165                        }
166                } else {
167                        addrreg &= 0xff00; /* Force alignment */
168                }
169        } else {
170                datareg = strtol(argv[1+flags+1], &end, 0);
171                if (*end) {
172                        fprintf(stderr, "Error: Invalid data register!\n");
173                        help();
174                        exit(1);
175                }
176                if (datareg < 0 || datareg > 0x3fff) {
177                        fprintf(stderr, "Error: Data register out of range "
178                                "(0x0000-0x3fff)!\n");
179                        help();
180                        exit(1);
181                }
182        }
183
184        bankreg = default_bankreg(flat, addrreg, datareg);
185
186        if (1+flags+2 < argc) {
187                bank = strtol(argv[1+flags+2], &end, 0);
188                if (*end) {
189                        fprintf(stderr, "Error: Invalid bank number!\n");
190                        help();
191                        exit(1);
192                }
193                if ((bank < 0) || (bank > 31)) {
194                        fprintf(stderr, "Error: bank out of range (0-31)!\n");
195                        help();
196                        exit(1);
197                }
198
199                if (1+flags+3 < argc) {
200                        bankreg = strtol(argv[1+flags+3], &end, 0);
201                        if (*end) {
202                                fprintf(stderr, "Error: Invalid bank "
203                                        "register!\n");
204                                help();
205                                exit(1);
206                        }
207                        if (bankreg < 0 || bankreg >= range) {
208                                fprintf(stderr, "Error: bank out of range "
209                                        "(0x00-0x%02x)!\n", range-1);
210                                help();
211                                exit(1);
212                        }
213                }
214        }
215
216        if (getuid()) {
217                fprintf(stderr, "Error: Can only be run as root (or make it "
218                        "suid root)\n");
219                exit(1);
220        }
221
222        if (!yes) {
223                fprintf(stderr, "WARNING! Running this program can cause "
224                        "system crashes, data loss and worse!\n");
225
226                if (flat)
227                        fprintf(stderr, "I will probe address range 0x%x to "
228                                "0x%x.\n", addrreg, addrreg + range - 1);
229                else
230                        fprintf(stderr, "I will probe address register 0x%x "
231                                "and data register 0x%x.\n", addrreg, datareg);
232
233                if (bank>=0)   
234                        fprintf(stderr, "Probing bank %d using bank register "
235                                "0x%02x.\n", bank, bankreg);
236
237                fprintf(stderr, "Continue? [Y/n] ");
238                fflush(stderr);
239                if (!user_ack(1)) {
240                        fprintf(stderr, "Aborting on user request.\n");
241                        exit(0);
242                }
243        }
244
245#ifndef __powerpc__
246        if ((datareg < 0x400) && (addrreg < 0x400) && !flat) {
247                if (ioperm(datareg, 1, 1)) {
248                        fprintf(stderr, "Error: Could not ioperm() data "
249                                "register!\n");
250                        exit(1);
251                }
252                if (ioperm(addrreg, 1, 1)) {
253                        fprintf(stderr, "Error: Could not ioperm() address "
254                                "register!\n");
255                        exit(1);
256                }
257        } else {
258                if (iopl(3)) {
259                        fprintf(stderr, "Error: Could not do iopl(3)!\n");
260                        exit(1);
261                }
262        }
263#endif
264
265        /* Enter Super-I/O configuration mode */
266        if (enter_key[0])
267                superio_write_key(addrreg, enter_key);
268
269        if (bank >= 0)
270                oldbank = set_bank(flat, addrreg, datareg, bank, bankreg);
271
272        if (flat)
273                printf("  ");
274        printf("     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n");
275        for (i = 0; i < range; i += 16) {
276                if (flat)
277                        printf("%04x: ", addrreg + i);
278                else
279                        printf("%02x: ", i);
280
281                /* It was noticed that Winbond Super-I/O chips
282                   would leave the configuration mode after
283                   an arbitrary number of register reads,
284                   causing any subsequent read attempt to
285                   silently fail. Repeating the key every 16 reads
286                   prevents that. */
287                if (enter_key[0])
288                        superio_write_key(addrreg, enter_key);
289
290                for (j = 0; j < 16; j++) {
291                        fflush(stdout);
292                        if (flat) {
293                                res = inb(addrreg + i + j);
294                        } else {       
295                                outb(i+j, addrreg);
296                                if (i+j == 0 && inb(addrreg) == 0x80) {
297                                        /* Bit 7 appears to be a busy flag */
298                                        range = 128;
299                                }
300                                res = inb(datareg);
301                        }
302                        printf("%02x ", res);
303                }
304                printf("\n");
305        }
306
307        /* Restore the original bank value */
308        if (bank >= 0)
309                set_bank(flat, addrreg, datareg, oldbank, bankreg);
310
311        /* Exit Super-I/O configuration mode */
312        if (enter_key[0])
313                superio_reset(addrreg, datareg);
314
315        exit(0);
316}
Note: See TracBrowser for help on using the browser.