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