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