]> mj.ucw.cz Git - pciutils.git/blob - setpci.c
Introduced NONRET macro
[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 NONRET
253 usage(void)
254 {
255   fprintf(stderr,
256 "Usage: setpci [<options>] (<device>+ <reg>[=<values>]*)*\n\
257 -f\t\tDon't complain if there's nothing to do\n\
258 -v\t\tBe verbose\n\
259 -D\t\tList changes, don't commit them\n"
260 GENERIC_HELP
261 "<device>:\t-s [[<bus>]:][<slot>][.[<func>]]\n"
262 "\t|\t-d [<vendor>]:[<device>]\n"
263 "<reg>:\t\t<number>[.(B|W|L)]\n"
264 "     |\t\t<name>\n"
265 "<values>:\t<value>[,<value>...]\n"
266 "<value>:\t<hex>\n"
267 "       |\t<hex>:<mask>\n");
268   exit(1);
269 }
270
271 int
272 main(int argc, char **argv)
273 {
274   enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
275   struct pci_filter filter;
276   struct pci_dev **selected_devices = NULL;
277   char *opts = GENERIC_OPTIONS ;
278
279   if (argc == 2 && !strcmp(argv[1], "--version"))
280     {
281       puts("setpci version " PCIUTILS_VERSION);
282       return 0;
283     }
284   argc--;
285   argv++;
286
287   pacc = pci_alloc();
288   pacc->error = die;
289
290   while (argc && argv[0][0] == '-')
291     {
292       char *c = argv[0]+1;
293       char *d = c;
294       char *e;
295       while (*c)
296         switch (*c)
297           {
298           case 'v':
299             verbose++;
300             c++;
301             break;
302           case 'f':
303             force++;
304             c++;
305             break;
306           case 'D':
307             demo_mode++;
308             c++;
309             break;
310           case 0:
311             break;
312           default:
313             if (e = strchr(opts, *c))
314               {
315                 char *arg;
316                 c++;
317                 if (e[1] == ':')
318                   {
319                     if (*c)
320                       arg = c;
321                     else if (argc > 1)
322                       {
323                         arg = argv[1];
324                         argc--; argv++;
325                       }
326                     else
327                       usage();
328                     c = "";
329                   }
330                 else
331                   arg = NULL;
332                 if (!parse_generic_option(*e, pacc, arg))
333                   usage();
334               }
335             else
336               {
337                 if (c != d)
338                   usage();
339                 goto next;
340               }
341           }
342       argc--;
343       argv++;
344     }
345 next:
346
347   pci_init(pacc);
348   pci_scan_bus(pacc);
349
350   while (argc)
351     {
352       char *c = argv[0];
353       char *d, *e, *f;
354       int n, i;
355       struct op *op;
356       unsigned long ll;
357       unsigned int lim;
358
359       if (*c == '-')
360         {
361           if (!c[1] || !strchr("sd", c[1]))
362             usage();
363           if (c[2])
364             d = (c[2] == '=') ? c+3 : c+2;
365           else if (argc > 1)
366             {
367               argc--;
368               argv++;
369               d = argv[0];
370             }
371           else
372             usage();
373           if (state != STATE_GOT_FILTER)
374             {
375               pci_filter_init(pacc, &filter);
376               state = STATE_GOT_FILTER;
377             }
378           switch (c[1])
379             {
380             case 's':
381               if (d = pci_filter_parse_slot(&filter, d))
382                 die("-s: %s", d);
383               break;
384             case 'd':
385               if (d = pci_filter_parse_id(&filter, d))
386                 die("-d: %s", d);
387               break;
388             default:
389               usage();
390             }
391         }
392       else if (state == STATE_INIT)
393         usage();
394       else
395         {
396           if (state == STATE_GOT_FILTER)
397             selected_devices = select_devices(&filter);
398           if (!selected_devices[0] && !force)
399             fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c);
400           state = STATE_GOT_OP;
401           /* look for setting of values and count how many */
402           d = strchr(c, '=');
403           if (d)
404             {
405               *d++ = 0;
406               if (!*d)
407                 usage();
408               for(e=d, n=1; *e; e++)
409                 if (*e == ',')
410                   n++;
411               op = xmalloc(sizeof(struct op) + n*sizeof(struct value));
412             }
413           else
414             {
415               n = -1;
416               op = xmalloc(sizeof(struct op));
417             }
418           op->dev_vector = selected_devices;
419           op->num_values = n;
420           e = strchr(c, '.');
421           if (e)
422             {
423               *e++ = 0;
424               if (e[1])
425                 usage();
426               switch (*e & 0xdf)
427                 {
428                 case 'B':
429                   op->width = 1; break;
430                 case 'W':
431                   op->width = 2; break;
432                 case 'L':
433                   op->width = 4; break;
434                 default:
435                   usage();
436                 }
437             }
438           else
439             op->width = 1;
440           ll = strtol(c, &f, 16);
441           if (f && *f)
442             {
443               const struct reg_name *r;
444               for(r = pci_reg_names; r->name; r++)
445                 if (!strcasecmp(r->name, c))
446                   break;
447               if (!r->name || e)
448                 usage();
449               ll = r->offset;
450               op->width = r->width;
451             }
452           if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100)
453             die("Register number out of range!");
454           if (ll & (op->width - 1))
455             die("Unaligned register address!");
456           op->addr = ll;
457           /* read in all the values to be set */
458           for(i=0; i<n; i++)
459             {
460               e = strchr(d, ',');
461               if (e)
462                 *e++ = 0;
463               ll = strtoul(d, &f, 16);
464               lim = max_values[op->width];
465               if (f && *f && (*f != ':') ||
466                   (ll > lim && ll < ~0UL - lim))
467                 {
468                   fprintf(stderr, "bad value \"%s\"\n\n", d);
469                   usage();
470                 }
471               if (f && *f == ':')
472                 {
473                   op->values[i].value = ll;
474                   d = ++f;
475                   ll = strtoul(d, &f, 16);
476                   if (f && *f ||
477                       (ll > lim && ll < ~0UL - lim))
478                     {
479                       fprintf(stderr, "bad value:mask pair \"%s\"\n\n", d);
480                       usage();
481                     }
482                   op->values[i].mask = ll;
483                   op->values[i].value &= op->values[i].mask;
484                 }
485               else
486                 {
487                   op->values[i].value = ll;
488                   op->values[i].mask = ~0U;
489                 }
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();
501
502   scan_ops(first_op);
503   execute(first_op);
504
505   return 0;
506 }