Update list of superiotool contributors to r5048 (trivial).
[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 #if defined(__FreeBSD__)
27 #include <fcntl.h>
28 #include <unistd.h>
29 #endif
30
31 /* Command line options. */
32 int dump = 0, verbose = 0, extra_dump = 0;
33
34 /* Global flag which indicates whether a chip was detected at all. */
35 int chip_found = 0;
36
37 uint8_t regval(uint16_t port, uint8_t reg)
38 {
39         OUTB(reg, port);
40         return INB(port + ((port == 0x3bd) ? 2 : 1)); /* 0x3bd is special. */
41 }
42
43 void regwrite(uint16_t port, uint8_t reg, uint8_t val)
44 {
45         OUTB(reg, port);
46         OUTB(val, port + 1);
47 }
48
49 void enter_conf_mode_winbond_fintek_ite_8787(uint16_t port)
50 {
51         OUTB(0x87, port);
52         OUTB(0x87, port);
53 }
54
55 void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port)
56 {
57         OUTB(0xaa, port);               /* Fintek, Winbond */
58         regwrite(port, 0x02, 0x02);     /* ITE */
59 }
60
61 int superio_unknown(const struct superio_registers reg_table[], uint16_t id)
62 {
63         return !strncmp(get_superio_name(reg_table, id), "<unknown>", 9);
64 }
65
66 const char *get_superio_name(const struct superio_registers reg_table[],
67                              uint16_t id)
68 {
69         int i;
70
71         for (i = 0; /* Nothing */; i++) {
72                 if (reg_table[i].superio_id == EOT)
73                         break;
74
75                 if ((uint16_t)reg_table[i].superio_id != id)
76                         continue;
77
78                 return reg_table[i].name;
79         }
80
81         return "<unknown>";
82 }
83
84 static void dump_regs(const struct superio_registers reg_table[],
85                       int i, int j, uint16_t port, uint8_t ldn_sel)
86 {
87         int k;
88         const int16_t *idx;
89
90         if (reg_table[i].ldn[j].ldn != NOLDN) {
91                 printf("LDN 0x%02x", reg_table[i].ldn[j].ldn);
92                 if (reg_table[i].ldn[j].name != NULL)
93                         printf(" (%s)", reg_table[i].ldn[j].name);
94                 regwrite(port, ldn_sel, reg_table[i].ldn[j].ldn);
95         } else {
96                 printf("Register dump:");
97         }
98
99         idx = reg_table[i].ldn[j].idx;
100
101         printf("\nidx");
102         for (k = 0; idx[k] != EOT; k++) {
103                 if (k && !(k % 8))
104                         putchar(' ');
105                 printf(" %02x", idx[k]);
106         }
107
108         printf("\nval");
109         for (k = 0; idx[k] != EOT; k++) {
110                 if (k && !(k % 8))
111                         putchar(' ');
112                 printf(" %02x", regval(port, idx[k]));
113         }
114
115         printf("\ndef");
116         idx = reg_table[i].ldn[j].def;
117         for (k = 0; idx[k] != EOT; k++) {
118                 if (k && !(k % 8))
119                         putchar(' ');
120                 if (idx[k] == NANA)
121                         printf(" NA");
122                 else if (idx[k] == RSVD)
123                         printf(" RR");
124                 else if (idx[k] == MISC)
125                         printf(" MM");
126                 else
127                         printf(" %02x", idx[k]);
128         }
129         printf("\n");
130 }
131
132 void dump_superio(const char *vendor,
133                   const struct superio_registers reg_table[],
134                   uint16_t port, uint16_t id, uint8_t ldn_sel)
135 {
136         int i, j, no_dump_available = 1;
137
138         if (!dump)
139                 return;
140
141         for (i = 0; /* Nothing */; i++) {
142                 if (reg_table[i].superio_id == EOT)
143                         break;
144
145                 if ((uint16_t)reg_table[i].superio_id != id)
146                         continue;
147
148                 for (j = 0; /* Nothing */; j++) {
149                         if (reg_table[i].ldn[j].ldn == EOT)
150                                 break;
151                         no_dump_available = 0;
152                         dump_regs(reg_table, i, j, port, ldn_sel);
153                 }
154
155                 if (no_dump_available)
156                         printf("No dump available for this Super I/O\n");
157         }
158 }
159
160 void dump_io(uint16_t iobase, uint16_t length)
161 {
162         uint16_t i;
163
164         printf("Dumping %d I/O mapped registers at base 0x%04x:\n",
165                         length, iobase);
166         for (i = 0; i < length; i++)
167                 printf("%02x ", i);
168         printf("\n");
169         for (i = 0; i < length; i++)
170                 printf("%02x ", INB(iobase + i));
171         printf("\n");
172 }
173
174 void probing_for(const char *vendor, const char *info, uint16_t port)
175 {
176         if (!verbose)
177                 return;
178
179         /* Yes, there's no space between '%s' and 'at'! */
180         printf("Probing for %s Super I/O %sat 0x%x...\n", vendor, info, port);
181 }
182
183 /** Print a list of all supported chips from the given vendor. */
184 void print_vendor_chips(const char *vendor,
185                         const struct superio_registers reg_table[])
186 {
187         int i;
188
189         for (i = 0; reg_table[i].superio_id != EOT; i++) {
190                 printf("%s %s", vendor, reg_table[i].name);
191
192                 /* Unless the ldn is empty, assume this chip has a dump. */
193                 if (reg_table[i].ldn[0].ldn != EOT)
194                         printf(" (dump available)");
195
196                 printf("\n");
197         }
198
199         /* If we printed any chips for this vendor, put in a blank line. */
200         if (i != 0)
201                 printf("\n");
202 }
203
204 /** Print a list of all chips supported by superiotool. */
205 void print_list_of_supported_chips(void)
206 {
207         int i;
208
209         printf("Supported Super I/O chips:\n\n");
210
211         for (i = 0; i < ARRAY_SIZE(vendor_print_functions); i++)
212                 vendor_print_functions[i].print_list();
213
214         printf("See <http://coreboot.org/Superiotool#Supported_devices> "
215                "for more information.\n");
216 }
217
218 static void print_version(void)
219 {
220         printf("superiotool r%s\n", SUPERIOTOOL_VERSION);
221 }
222
223 int main(int argc, char *argv[])
224 {
225         int i, j, opt, option_index;
226 #if defined(__FreeBSD__)
227         int io_fd;
228 #endif
229
230         static const struct option long_options[] = {
231                 {"dump",                no_argument, NULL, 'd'},
232                 {"extra-dump",          no_argument, NULL, 'e'},
233                 {"list-supported",      no_argument, NULL, 'l'},
234                 {"verbose",             no_argument, NULL, 'V'},
235                 {"version",             no_argument, NULL, 'v'},
236                 {"help",                no_argument, NULL, 'h'},
237                 {0, 0, 0, 0}
238         };
239
240         while ((opt = getopt_long(argc, argv, "delVvh",
241                                   long_options, &option_index)) != EOF) {
242                 switch (opt) {
243                 case 'd':
244                         dump = 1;
245                         break;
246                 case 'e':
247                         extra_dump = 1;
248                         break;
249                 case 'l':
250                         print_list_of_supported_chips();
251                         exit(0);
252                         break;
253                 case 'V':
254                         verbose = 1;
255                         break;
256                 case 'v':
257                         print_version();
258                         exit(0);
259                         break;
260                 case 'h':
261                         printf(USAGE);
262                         printf(USAGE_INFO);
263                         exit(0);
264                         break;
265                 default:
266                         /* Unknown option. */
267                         exit(1);
268                         break;
269                 }
270         }
271
272 #if defined(__FreeBSD__)
273         if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
274                 perror("/dev/io");
275 #else
276         if (iopl(3) < 0) {
277                 perror("iopl");
278 #endif
279                 printf("Superiotool must be run as root.\n");
280                 exit(1);
281         }
282
283         print_version();
284
285 #ifdef PCI_SUPPORT
286         /* Do some basic libpci init. */
287         pacc = pci_alloc();
288         pci_init(pacc);
289         pci_scan_bus(pacc);
290 #endif
291
292         for (i = 0; i < ARRAY_SIZE(superio_ports_table); i++) {
293                 for (j = 0; superio_ports_table[i].ports[j] != EOT; j++)
294                         superio_ports_table[i].probe_idregs(
295                                 superio_ports_table[i].ports[j]);
296         }
297
298         if (!chip_found)
299                 printf("No Super I/O found\n");
300
301 #if defined(__FreeBSD__)
302         close(io_fd);
303 #endif
304         return 0;
305 }