]> mj.ucw.cz Git - pciutils.git/blob - setpci.c
Annotate printf-like functions with format checking attributes.
[pciutils.git] / setpci.c
1 /*
2  *      The PCI Utilities -- Manipulate PCI Configuration Registers
3  *
4  *      Copyright (c) 1998--2006 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <stdarg.h>
13 #include <unistd.h>
14
15 #include "pciutils.h"
16
17 static int force;                       /* Don't complain if no devices match */
18 static int verbose;                     /* Verbosity level */
19 static int demo_mode;                   /* Only show */
20
21 const char program_name[] = "setpci";
22
23 static struct pci_access *pacc;
24
25 struct value {
26   unsigned int value;
27   unsigned int mask;
28 };
29
30 struct op {
31   struct op *next;
32   struct pci_dev **dev_vector;
33   unsigned int addr;
34   unsigned int width;                   /* Byte width of the access */
35   int num_values;                       /* Number of values to write; <0=read */
36   struct value values[0];
37 };
38
39 static struct op *first_op, **last_op = &first_op;
40 static unsigned int max_values[] = { 0, 0xff, 0xffff, 0, 0xffffffff };
41
42 static struct pci_dev **
43 select_devices(struct pci_filter *filt)
44 {
45   struct pci_dev *z, **a, **b;
46   int cnt = 1;
47
48   for(z=pacc->devices; z; z=z->next)
49     if (pci_filter_match(filt, z))
50       cnt++;
51   a = b = xmalloc(sizeof(struct device *) * cnt);
52   for(z=pacc->devices; z; z=z->next)
53     if (pci_filter_match(filt, z))
54       *a++ = z;
55   *a = NULL;
56   return b;
57 }
58
59 static void
60 exec_op(struct op *op, struct pci_dev *dev)
61 {
62   char *formats[] = { NULL, "%02x", "%04x", NULL, "%08x" };
63   char *mask_formats[] = { NULL, "%02x->(%02x:%02x)->%02x", "%04x->(%04x:%04x)->%04x", NULL, "%08x->(%08x:%08x)->%08x" };
64   unsigned int x, y;
65   int i, addr;
66   int width = op->width;
67
68   if (verbose)
69     printf("%02x:%02x.%x:%02x", dev->bus, dev->dev, dev->func, op->addr);
70   addr = op->addr;
71   if (op->num_values >= 0)
72     {
73       for(i=0; i<op->num_values; i++)
74         {
75           if ((op->values[i].mask & max_values[width]) == max_values[width])
76             {
77               x = op->values[i].value;
78               if (verbose)
79                 {
80                   putchar(' ');
81                   printf(formats[width], op->values[i].value);
82                 }
83             }
84           else
85             {
86               switch (width)
87                 {
88                 case 1:
89                   y = pci_read_byte(dev, addr);
90                   break;
91                 case 2:
92                   y = pci_read_word(dev, addr);
93                   break;
94                 default:
95                   y = pci_read_long(dev, addr);
96                   break;
97                 }
98               x = (y & ~op->values[i].mask) | op->values[i].value;
99               if (verbose)
100                 {
101                   putchar(' ');
102                   printf(mask_formats[width], y, op->values[i].value, op->values[i].mask, x);
103                 }
104             }
105           if (!demo_mode)
106             {
107               switch (width)
108                 {
109                 case 1:
110                   pci_write_byte(dev, addr, x);
111                   break;
112                 case 2:
113                   pci_write_word(dev, addr, x);
114                   break;
115                 default:
116                   pci_write_long(dev, addr, x);
117                   break;
118                 }
119             }
120           addr += width;
121         }
122       if (verbose)
123         putchar('\n');
124     }
125   else
126     {
127       if (verbose)
128         printf(" = ");
129       switch (width)
130         {
131         case 1:
132           x = pci_read_byte(dev, addr);
133           break;
134         case 2:
135           x = pci_read_word(dev, addr);
136           break;
137         default:
138           x = pci_read_long(dev, addr);
139           break;
140         }
141       printf(formats[width], x);
142       putchar('\n');
143     }
144 }
145
146 static void
147 execute(struct op *op)
148 {
149   struct pci_dev **vec = NULL;
150   struct pci_dev **pdev, *dev;
151   struct op *oops;
152
153   while (op)
154     {
155       pdev = vec = op->dev_vector;
156       while (dev = *pdev++)
157         for(oops=op; oops && oops->dev_vector == vec; oops=oops->next)
158           exec_op(oops, dev);
159       while (op && op->dev_vector == vec)
160         op = op->next;
161     }
162 }
163
164 static void
165 scan_ops(struct op *op)
166 {
167   while (op)
168     {
169       if (op->num_values >= 0)
170         pacc->writeable = 1;
171       op = op->next;
172     }
173 }
174
175 struct reg_name {
176   unsigned int offset;
177   unsigned int width;
178   const char *name;
179 };
180
181 static const struct reg_name pci_reg_names[] = {
182   { 0x00, 2, "VENDOR_ID", },
183   { 0x02, 2, "DEVICE_ID", },
184   { 0x04, 2, "COMMAND", },
185   { 0x06, 2, "STATUS", },
186   { 0x08, 1, "REVISION", },
187   { 0x09, 1, "CLASS_PROG", },
188   { 0x0a, 2, "CLASS_DEVICE", },
189   { 0x0c, 1, "CACHE_LINE_SIZE", },
190   { 0x0d, 1, "LATENCY_TIMER", },
191   { 0x0e, 1, "HEADER_TYPE", },
192   { 0x0f, 1, "BIST", },
193   { 0x10, 4, "BASE_ADDRESS_0", },
194   { 0x14, 4, "BASE_ADDRESS_1", },
195   { 0x18, 4, "BASE_ADDRESS_2", },
196   { 0x1c, 4, "BASE_ADDRESS_3", },
197   { 0x20, 4, "BASE_ADDRESS_4", },
198   { 0x24, 4, "BASE_ADDRESS_5", },
199   { 0x28, 4, "CARDBUS_CIS", },
200   { 0x2c, 4, "SUBSYSTEM_VENDOR_ID", },
201   { 0x2e, 2, "SUBSYSTEM_ID", },
202   { 0x30, 4, "ROM_ADDRESS", },
203   { 0x3c, 1, "INTERRUPT_LINE", },
204   { 0x3d, 1, "INTERRUPT_PIN", },
205   { 0x3e, 1, "MIN_GNT", },
206   { 0x3f, 1, "MAX_LAT", },
207   { 0x18, 1, "PRIMARY_BUS", },
208   { 0x19, 1, "SECONDARY_BUS", },
209   { 0x1a, 1, "SUBORDINATE_BUS", },
210   { 0x1b, 1, "SEC_LATENCY_TIMER", },
211   { 0x1c, 1, "IO_BASE", },
212   { 0x1d, 1, "IO_LIMIT", },
213   { 0x1e, 2, "SEC_STATUS", },
214   { 0x20, 2, "MEMORY_BASE", },
215   { 0x22, 2, "MEMORY_LIMIT", },
216   { 0x24, 2, "PREF_MEMORY_BASE", },
217   { 0x26, 2, "PREF_MEMORY_LIMIT", },
218   { 0x28, 4, "PREF_BASE_UPPER32", },
219   { 0x2c, 4, "PREF_LIMIT_UPPER32", },
220   { 0x30, 2, "IO_BASE_UPPER16", },
221   { 0x32, 2, "IO_LIMIT_UPPER16", },
222   { 0x38, 4, "BRIDGE_ROM_ADDRESS", },
223   { 0x3e, 2, "BRIDGE_CONTROL", },
224   { 0x10, 4, "CB_CARDBUS_BASE", },
225   { 0x14, 2, "CB_CAPABILITIES", },
226   { 0x16, 2, "CB_SEC_STATUS", },
227   { 0x18, 1, "CB_BUS_NUMBER", },
228   { 0x19, 1, "CB_CARDBUS_NUMBER", },
229   { 0x1a, 1, "CB_SUBORDINATE_BUS", },
230   { 0x1b, 1, "CB_CARDBUS_LATENCY", },
231   { 0x1c, 4, "CB_MEMORY_BASE_0", },
232   { 0x20, 4, "CB_MEMORY_LIMIT_0", },
233   { 0x24, 4, "CB_MEMORY_BASE_1", },
234   { 0x28, 4, "CB_MEMORY_LIMIT_1", },
235   { 0x2c, 2, "CB_IO_BASE_0", },
236   { 0x2e, 2, "CB_IO_BASE_0_HI", },
237   { 0x30, 2, "CB_IO_LIMIT_0", },
238   { 0x32, 2, "CB_IO_LIMIT_0_HI", },
239   { 0x34, 2, "CB_IO_BASE_1", },
240   { 0x36, 2, "CB_IO_BASE_1_HI", },
241   { 0x38, 2, "CB_IO_LIMIT_1", },
242   { 0x3a, 2, "CB_IO_LIMIT_1_HI", },
243   { 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID", },
244   { 0x42, 2, "CB_SUBSYSTEM_ID", },
245   { 0x44, 4, "CB_LEGACY_MODE_BASE", },
246   { 0x00, 0, NULL }
247 };
248
249 static void NONRET PCI_PRINTF(1,2)
250 usage(char *msg, ...)
251 {
252   va_list args;
253   va_start(args, msg);
254   if (msg)
255     {
256       fprintf(stderr, "setpci: ");
257       vfprintf(stderr, msg, args);
258       fprintf(stderr, "\n\n");
259     }
260   fprintf(stderr,
261 "Usage: setpci [<options>] (<device>+ <reg>[=<values>]*)*\n"
262 "-f\t\tDon't complain if there's nothing to do\n"
263 "-v\t\tBe verbose\n"
264 "-D\t\tList changes, don't commit them\n"
265 GENERIC_HELP
266 "<device>:\t-s [[[<domain>]:][<bus>]:][<slot>][.[<func>]]\n"
267 "\t|\t-d [<vendor>]:[<device>]\n"
268 "<reg>:\t\t<number>[.(B|W|L)]\n"
269 "     |\t\t<name>\n"
270 "<values>:\t<value>[,<value>...]\n"
271 "<value>:\t<hex>\n"
272 "       |\t<hex>:<mask>\n");
273   exit(1);
274 }
275
276 int
277 main(int argc, char **argv)
278 {
279   enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
280   struct pci_filter filter;
281   struct pci_dev **selected_devices = NULL;
282   char *opts = GENERIC_OPTIONS ;
283
284   if (argc == 2 && !strcmp(argv[1], "--version"))
285     {
286       puts("setpci version " PCIUTILS_VERSION);
287       return 0;
288     }
289   argc--;
290   argv++;
291
292   pacc = pci_alloc();
293   pacc->error = die;
294
295   while (argc && argv[0][0] == '-')
296     {
297       char *c = argv[0]+1;
298       char *d = c;
299       char *e;
300       while (*c)
301         switch (*c)
302           {
303           case 'v':
304             verbose++;
305             c++;
306             break;
307           case 'f':
308             force++;
309             c++;
310             break;
311           case 'D':
312             demo_mode++;
313             c++;
314             break;
315           case 0:
316             break;
317           default:
318             if (e = strchr(opts, *c))
319               {
320                 char *arg;
321                 c++;
322                 if (e[1] == ':')
323                   {
324                     if (*c)
325                       arg = c;
326                     else if (argc > 1)
327                       {
328                         arg = argv[1];
329                         argc--; argv++;
330                       }
331                     else
332                       usage(NULL);
333                     c = "";
334                   }
335                 else
336                   arg = NULL;
337                 if (!parse_generic_option(*e, pacc, arg))
338                   usage(NULL);
339               }
340             else
341               {
342                 if (c != d)
343                   usage(NULL);
344                 goto next;
345               }
346           }
347       argc--;
348       argv++;
349     }
350 next:
351
352   pci_init(pacc);
353   pci_scan_bus(pacc);
354
355   while (argc)
356     {
357       char *c = argv[0];
358       char *d, *e, *f;
359       int n, i;
360       struct op *op;
361       unsigned long ll;
362       unsigned int lim;
363
364       if (*c == '-')
365         {
366           if (!c[1] || !strchr("sd", c[1]))
367             usage(NULL);
368           if (c[2])
369             d = (c[2] == '=') ? c+3 : c+2;
370           else if (argc > 1)
371             {
372               argc--;
373               argv++;
374               d = argv[0];
375             }
376           else
377             usage(NULL);
378           if (state != STATE_GOT_FILTER)
379             {
380               pci_filter_init(pacc, &filter);
381               state = STATE_GOT_FILTER;
382             }
383           switch (c[1])
384             {
385             case 's':
386               if (d = pci_filter_parse_slot(&filter, d))
387                 die("-s: %s", d);
388               break;
389             case 'd':
390               if (d = pci_filter_parse_id(&filter, d))
391                 die("-d: %s", d);
392               break;
393             default:
394               usage(NULL);
395             }
396         }
397       else if (state == STATE_INIT)
398         usage(NULL);
399       else
400         {
401           if (state == STATE_GOT_FILTER)
402             selected_devices = select_devices(&filter);
403           if (!selected_devices[0] && !force)
404             fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c);
405           state = STATE_GOT_OP;
406           /* look for setting of values and count how many */
407           d = strchr(c, '=');
408           if (d)
409             {
410               *d++ = 0;
411               if (!*d)
412                 usage("Missing value");
413               for(e=d, n=1; *e; e++)
414                 if (*e == ',')
415                   n++;
416               op = xmalloc(sizeof(struct op) + n*sizeof(struct value));
417             }
418           else
419             {
420               n = -1;
421               op = xmalloc(sizeof(struct op));
422             }
423           op->dev_vector = selected_devices;
424           op->num_values = n;
425           e = strchr(c, '.');
426           if (e)
427             {
428               *e++ = 0;
429               if (e[1])
430                 usage("Missing width");
431               switch (*e & 0xdf)
432                 {
433                 case 'B':
434                   op->width = 1; break;
435                 case 'W':
436                   op->width = 2; break;
437                 case 'L':
438                   op->width = 4; break;
439                 default:
440                   usage("Invalid width \"%c\"", *e);
441                 }
442             }
443           else
444             op->width = 1;
445           ll = strtol(c, &f, 16);
446           if (f && *f)
447             {
448               const struct reg_name *r;
449               for(r = pci_reg_names; r->name; r++)
450                 if (!strcasecmp(r->name, c))
451                   break;
452               if (!r->name)
453                 usage("Unknown register \"%s\"", c);
454               if (e && op->width != r->width)
455                 usage("Explicit width doesn't correspond with the named register \"%s\"", c);
456               ll = r->offset;
457               op->width = r->width;
458             }
459           if (ll > 0x1000 || ll + op->width*((n < 0) ? 1 : n) > 0x1000)
460             die("Register number out of range!");
461           if (ll & (op->width - 1))
462             die("Unaligned register address!");
463           op->addr = ll;
464           /* read in all the values to be set */
465           for(i=0; i<n; i++)
466             {
467               e = strchr(d, ',');
468               if (e)
469                 *e++ = 0;
470               ll = strtoul(d, &f, 16);
471               lim = max_values[op->width];
472               if (f && *f && *f != ':')
473                 usage("Invalid value \"%s\"", d);
474               if (ll > lim && ll < ~0UL - lim)
475                 usage("Value \"%s\" is out of range", d);
476               op->values[i].value = ll;
477               if (f && *f == ':')
478                 {
479                   d = ++f;
480                   ll = strtoul(d, &f, 16);
481                   if (f && *f)
482                     usage("Invalid mask \"%s\"", d);
483                   if (ll > lim && ll < ~0UL - lim)
484                     usage("Mask \"%s\" is out of range", d);
485                   op->values[i].mask = ll;
486                   op->values[i].value &= ll;
487                 }
488               else
489                 op->values[i].mask = ~0U;
490               d = e;
491             }
492           *last_op = op;
493           last_op = &op->next;
494           op->next = NULL;
495         }
496       argc--;
497       argv++;
498     }
499   if (state == STATE_INIT)
500     usage("No operation specified");
501
502   scan_ops(first_op);
503   execute(first_op);
504
505   return 0;
506 }