202daec15173482c496f29ed3a89782a07644300
[coreboot.git] / util / superiotool / superiotool.c
1 /*
2  * This file is part of the superiotool project.
3  *
4  * Copyright (C) 2006 Ronald Minnich <rminnich@gmail.com>
5  * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
6  * Copyright (C) 2007 Carl-Daniel Hailfinger
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
21  */
22
23 #include "superiotool.h"
24
25 /* Command line options. */
26 int dump = 0, dump_readable = 0, verbose = 0;
27
28 /* Global flag which indicates whether a chip was detected at all. */
29 int chip_found = 0;
30
31 uint8_t regval(uint16_t port, uint8_t reg)
32 {
33         outb(reg, port);
34         return inb(port + 1);
35 }
36
37 void regwrite(uint16_t port, uint8_t reg, uint8_t val)
38 {
39         outb(reg, port);
40         outb(val, port + 1);
41 }
42
43 void enter_conf_mode_winbond_fintek_ite_8787(uint16_t port)
44 {
45         outb(0x87, port);
46         outb(0x87, port);
47 }
48
49 void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port)
50 {
51         outb(0xaa, port);               /* Fintek, Winbond */
52         regwrite(port, 0x02, 0x02);     /* ITE */
53 }
54
55 int superio_unknown(const struct superio_registers reg_table[], uint16_t id)
56 {
57         return !strncmp(get_superio_name(reg_table, id), "<unknown>", 9);
58 }
59
60 const char *get_superio_name(const struct superio_registers reg_table[],
61                              uint16_t id)
62 {
63         int i;
64
65         for (i = 0; /* Nothing */; i++) {
66                 if (reg_table[i].superio_id == EOT)
67                         break;
68
69                 if ((uint16_t)reg_table[i].superio_id != id)
70                         continue;
71
72                 return reg_table[i].name;
73         }
74
75         return "<unknown>";
76 }
77
78 static void dump_regs(const struct superio_registers reg_table[],
79                       int i, int j, uint16_t port)
80 {
81         int k;
82         const int *idx;
83
84         if (reg_table[i].ldn[j].ldn != NOLDN) {
85                 printf("LDN 0x%02x ", reg_table[i].ldn[j].ldn);
86                 if (reg_table[i].ldn[j].name != NULL)
87                         printf("(%s)", reg_table[i].ldn[j].name);
88                 regwrite(port, 0x07, reg_table[i].ldn[j].ldn);
89         } else {
90                 printf("Register dump:");
91         }
92
93         idx = reg_table[i].ldn[j].idx;
94
95         printf("\nidx ");
96         for (k = 0; /* Nothing */; k++) {
97                 if (idx[k] == EOT)
98                         break;
99                 printf("%02x ", idx[k]);
100         }
101
102         printf("\nval ");
103         for (k = 0; /* Nothing */; k++) {
104                 if (idx[k] == EOT)
105                         break;
106                 printf("%02x ", regval(port, idx[k]));
107         }
108
109         printf("\ndef ");
110         idx = reg_table[i].ldn[j].def;
111         for (k = 0; /* Nothing */; k++) {
112                 if (idx[k] == EOT)
113                         break;
114                 else if (idx[k] == NANA)
115                         printf("NA ");
116                 else if (idx[k] == RSVD)
117                         printf("RR ");
118                 else if (idx[k] == MISC)        /* TODO */
119                         printf("MM ");
120                 else
121                         printf("%02x ", idx[k]);
122         }
123         printf("\n");
124 }
125
126 void dump_superio(const char *vendor,
127                   const struct superio_registers reg_table[],
128                   uint16_t port, uint16_t id)
129 {
130         int i, j, no_dump_available = 1;
131
132         if (!dump)
133                 return;
134
135         for (i = 0; /* Nothing */; i++) {
136                 if (reg_table[i].superio_id == EOT)
137                         break;
138
139                 if ((uint16_t)reg_table[i].superio_id != id)
140                         continue;
141
142                 for (j = 0; /* Nothing */; j++) {
143                         if (reg_table[i].ldn[j].ldn == EOT)
144                                 break;
145                         no_dump_available = 0;
146                         dump_regs(reg_table, i, j, port);
147                 }
148
149                 if (no_dump_available)
150                         printf("No dump available for this Super I/O\n");
151         }
152 }
153
154 void dump_superio_readable(uint16_t port)
155 {
156         /* TODO */
157         if (dump_readable)
158                 printf("No human-readable dump available for this Super I/O\n");
159 }
160
161 void probing_for(const char *vendor, const char *info, uint16_t port)
162 {
163         if (!verbose)
164                 return;
165
166         /* Yes, there's no space between '%s' and 'at'! */
167         printf("Probing for %s Super I/O %sat 0x%x...\n",
168                vendor, info, port);
169 }
170
171 static void print_version(void)
172 {
173         printf("superiotool r%s\n", SUPERIOTOOL_VERSION);
174 }
175
176 int main(int argc, char *argv[])
177 {
178         int i, j, opt, option_index;
179
180         const static struct option long_options[] = {
181                 {"dump",                no_argument, NULL, 'd'},
182                 {"dump-readable",       no_argument, NULL, 'D'},
183                 {"verbose",             no_argument, NULL, 'V'},
184                 {"version",             no_argument, NULL, 'v'},
185                 {"help",                no_argument, NULL, 'h'},
186                 {0, 0, 0, 0}
187         };
188
189         while ((opt = getopt_long(argc, argv, "dDVvh",
190                                   long_options, &option_index)) != EOF) {
191                 switch (opt) {
192                 case 'd':
193                         dump = 1;
194                         break;
195                 case 'D':
196                         dump_readable = 1;
197                         break;
198                 case 'V':
199                         verbose = 1;
200                         break;
201                 case 'v':
202                         print_version();
203                         exit(0);
204                         break;
205                 case 'h':
206                         printf(USAGE);
207                         exit(0);
208                         break;
209                 default:
210                         /* Unknown option. */
211                         exit(1);
212                         break;
213                 }
214         }
215
216         if (iopl(3) < 0) {
217                 perror("iopl");
218                 printf("Superiotool must be run as root.\n");
219                 exit(1);
220         }
221
222         print_version();
223
224         for (i = 0; i < ARRAY_SIZE(superio_ports_table); i++) {
225                 for (j = 0; superio_ports_table[i].ports[j] != EOT; j++)
226                         superio_ports_table[i].probe_idregs(
227                                 superio_ports_table[i].ports[j]);
228         }
229
230         if (!chip_found)
231                 printf("No Super I/O found\n");
232
233         return 0;
234 }