Use the preferred order of 'static const' instead of 'const static'.
[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, 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 probing_for(const char *vendor, const char *info, uint16_t port)
155 {
156         if (!verbose)
157                 return;
158
159         /* Yes, there's no space between '%s' and 'at'! */
160         printf("Probing for %s Super I/O %sat 0x%x...\n",
161                vendor, info, port);
162 }
163
164 static void print_version(void)
165 {
166         printf("superiotool r%s\n", SUPERIOTOOL_VERSION);
167 }
168
169 int main(int argc, char *argv[])
170 {
171         int i, j, opt, option_index;
172
173         static const struct option long_options[] = {
174                 {"dump",                no_argument, NULL, 'd'},
175                 {"verbose",             no_argument, NULL, 'V'},
176                 {"version",             no_argument, NULL, 'v'},
177                 {"help",                no_argument, NULL, 'h'},
178                 {0, 0, 0, 0}
179         };
180
181         while ((opt = getopt_long(argc, argv, "dVvh",
182                                   long_options, &option_index)) != EOF) {
183                 switch (opt) {
184                 case 'd':
185                         dump = 1;
186                         break;
187                 case 'V':
188                         verbose = 1;
189                         break;
190                 case 'v':
191                         print_version();
192                         exit(0);
193                         break;
194                 case 'h':
195                         printf(USAGE);
196                         exit(0);
197                         break;
198                 default:
199                         /* Unknown option. */
200                         exit(1);
201                         break;
202                 }
203         }
204
205         if (iopl(3) < 0) {
206                 perror("iopl");
207                 printf("Superiotool must be run as root.\n");
208                 exit(1);
209         }
210
211         print_version();
212
213         for (i = 0; i < ARRAY_SIZE(superio_ports_table); i++) {
214                 for (j = 0; superio_ports_table[i].ports[j] != EOT; j++)
215                         superio_ports_table[i].probe_idregs(
216                                 superio_ports_table[i].ports[j]);
217         }
218
219         if (!chip_found)
220                 printf("No Super I/O found\n");
221
222         return 0;
223 }