Print superiotool version when run with --verbose.
[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 uint8_t regval(uint16_t port, uint8_t reg)
29 {
30         outb(reg, port);
31         return inb(port + 1);
32 }
33
34 void regwrite(uint16_t port, uint8_t reg, uint8_t val)
35 {
36         outb(reg, port);
37         outb(val, port + 1);
38 }
39
40 void enter_conf_mode_winbond_fintek_ite_8787(uint16_t port)
41 {
42         outb(0x87, port);
43         outb(0x87, port);
44 }
45
46 void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port)
47 {
48         outb(0xaa, port);               /* Fintek, Winbond */
49         regwrite(port, 0x02, 0x02);     /* ITE */
50 }
51
52 int superio_unknown(const struct superio_registers reg_table[], uint16_t id)
53 {
54         return !strncmp(get_superio_name(reg_table, id), "<unknown>", 9);
55 }
56
57 const char *get_superio_name(const struct superio_registers reg_table[],
58                              uint16_t id)
59 {
60         int i;
61
62         for (i = 0; /* Nothing */; i++) {
63                 if (reg_table[i].superio_id == EOT)
64                         break;
65
66                 if ((uint16_t)reg_table[i].superio_id != id)
67                         continue;
68
69                 return reg_table[i].name;
70         }
71
72         return "<unknown>";
73 }
74
75 static void dump_regs(const struct superio_registers reg_table[],
76                       int i, int j, uint16_t port)
77 {
78         int k;
79         const int *idx;
80
81         if (reg_table[i].ldn[j].ldn != NOLDN) {
82                 printf("LDN 0x%02x ", reg_table[i].ldn[j].ldn);
83                 if (reg_table[i].ldn[j].name != NULL)
84                         printf("(%s)", reg_table[i].ldn[j].name);
85                 regwrite(port, 0x07, reg_table[i].ldn[j].ldn);
86         } else {
87                 printf("Register dump:");
88         }
89
90         idx = reg_table[i].ldn[j].idx;
91
92         printf("\nidx ");
93         for (k = 0; /* Nothing */; k++) {
94                 if (idx[k] == EOT)
95                         break;
96                 printf("%02x ", idx[k]);
97         }
98
99         printf("\nval ");
100         for (k = 0; /* Nothing */; k++) {
101                 if (idx[k] == EOT)
102                         break;
103                 printf("%02x ", regval(port, idx[k]));
104         }
105
106         printf("\ndef ");
107         idx = reg_table[i].ldn[j].def;
108         for (k = 0; /* Nothing */; k++) {
109                 if (idx[k] == EOT)
110                         break;
111                 else if (idx[k] == NANA)
112                         printf("NA ");
113                 else if (idx[k] == RSVD)
114                         printf("RR ");
115                 else if (idx[k] == MISC)        /* TODO */
116                         printf("MM ");
117                 else
118                         printf("%02x ", idx[k]);
119         }
120         printf("\n");
121 }
122
123 void dump_superio(const char *vendor,
124                   const struct superio_registers reg_table[],
125                   uint16_t port, uint16_t id)
126 {
127         int i, j, no_dump_available = 1;
128
129         if (!dump)
130                 return;
131
132         for (i = 0; /* Nothing */; i++) {
133                 if (reg_table[i].superio_id == EOT)
134                         break;
135
136                 if ((uint16_t)reg_table[i].superio_id != id)
137                         continue;
138
139                 for (j = 0; /* Nothing */; j++) {
140                         if (reg_table[i].ldn[j].ldn == EOT)
141                                 break;
142                         no_dump_available = 0;
143                         dump_regs(reg_table, i, j, port);
144                 }
145
146                 if (no_dump_available)
147                         printf("No dump available for this Super I/O\n");
148         }
149 }
150
151 void dump_superio_readable(uint16_t port)
152 {
153         /* TODO */
154         if (dump_readable)
155                 printf("No human-readable dump available for this Super I/O\n");
156 }
157
158 void no_superio_found(const char *vendor, const char *info, uint16_t port)
159 {
160         if (!verbose)
161                 return;
162
163         if (inb(port) == 0xff)
164                 /* Yes, there's no space between '%s' and 'at'! */
165                 printf("Probing for %s Super I/O %sat 0x%x... failed\n",
166                        vendor, info, port);
167         else
168                 printf("Probing 0x%x, failed (0x%02x), data returns 0x%02x\n",
169                        port, inb(port), inb(port + 1));
170 }
171
172 static void print_version(void)
173 {
174         char tmp[80];
175
176         strncpy((char *)&tmp,
177                 (const char *)&SUPERIOTOOL_VERSION[6],
178                 strlen(SUPERIOTOOL_VERSION) - 8);
179         printf("superiotool r%s\n", (char *)&tmp);
180 }
181
182 int main(int argc, char *argv[])
183 {
184         int i, j, opt, option_index;
185
186         const static struct option long_options[] = {
187                 {"dump",                no_argument, NULL, 'd'},
188                 {"dump-readable",       no_argument, NULL, 'D'},
189                 {"verbose",             no_argument, NULL, 'V'},
190                 {"version",             no_argument, NULL, 'v'},
191                 {"help",                no_argument, NULL, 'h'},
192                 {0, 0, 0, 0}
193         };
194
195         while ((opt = getopt_long(argc, argv, "dDVvh",
196                                   long_options, &option_index)) != EOF) {
197                 switch (opt) {
198                 case 'd':
199                         dump = 1;
200                         break;
201                 case 'D':
202                         dump_readable = 1;
203                         break;
204                 case 'V':
205                         /* Print version in --verbose mode. */
206                         print_version();
207                         verbose = 1;
208                         break;
209                 case 'v':
210                         print_version();
211                         exit(0);
212                         break;
213                 case 'h':
214                         printf(USAGE);
215                         exit(0);
216                         break;
217                 default:
218                         /* Unknown option. */
219                         exit(1);
220                         break;
221                 }
222         }
223
224         if (iopl(3) < 0) {
225                 perror("iopl");
226                 printf("Superiotool must be run as root.\n");
227                 exit(1);
228         }
229
230         for (i = 0; i < ARRAY_SIZE(superio_ports_table); i++) {
231                 for (j = 0; superio_ports_table[i].ports[j] != EOT; j++)
232                         superio_ports_table[i].probe_idregs(
233                                 superio_ports_table[i].ports[j]);
234         }
235
236         return 0;
237 }