~ubuntu-branches/ubuntu/precise/pciutils/precise

« back to all changes in this revision

Viewing changes to setpci.c

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar
  • Date: 2010-06-26 14:17:57 UTC
  • mfrom: (2.1.18 sid)
  • Revision ID: james.westby@ubuntu.com-20100626141757-xsp7xqv15qotwels
Tags: 1:3.1.7-4
Update pci.ids with snapshot dated 2010-06-12

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
#include <stdlib.h>
12
12
#include <stdarg.h>
13
13
#include <unistd.h>
 
14
#include <errno.h>
14
15
 
15
16
#define PCIUTILS_SETPCI
16
17
#include "pciutils.h"
31
32
struct op {
32
33
  struct op *next;
33
34
  struct pci_dev **dev_vector;
 
35
  u16 cap_type;                         /* PCI_CAP_xxx or 0 */
 
36
  u16 cap_id;
34
37
  unsigned int addr;
35
38
  unsigned int width;                   /* Byte width of the access */
36
 
  int num_values;                       /* Number of values to write; <0=read */
 
39
  unsigned int num_values;              /* Number of values to write; 0=read */
37
40
  struct value values[0];
38
41
};
39
42
 
46
49
  struct pci_dev *z, **a, **b;
47
50
  int cnt = 1;
48
51
 
49
 
  for(z=pacc->devices; z; z=z->next)
 
52
  for (z=pacc->devices; z; z=z->next)
50
53
    if (pci_filter_match(filt, z))
51
54
      cnt++;
52
55
  a = b = xmalloc(sizeof(struct device *) * cnt);
53
 
  for(z=pacc->devices; z; z=z->next)
 
56
  for (z=pacc->devices; z; z=z->next)
54
57
    if (pci_filter_match(filt, z))
55
58
      *a++ = z;
56
59
  *a = NULL;
57
60
  return b;
58
61
}
59
62
 
 
63
static void PCI_PRINTF(1,2)
 
64
trace(const char *fmt, ...)
 
65
{
 
66
  va_list args;
 
67
  va_start(args, fmt);
 
68
  if (verbose)
 
69
    vprintf(fmt, args);
 
70
  va_end(args);
 
71
}
 
72
 
60
73
static void
61
74
exec_op(struct op *op, struct pci_dev *dev)
62
75
{
63
 
  char *formats[] = { NULL, "%02x", "%04x", NULL, "%08x" };
64
 
  char *mask_formats[] = { NULL, "%02x->(%02x:%02x)->%02x", "%04x->(%04x:%04x)->%04x", NULL, "%08x->(%08x:%08x)->%08x" };
65
 
  unsigned int x, y;
66
 
  int i, addr;
 
76
  const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x" };
 
77
  const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x" };
 
78
  unsigned int i, x, y;
 
79
  int addr = 0;
67
80
  int width = op->width;
68
 
 
69
 
  if (verbose)
70
 
    printf("%02x:%02x.%x:%02x", dev->bus, dev->dev, dev->func, op->addr);
71
 
  addr = op->addr;
72
 
  if (op->num_values >= 0)
73
 
    {
74
 
      for(i=0; i<op->num_values; i++)
 
81
  char slot[16];
 
82
 
 
83
  sprintf(slot, "%04x:%02x:%02x.%x", dev->domain, dev->bus, dev->dev, dev->func);
 
84
  trace("%s ", slot);
 
85
  if (op->cap_type)
 
86
    {
 
87
      struct pci_cap *cap;
 
88
      cap = pci_find_cap(dev, op->cap_id, op->cap_type);
 
89
      if (cap)
 
90
        addr = cap->addr;
 
91
      else
 
92
        die("%s: %s %04x not found", slot, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), op->cap_id);
 
93
      trace(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x @%02x) " : "(ecap %04x @%03x) "), op->cap_id, addr);
 
94
    }
 
95
  addr += op->addr;
 
96
  trace("@%02x", addr);
 
97
 
 
98
  /* We have already checked it when parsing, but addressing relative to capabilities can change the address. */
 
99
  if (addr & (width-1))
 
100
    die("%s: Unaligned access of width %d to register %04x", slot, width, addr);
 
101
  if (addr + width > 0x1000)
 
102
    die("%s: Access of width %d to register %04x out of range", slot, width, addr);
 
103
 
 
104
  if (op->num_values)
 
105
    {
 
106
      for (i=0; i<op->num_values; i++)
75
107
        {
76
108
          if ((op->values[i].mask & max_values[width]) == max_values[width])
77
109
            {
78
110
              x = op->values[i].value;
79
 
              if (verbose)
80
 
                {
81
 
                  putchar(' ');
82
 
                  printf(formats[width], op->values[i].value);
83
 
                }
 
111
              trace(formats[width], op->values[i].value);
84
112
            }
85
113
          else
86
114
            {
97
125
                  break;
98
126
                }
99
127
              x = (y & ~op->values[i].mask) | op->values[i].value;
100
 
              if (verbose)
101
 
                {
102
 
                  putchar(' ');
103
 
                  printf(mask_formats[width], y, op->values[i].value, op->values[i].mask, x);
104
 
                }
 
128
              trace(mask_formats[width], y, op->values[i].value, op->values[i].mask, x);
105
129
            }
106
130
          if (!demo_mode)
107
131
            {
120
144
            }
121
145
          addr += width;
122
146
        }
123
 
      if (verbose)
124
 
        putchar('\n');
 
147
      trace("\n");
125
148
    }
126
149
  else
127
150
    {
128
 
      if (verbose)
129
 
        printf(" = ");
 
151
      trace(" = ");
130
152
      switch (width)
131
153
        {
132
154
        case 1:
139
161
          x = pci_read_long(dev, addr);
140
162
          break;
141
163
        }
142
 
      printf(formats[width], x);
 
164
      printf(formats[width]+1, x);
143
165
      putchar('\n');
144
166
    }
145
167
}
155
177
    {
156
178
      pdev = vec = op->dev_vector;
157
179
      while (dev = *pdev++)
158
 
        for(oops=op; oops && oops->dev_vector == vec; oops=oops->next)
 
180
        for (oops=op; oops && oops->dev_vector == vec; oops=oops->next)
159
181
          exec_op(oops, dev);
160
182
      while (op && op->dev_vector == vec)
161
183
        op = op->next;
165
187
static void
166
188
scan_ops(struct op *op)
167
189
{
 
190
  if (demo_mode)
 
191
    return;
168
192
  while (op)
169
193
    {
170
 
      if (op->num_values >= 0)
 
194
      if (op->num_values)
171
195
        pacc->writeable = 1;
172
196
      op = op->next;
173
197
    }
174
198
}
175
199
 
176
200
struct reg_name {
 
201
  unsigned int cap;
177
202
  unsigned int offset;
178
203
  unsigned int width;
179
204
  const char *name;
180
205
};
181
206
 
182
207
static const struct reg_name pci_reg_names[] = {
183
 
  { 0x00, 2, "VENDOR_ID", },
184
 
  { 0x02, 2, "DEVICE_ID", },
185
 
  { 0x04, 2, "COMMAND", },
186
 
  { 0x06, 2, "STATUS", },
187
 
  { 0x08, 1, "REVISION", },
188
 
  { 0x09, 1, "CLASS_PROG", },
189
 
  { 0x0a, 2, "CLASS_DEVICE", },
190
 
  { 0x0c, 1, "CACHE_LINE_SIZE", },
191
 
  { 0x0d, 1, "LATENCY_TIMER", },
192
 
  { 0x0e, 1, "HEADER_TYPE", },
193
 
  { 0x0f, 1, "BIST", },
194
 
  { 0x10, 4, "BASE_ADDRESS_0", },
195
 
  { 0x14, 4, "BASE_ADDRESS_1", },
196
 
  { 0x18, 4, "BASE_ADDRESS_2", },
197
 
  { 0x1c, 4, "BASE_ADDRESS_3", },
198
 
  { 0x20, 4, "BASE_ADDRESS_4", },
199
 
  { 0x24, 4, "BASE_ADDRESS_5", },
200
 
  { 0x28, 4, "CARDBUS_CIS", },
201
 
  { 0x2c, 4, "SUBSYSTEM_VENDOR_ID", },
202
 
  { 0x2e, 2, "SUBSYSTEM_ID", },
203
 
  { 0x30, 4, "ROM_ADDRESS", },
204
 
  { 0x3c, 1, "INTERRUPT_LINE", },
205
 
  { 0x3d, 1, "INTERRUPT_PIN", },
206
 
  { 0x3e, 1, "MIN_GNT", },
207
 
  { 0x3f, 1, "MAX_LAT", },
208
 
  { 0x18, 1, "PRIMARY_BUS", },
209
 
  { 0x19, 1, "SECONDARY_BUS", },
210
 
  { 0x1a, 1, "SUBORDINATE_BUS", },
211
 
  { 0x1b, 1, "SEC_LATENCY_TIMER", },
212
 
  { 0x1c, 1, "IO_BASE", },
213
 
  { 0x1d, 1, "IO_LIMIT", },
214
 
  { 0x1e, 2, "SEC_STATUS", },
215
 
  { 0x20, 2, "MEMORY_BASE", },
216
 
  { 0x22, 2, "MEMORY_LIMIT", },
217
 
  { 0x24, 2, "PREF_MEMORY_BASE", },
218
 
  { 0x26, 2, "PREF_MEMORY_LIMIT", },
219
 
  { 0x28, 4, "PREF_BASE_UPPER32", },
220
 
  { 0x2c, 4, "PREF_LIMIT_UPPER32", },
221
 
  { 0x30, 2, "IO_BASE_UPPER16", },
222
 
  { 0x32, 2, "IO_LIMIT_UPPER16", },
223
 
  { 0x38, 4, "BRIDGE_ROM_ADDRESS", },
224
 
  { 0x3e, 2, "BRIDGE_CONTROL", },
225
 
  { 0x10, 4, "CB_CARDBUS_BASE", },
226
 
  { 0x14, 2, "CB_CAPABILITIES", },
227
 
  { 0x16, 2, "CB_SEC_STATUS", },
228
 
  { 0x18, 1, "CB_BUS_NUMBER", },
229
 
  { 0x19, 1, "CB_CARDBUS_NUMBER", },
230
 
  { 0x1a, 1, "CB_SUBORDINATE_BUS", },
231
 
  { 0x1b, 1, "CB_CARDBUS_LATENCY", },
232
 
  { 0x1c, 4, "CB_MEMORY_BASE_0", },
233
 
  { 0x20, 4, "CB_MEMORY_LIMIT_0", },
234
 
  { 0x24, 4, "CB_MEMORY_BASE_1", },
235
 
  { 0x28, 4, "CB_MEMORY_LIMIT_1", },
236
 
  { 0x2c, 2, "CB_IO_BASE_0", },
237
 
  { 0x2e, 2, "CB_IO_BASE_0_HI", },
238
 
  { 0x30, 2, "CB_IO_LIMIT_0", },
239
 
  { 0x32, 2, "CB_IO_LIMIT_0_HI", },
240
 
  { 0x34, 2, "CB_IO_BASE_1", },
241
 
  { 0x36, 2, "CB_IO_BASE_1_HI", },
242
 
  { 0x38, 2, "CB_IO_LIMIT_1", },
243
 
  { 0x3a, 2, "CB_IO_LIMIT_1_HI", },
244
 
  { 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID", },
245
 
  { 0x42, 2, "CB_SUBSYSTEM_ID", },
246
 
  { 0x44, 4, "CB_LEGACY_MODE_BASE", },
247
 
  { 0x00, 0, NULL }
 
208
  {       0, 0x00, 2, "VENDOR_ID" },
 
209
  {       0, 0x02, 2, "DEVICE_ID" },
 
210
  {       0, 0x04, 2, "COMMAND" },
 
211
  {       0, 0x06, 2, "STATUS" },
 
212
  {       0, 0x08, 1, "REVISION" },
 
213
  {       0, 0x09, 1, "CLASS_PROG" },
 
214
  {       0, 0x0a, 2, "CLASS_DEVICE" },
 
215
  {       0, 0x0c, 1, "CACHE_LINE_SIZE" },
 
216
  {       0, 0x0d, 1, "LATENCY_TIMER" },
 
217
  {       0, 0x0e, 1, "HEADER_TYPE" },
 
218
  {       0, 0x0f, 1, "BIST" },
 
219
  {       0, 0x10, 4, "BASE_ADDRESS_0" },
 
220
  {       0, 0x14, 4, "BASE_ADDRESS_1" },
 
221
  {       0, 0x18, 4, "BASE_ADDRESS_2" },
 
222
  {       0, 0x1c, 4, "BASE_ADDRESS_3" },
 
223
  {       0, 0x20, 4, "BASE_ADDRESS_4" },
 
224
  {       0, 0x24, 4, "BASE_ADDRESS_5" },
 
225
  {       0, 0x28, 4, "CARDBUS_CIS" },
 
226
  {       0, 0x2c, 4, "SUBSYSTEM_VENDOR_ID" },
 
227
  {       0, 0x2e, 2, "SUBSYSTEM_ID" },
 
228
  {       0, 0x30, 4, "ROM_ADDRESS" },
 
229
  {       0, 0x3c, 1, "INTERRUPT_LINE" },
 
230
  {       0, 0x3d, 1, "INTERRUPT_PIN" },
 
231
  {       0, 0x3e, 1, "MIN_GNT" },
 
232
  {       0, 0x3f, 1, "MAX_LAT" },
 
233
  {       0, 0x18, 1, "PRIMARY_BUS" },
 
234
  {       0, 0x19, 1, "SECONDARY_BUS" },
 
235
  {       0, 0x1a, 1, "SUBORDINATE_BUS" },
 
236
  {       0, 0x1b, 1, "SEC_LATENCY_TIMER" },
 
237
  {       0, 0x1c, 1, "IO_BASE" },
 
238
  {       0, 0x1d, 1, "IO_LIMIT" },
 
239
  {       0, 0x1e, 2, "SEC_STATUS" },
 
240
  {       0, 0x20, 2, "MEMORY_BASE" },
 
241
  {       0, 0x22, 2, "MEMORY_LIMIT" },
 
242
  {       0, 0x24, 2, "PREF_MEMORY_BASE" },
 
243
  {       0, 0x26, 2, "PREF_MEMORY_LIMIT" },
 
244
  {       0, 0x28, 4, "PREF_BASE_UPPER32" },
 
245
  {       0, 0x2c, 4, "PREF_LIMIT_UPPER32" },
 
246
  {       0, 0x30, 2, "IO_BASE_UPPER16" },
 
247
  {       0, 0x32, 2, "IO_LIMIT_UPPER16" },
 
248
  {       0, 0x38, 4, "BRIDGE_ROM_ADDRESS" },
 
249
  {       0, 0x3e, 2, "BRIDGE_CONTROL" },
 
250
  {       0, 0x10, 4, "CB_CARDBUS_BASE" },
 
251
  {       0, 0x14, 2, "CB_CAPABILITIES" },
 
252
  {       0, 0x16, 2, "CB_SEC_STATUS" },
 
253
  {       0, 0x18, 1, "CB_BUS_NUMBER" },
 
254
  {       0, 0x19, 1, "CB_CARDBUS_NUMBER" },
 
255
  {       0, 0x1a, 1, "CB_SUBORDINATE_BUS" },
 
256
  {       0, 0x1b, 1, "CB_CARDBUS_LATENCY" },
 
257
  {       0, 0x1c, 4, "CB_MEMORY_BASE_0" },
 
258
  {       0, 0x20, 4, "CB_MEMORY_LIMIT_0" },
 
259
  {       0, 0x24, 4, "CB_MEMORY_BASE_1" },
 
260
  {       0, 0x28, 4, "CB_MEMORY_LIMIT_1" },
 
261
  {       0, 0x2c, 2, "CB_IO_BASE_0" },
 
262
  {       0, 0x2e, 2, "CB_IO_BASE_0_HI" },
 
263
  {       0, 0x30, 2, "CB_IO_LIMIT_0" },
 
264
  {       0, 0x32, 2, "CB_IO_LIMIT_0_HI" },
 
265
  {       0, 0x34, 2, "CB_IO_BASE_1" },
 
266
  {       0, 0x36, 2, "CB_IO_BASE_1_HI" },
 
267
  {       0, 0x38, 2, "CB_IO_LIMIT_1" },
 
268
  {       0, 0x3a, 2, "CB_IO_LIMIT_1_HI" },
 
269
  {       0, 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID" },
 
270
  {       0, 0x42, 2, "CB_SUBSYSTEM_ID" },
 
271
  {       0, 0x44, 4, "CB_LEGACY_MODE_BASE" },
 
272
  { 0x10001,    0, 0, "CAP_PM" },
 
273
  { 0x10002,    0, 0, "CAP_AGP" },
 
274
  { 0x10003,    0, 0, "CAP_VPD" },
 
275
  { 0x10004,    0, 0, "CAP_SLOTID" },
 
276
  { 0x10005,    0, 0, "CAP_MSI" },
 
277
  { 0x10006,    0, 0, "CAP_CHSWP" },
 
278
  { 0x10007,    0, 0, "CAP_PCIX" },
 
279
  { 0x10008,    0, 0, "CAP_HT" },
 
280
  { 0x10009,    0, 0, "CAP_VNDR" },
 
281
  { 0x1000a,    0, 0, "CAP_DBG" },
 
282
  { 0x1000b,    0, 0, "CAP_CCRC" },
 
283
  { 0x1000c,    0, 0, "CAP_HOTPLUG" },
 
284
  { 0x1000d,    0, 0, "CAP_SSVID" },
 
285
  { 0x1000e,    0, 0, "CAP_AGP3" },
 
286
  { 0x1000f,    0, 0, "CAP_SECURE" },
 
287
  { 0x10010,    0, 0, "CAP_EXP" },
 
288
  { 0x10011,    0, 0, "CAP_MSIX" },
 
289
  { 0x10012,    0, 0, "CAP_SATA" },
 
290
  { 0x10013,    0, 0, "CAP_AF" },
 
291
  { 0x20001,    0, 0, "ECAP_AER" },
 
292
  { 0x20002,    0, 0, "ECAP_VC" },
 
293
  { 0x20003,    0, 0, "ECAP_DSN" },
 
294
  { 0x20004,    0, 0, "ECAP_PB" },
 
295
  { 0x20005,    0, 0, "ECAP_RCLINK" },
 
296
  { 0x20006,    0, 0, "ECAP_RCILINK" },
 
297
  { 0x20007,    0, 0, "ECAP_RCECOLL" },
 
298
  { 0x20008,    0, 0, "ECAP_MFVC" },
 
299
  { 0x2000a,    0, 0, "ECAP_RBCB" },
 
300
  { 0x2000b,    0, 0, "ECAP_VNDR" },
 
301
  { 0x2000d,    0, 0, "ECAP_ACS" },
 
302
  { 0x2000e,    0, 0, "ECAP_ARI" },
 
303
  { 0x2000f,    0, 0, "ECAP_ATS" },
 
304
  { 0x20010,    0, 0, "ECAP_SRIOV" },
 
305
  {       0,    0, 0, NULL }
248
306
};
249
307
 
250
 
static void NONRET PCI_PRINTF(1,2)
251
 
usage(char *msg, ...)
 
308
static void
 
309
dump_registers(void)
252
310
{
253
 
  va_list args;
254
 
  va_start(args, msg);
255
 
  if (msg)
 
311
  const struct reg_name *r;
 
312
 
 
313
  printf("cap pos w name\n");
 
314
  for (r = pci_reg_names; r->name; r++)
256
315
    {
257
 
      fprintf(stderr, "setpci: ");
258
 
      vfprintf(stderr, msg, args);
259
 
      fprintf(stderr, "\n\n");
 
316
      if (r->cap >= 0x20000)
 
317
        printf("%04x", r->cap - 0x20000);
 
318
      else if (r->cap)
 
319
        printf("  %02x", r->cap - 0x10000);
 
320
      else
 
321
        printf("    ");
 
322
      printf(" %02x %c %s\n", r->offset, "-BW?L"[r->width], r->name);
260
323
    }
 
324
}
 
325
 
 
326
static void NONRET
 
327
usage(void)
 
328
{
261
329
  fprintf(stderr,
262
330
"Usage: setpci [<options>] (<device>+ <reg>[=<values>]*)*\n"
263
331
"\n"
265
333
"-f\t\tDon't complain if there's nothing to do\n"
266
334
"-v\t\tBe verbose\n"
267
335
"-D\t\tList changes, don't commit them\n"
 
336
"--dumpregs\tDump all known register names and exit\n"
268
337
"\n"
269
338
"PCI access options:\n"
270
339
GENERIC_HELP
271
340
"\n"
272
341
"Setting commands:\n"
273
342
"<device>:\t-s [[[<domain>]:][<bus>]:][<slot>][.[<func>]]\n"
274
 
"\t|\t-d [<vendor>]:[<device>]\n"
275
 
"<reg>:\t\t<number>[.(B|W|L)]\n"
276
 
"     |\t\t<name>\n"
 
343
"\t\t-d [<vendor>]:[<device>]\n"
 
344
"<reg>:\t\t<base>[+<offset>][.(B|W|L)]\n"
 
345
"<base>:\t\t<address>\n"
 
346
"\t\t<named-register>\n"
 
347
"\t\t[E]CAP_<capability-name>\n"
 
348
"\t\t[E]CAP<capability-number>\n"
277
349
"<values>:\t<value>[,<value>...]\n"
278
350
"<value>:\t<hex>\n"
279
 
"       |\t<hex>:<mask>\n");
 
351
"\t\t<hex>:<mask>\n");
 
352
  exit(0);
 
353
}
 
354
 
 
355
static void NONRET PCI_PRINTF(1,2)
 
356
parse_err(const char *msg, ...)
 
357
{
 
358
  va_list args;
 
359
  va_start(args, msg);
 
360
  fprintf(stderr, "setpci: ");
 
361
  vfprintf(stderr, msg, args);
 
362
  fprintf(stderr, ".\nTry `setpci --help' for more information.\n");
280
363
  exit(1);
281
364
}
282
365
 
283
 
int
284
 
main(int argc, char **argv)
 
366
static int
 
367
parse_options(int argc, char **argv)
285
368
{
286
 
  enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
287
 
  struct pci_filter filter;
288
 
  struct pci_dev **selected_devices = NULL;
289
 
  char *opts = GENERIC_OPTIONS ;
 
369
  const char opts[] = GENERIC_OPTIONS;
 
370
  int i=1;
290
371
 
291
 
  if (argc == 2 && !strcmp(argv[1], "--version"))
 
372
  if (argc == 2)
292
373
    {
293
 
      puts("setpci version " PCIUTILS_VERSION);
294
 
      return 0;
 
374
      if (!strcmp(argv[1], "--help"))
 
375
        usage();
 
376
      if (!strcmp(argv[1], "--version"))
 
377
        {
 
378
          puts("setpci version " PCIUTILS_VERSION);
 
379
          exit(0);
 
380
        }
 
381
      if (!strcmp(argv[1], "--dumpregs"))
 
382
        {
 
383
          dump_registers();
 
384
          exit(0);
 
385
        }
295
386
    }
296
 
  argc--;
297
 
  argv++;
298
 
 
299
 
  pacc = pci_alloc();
300
 
  pacc->error = die;
301
 
 
302
 
  while (argc && argv[0][0] == '-')
 
387
 
 
388
  while (i < argc && argv[i][0] == '-')
303
389
    {
304
 
      char *c = argv[0]+1;
 
390
      char *c = argv[i++] + 1;
305
391
      char *d = c;
306
392
      char *e;
307
393
      while (*c)
308
394
        switch (*c)
309
395
          {
 
396
          case 0:
 
397
            break;
310
398
          case 'v':
311
399
            verbose++;
312
400
            c++;
319
407
            demo_mode++;
320
408
            c++;
321
409
            break;
322
 
          case 0:
323
 
            break;
324
410
          default:
325
411
            if (e = strchr(opts, *c))
326
412
              {
330
416
                  {
331
417
                    if (*c)
332
418
                      arg = c;
333
 
                    else if (argc > 1)
334
 
                      {
335
 
                        arg = argv[1];
336
 
                        argc--; argv++;
337
 
                      }
 
419
                    else if (i < argc)
 
420
                      arg = argv[i++];
338
421
                    else
339
 
                      usage(NULL);
 
422
                      parse_err("Option -%c requires an argument", *e);
340
423
                    c = "";
341
424
                  }
342
425
                else
343
426
                  arg = NULL;
344
427
                if (!parse_generic_option(*e, pacc, arg))
345
 
                  usage(NULL);
 
428
                  parse_err("Unable to parse option -%c", *e);
346
429
              }
347
430
            else
348
431
              {
349
432
                if (c != d)
350
 
                  usage(NULL);
351
 
                goto next;
 
433
                  parse_err("Invalid or misplaced option -%c", *c);
 
434
                return i-1;
352
435
              }
353
436
          }
354
 
      argc--;
355
 
      argv++;
356
 
    }
357
 
next:
358
 
 
359
 
  pci_init(pacc);
360
 
  pci_scan_bus(pacc);
361
 
 
362
 
  while (argc)
363
 
    {
364
 
      char *c = argv[0];
365
 
      char *d, *e, *f;
366
 
      int n, i;
367
 
      struct op *op;
368
 
      unsigned long ll;
369
 
      unsigned int lim;
 
437
    }
 
438
 
 
439
  return i;
 
440
}
 
441
 
 
442
static int parse_filter(int argc, char **argv, int i, struct pci_filter *filter)
 
443
{
 
444
  char *c = argv[i++];
 
445
  char *d;
 
446
 
 
447
  if (!c[1] || !strchr("sd", c[1]))
 
448
    parse_err("Invalid option -%c", c[1]);
 
449
  if (c[2])
 
450
    d = (c[2] == '=') ? c+3 : c+2;
 
451
  else if (i < argc)
 
452
    d = argv[i++];
 
453
  else
 
454
    parse_err("Option -%c requires an argument", c[1]);
 
455
  switch (c[1])
 
456
    {
 
457
    case 's':
 
458
      if (d = pci_filter_parse_slot(filter, d))
 
459
        parse_err("Unable to parse filter -s %s", d);
 
460
      break;
 
461
    case 'd':
 
462
      if (d = pci_filter_parse_id(filter, d))
 
463
        parse_err("Unable to parse filter -d %s", d);
 
464
      break;
 
465
    default:
 
466
      parse_err("Unknown filter option -%c", c[1]);
 
467
    }
 
468
 
 
469
  return i;
 
470
}
 
471
 
 
472
static const struct reg_name *parse_reg_name(char *name)
 
473
{
 
474
  const struct reg_name *r;
 
475
 
 
476
  for (r = pci_reg_names; r->name; r++)
 
477
    if (!strcasecmp(r->name, name))
 
478
      return r;
 
479
  return NULL;
 
480
}
 
481
 
 
482
static int parse_x32(char *c, char **stopp, unsigned int *resp)
 
483
{
 
484
  char *stop;
 
485
 
 
486
  if (!*c)
 
487
    return -1;
 
488
  errno = 0;
 
489
  unsigned long int l = strtoul(c, &stop, 16);
 
490
  if (errno)
 
491
    return -1;
 
492
  if ((l & ~0U) != l)
 
493
    return -1;
 
494
  *resp = l;
 
495
  if (*stop)
 
496
    {
 
497
      if (stopp)
 
498
        *stopp = stop;
 
499
      return 0;
 
500
    }
 
501
  else
 
502
    {
 
503
      if (stopp)
 
504
        *stopp = NULL;
 
505
      return 1;
 
506
    }
 
507
}
 
508
 
 
509
static void parse_register(struct op *op, char *base)
 
510
{
 
511
  const struct reg_name *r;
 
512
  unsigned int cap;
 
513
 
 
514
  op->cap_type = op->cap_id = 0;
 
515
  if (parse_x32(base, NULL, &op->addr) > 0)
 
516
    return;
 
517
  else if (r = parse_reg_name(base))
 
518
    {
 
519
      switch (r->cap & 0xff0000)
 
520
        {
 
521
        case 0x10000:
 
522
          op->cap_type = PCI_CAP_NORMAL;
 
523
          break;
 
524
        case 0x20000:
 
525
          op->cap_type = PCI_CAP_EXTENDED;
 
526
          break;
 
527
        }
 
528
      op->cap_id = r->cap & 0xffff;
 
529
      op->addr = r->offset;
 
530
      if (r->width && !op->width)
 
531
        op->width = r->width;
 
532
      return;
 
533
    }
 
534
  else if (!strncasecmp(base, "CAP", 3))
 
535
    {
 
536
      if (parse_x32(base+3, NULL, &cap) > 0 && cap < 0x100)
 
537
        {
 
538
          op->cap_type = PCI_CAP_NORMAL;
 
539
          op->cap_id = cap;
 
540
          op->addr = 0;
 
541
          return;
 
542
        }
 
543
    }
 
544
  else if (!strncasecmp(base, "ECAP", 4))
 
545
    {
 
546
      if (parse_x32(base+4, NULL, &cap) > 0 && cap < 0x1000)
 
547
        {
 
548
          op->cap_type = PCI_CAP_EXTENDED;
 
549
          op->cap_id = cap;
 
550
          op->addr = 0;
 
551
          return;
 
552
        }
 
553
    }
 
554
  parse_err("Unknown register \"%s\"", base);
 
555
}
 
556
 
 
557
static void parse_op(char *c, struct pci_dev **selected_devices)
 
558
{
 
559
  char *base, *offset, *width, *value;
 
560
  char *e, *f;
 
561
  int n, j;
 
562
  struct op *op;
 
563
 
 
564
  /* Split the argument */
 
565
  base = xstrdup(c);
 
566
  if (value = strchr(base, '='))
 
567
    *value++ = 0;
 
568
  if (width = strchr(base, '.'))
 
569
    *width++ = 0;
 
570
  if (offset = strchr(base, '+'))
 
571
    *offset++ = 0;
 
572
 
 
573
  /* Look for setting of values and count how many */
 
574
  n = 0;
 
575
  if (value)
 
576
    {
 
577
      if (!*value)
 
578
        parse_err("Missing value");
 
579
      n++;
 
580
      for (e=value; *e; e++)
 
581
        if (*e == ',')
 
582
          n++;
 
583
    }
 
584
 
 
585
  /* Allocate the operation */
 
586
  op = xmalloc(sizeof(struct op) + n*sizeof(struct value));
 
587
  op->dev_vector = selected_devices;
 
588
  op->num_values = n;
 
589
 
 
590
  /* What is the width suffix? */
 
591
  if (width)
 
592
    {
 
593
      if (width[1])
 
594
        parse_err("Invalid width \"%s\"", width);
 
595
      switch (*width & 0xdf)
 
596
        {
 
597
        case 'B':
 
598
          op->width = 1; break;
 
599
        case 'W':
 
600
          op->width = 2; break;
 
601
        case 'L':
 
602
          op->width = 4; break;
 
603
        default:
 
604
          parse_err("Invalid width \"%c\"", *width);
 
605
        }
 
606
    }
 
607
  else
 
608
    op->width = 0;
 
609
 
 
610
  /* Find the register */
 
611
  parse_register(op, base);
 
612
  if (!op->width)
 
613
    parse_err("Missing width");
 
614
 
 
615
  /* Add offset */
 
616
  if (offset)
 
617
    {
 
618
      unsigned int off;
 
619
      if (parse_x32(offset, NULL, &off) <= 0 || off >= 0x1000)
 
620
        parse_err("Invalid offset \"%s\"", offset);
 
621
      op->addr += off;
 
622
    }
 
623
 
 
624
  /* Check range */
 
625
  if (op->addr >= 0x1000 || op->addr + op->width*(n ? n : 1) > 0x1000)
 
626
    parse_err("Register number %02x out of range", op->addr);
 
627
  if (op->addr & (op->width - 1))
 
628
    parse_err("Unaligned register address %02x", op->addr);
 
629
 
 
630
  /* Parse the values */
 
631
  for (j=0; j<n; j++)
 
632
    {
 
633
      unsigned int ll, lim;
 
634
      e = strchr(value, ',');
 
635
      if (e)
 
636
        *e++ = 0;
 
637
      if (parse_x32(value, &f, &ll) < 0 || f && *f != ':')
 
638
        parse_err("Invalid value \"%s\"", value);
 
639
      lim = max_values[op->width];
 
640
      if (ll > lim && ll < ~0UL - lim)
 
641
        parse_err("Value \"%s\" is out of range", value);
 
642
      op->values[j].value = ll;
 
643
      if (f && *f == ':')
 
644
        {
 
645
          if (parse_x32(f+1, NULL, &ll) <= 0)
 
646
            parse_err("Invalid mask \"%s\"", f+1);
 
647
          if (ll > lim && ll < ~0UL - lim)
 
648
            parse_err("Mask \"%s\" is out of range", f+1);
 
649
          op->values[j].mask = ll;
 
650
          op->values[j].value &= ll;
 
651
        }
 
652
      else
 
653
        op->values[j].mask = ~0U;
 
654
      value = e;
 
655
    }
 
656
 
 
657
  *last_op = op;
 
658
  last_op = &op->next;
 
659
  op->next = NULL;
 
660
}
 
661
 
 
662
static void parse_ops(int argc, char **argv, int i)
 
663
{
 
664
  enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
 
665
  struct pci_filter filter;
 
666
  struct pci_dev **selected_devices = NULL;
 
667
 
 
668
  while (i < argc)
 
669
    {
 
670
      char *c = argv[i++];
370
671
 
371
672
      if (*c == '-')
372
673
        {
373
 
          if (!c[1] || !strchr("sd", c[1]))
374
 
            usage(NULL);
375
 
          if (c[2])
376
 
            d = (c[2] == '=') ? c+3 : c+2;
377
 
          else if (argc > 1)
378
 
            {
379
 
              argc--;
380
 
              argv++;
381
 
              d = argv[0];
382
 
            }
383
 
          else
384
 
            usage(NULL);
385
674
          if (state != STATE_GOT_FILTER)
386
 
            {
387
 
              pci_filter_init(pacc, &filter);
388
 
              state = STATE_GOT_FILTER;
389
 
            }
390
 
          switch (c[1])
391
 
            {
392
 
            case 's':
393
 
              if (d = pci_filter_parse_slot(&filter, d))
394
 
                die("-s: %s", d);
395
 
              break;
396
 
            case 'd':
397
 
              if (d = pci_filter_parse_id(&filter, d))
398
 
                die("-d: %s", d);
399
 
              break;
400
 
            default:
401
 
              usage(NULL);
402
 
            }
 
675
            pci_filter_init(pacc, &filter);
 
676
          i = parse_filter(argc, argv, i-1, &filter);
 
677
          state = STATE_GOT_FILTER;
403
678
        }
404
 
      else if (state == STATE_INIT)
405
 
        usage(NULL);
406
679
      else
407
680
        {
 
681
          if (state == STATE_INIT)
 
682
            parse_err("Filter specification expected");
408
683
          if (state == STATE_GOT_FILTER)
409
684
            selected_devices = select_devices(&filter);
410
685
          if (!selected_devices[0] && !force)
411
 
            fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c);
 
686
            fprintf(stderr, "setpci: Warning: No devices selected for \"%s\".\n", c);
 
687
          parse_op(c, selected_devices);
412
688
          state = STATE_GOT_OP;
413
 
          /* look for setting of values and count how many */
414
 
          d = strchr(c, '=');
415
 
          if (d)
416
 
            {
417
 
              *d++ = 0;
418
 
              if (!*d)
419
 
                usage("Missing value");
420
 
              for(e=d, n=1; *e; e++)
421
 
                if (*e == ',')
422
 
                  n++;
423
 
              op = xmalloc(sizeof(struct op) + n*sizeof(struct value));
424
 
            }
425
 
          else
426
 
            {
427
 
              n = -1;
428
 
              op = xmalloc(sizeof(struct op));
429
 
            }
430
 
          op->dev_vector = selected_devices;
431
 
          op->num_values = n;
432
 
          e = strchr(c, '.');
433
 
          if (e)
434
 
            {
435
 
              *e++ = 0;
436
 
              if (e[1])
437
 
                usage("Missing width");
438
 
              switch (*e & 0xdf)
439
 
                {
440
 
                case 'B':
441
 
                  op->width = 1; break;
442
 
                case 'W':
443
 
                  op->width = 2; break;
444
 
                case 'L':
445
 
                  op->width = 4; break;
446
 
                default:
447
 
                  usage("Invalid width \"%c\"", *e);
448
 
                }
449
 
            }
450
 
          else
451
 
            op->width = 1;
452
 
          ll = strtol(c, &f, 16);
453
 
          if (f && *f)
454
 
            {
455
 
              const struct reg_name *r;
456
 
              for(r = pci_reg_names; r->name; r++)
457
 
                if (!strcasecmp(r->name, c))
458
 
                  break;
459
 
              if (!r->name)
460
 
                usage("Unknown register \"%s\"", c);
461
 
              if (e && op->width != r->width)
462
 
                usage("Explicit width doesn't correspond with the named register \"%s\"", c);
463
 
              ll = r->offset;
464
 
              op->width = r->width;
465
 
            }
466
 
          if (ll > 0x1000 || ll + op->width*((n < 0) ? 1 : n) > 0x1000)
467
 
            die("Register number out of range!");
468
 
          if (ll & (op->width - 1))
469
 
            die("Unaligned register address!");
470
 
          op->addr = ll;
471
 
          /* read in all the values to be set */
472
 
          for(i=0; i<n; i++)
473
 
            {
474
 
              e = strchr(d, ',');
475
 
              if (e)
476
 
                *e++ = 0;
477
 
              ll = strtoul(d, &f, 16);
478
 
              lim = max_values[op->width];
479
 
              if (f && *f && *f != ':')
480
 
                usage("Invalid value \"%s\"", d);
481
 
              if (ll > lim && ll < ~0UL - lim)
482
 
                usage("Value \"%s\" is out of range", d);
483
 
              op->values[i].value = ll;
484
 
              if (f && *f == ':')
485
 
                {
486
 
                  d = ++f;
487
 
                  ll = strtoul(d, &f, 16);
488
 
                  if (f && *f)
489
 
                    usage("Invalid mask \"%s\"", d);
490
 
                  if (ll > lim && ll < ~0UL - lim)
491
 
                    usage("Mask \"%s\" is out of range", d);
492
 
                  op->values[i].mask = ll;
493
 
                  op->values[i].value &= ll;
494
 
                }
495
 
              else
496
 
                op->values[i].mask = ~0U;
497
 
              d = e;
498
 
            }
499
 
          *last_op = op;
500
 
          last_op = &op->next;
501
 
          op->next = NULL;
502
689
        }
503
 
      argc--;
504
 
      argv++;
505
690
    }
506
691
  if (state == STATE_INIT)
507
 
    usage("No operation specified");
508
 
 
 
692
    parse_err("No operation specified");
 
693
}
 
694
 
 
695
int
 
696
main(int argc, char **argv)
 
697
{
 
698
  int i;
 
699
 
 
700
  pacc = pci_alloc();
 
701
  pacc->error = die;
 
702
  i = parse_options(argc, argv);
 
703
 
 
704
  pci_init(pacc);
 
705
  pci_scan_bus(pacc);
 
706
 
 
707
  parse_ops(argc, argv, i);
509
708
  scan_ops(first_op);
510
709
  execute(first_op);
511
710