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

« back to all changes in this revision

Viewing changes to lib/sysfs.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:
1
1
/*
2
2
 *      The PCI Library -- Configuration Access via /sys/bus/pci
3
3
 *
4
 
 *      Copyright (c) 2003 Matthew Wilcox <willy@fc.hp.com>
 
4
 *      Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
5
5
 *      Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
6
6
 *
7
7
 *      Can be freely distributed and used under the terms of the GNU GPL.
50
50
sysfs_init(struct pci_access *a)
51
51
{
52
52
  a->fd = -1;
 
53
  a->fd_vpd = -1;
 
54
}
 
55
 
 
56
static void
 
57
sysfs_flush_cache(struct pci_access *a)
 
58
{
 
59
  if (a->fd >= 0)
 
60
    {
 
61
      close(a->fd);
 
62
      a->fd = -1;
 
63
    }
 
64
  if (a->fd_vpd >= 0)
 
65
    {
 
66
      close(a->fd_vpd);
 
67
      a->fd_vpd = -1;
 
68
    }
 
69
  a->cached_dev = NULL;
53
70
}
54
71
 
55
72
static void
56
73
sysfs_cleanup(struct pci_access *a)
57
74
{
58
 
  if (a->fd >= 0)
59
 
    {
60
 
      close(a->fd);
61
 
      a->fd = -1;
62
 
    }
 
75
  sysfs_flush_cache(a);
63
76
}
64
77
 
65
78
#define OBJNAMELEN 1024
107
120
    a->error("Cannot open %s: %s", namebuf, strerror(errno));
108
121
  for (i = 0; i < 7; i++)
109
122
    {
110
 
      unsigned long long start, end, size;
 
123
      unsigned long long start, end, size, flags;
111
124
      if (!fgets(buf, sizeof(buf), file))
112
125
        break;
113
 
      if (sscanf(buf, "%llx %llx", &start, &end) != 2)
 
126
      if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
114
127
        a->error("Syntax error in %s", namebuf);
115
128
      if (start)
116
129
        size = end - start + 1;
117
130
      else
118
131
        size = 0;
 
132
      flags &= PCI_ADDR_FLAG_MASK;
119
133
      if (i < 6)
120
134
        {
121
 
          d->base_addr[i] = start;
 
135
          d->base_addr[i] = start | flags;
122
136
          d->size[i] = size;
123
137
        }
124
138
      else
125
139
        {
126
 
          d->rom_base_addr = start;
 
140
          d->rom_base_addr = start | flags;
127
141
          d->rom_size = size;
128
142
        }
129
143
    }
177
191
  closedir(dir);
178
192
}
179
193
 
180
 
static int
181
 
sysfs_setup(struct pci_dev *d, int rw)
 
194
static void
 
195
sysfs_fill_slots(struct pci_access *a)
 
196
{
 
197
  char dirname[1024];
 
198
  DIR *dir;
 
199
  struct dirent *entry;
 
200
  int n;
 
201
 
 
202
  n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
 
203
  if (n < 0 || n >= (int) sizeof(dirname))
 
204
    a->error("Directory name too long");
 
205
  dir = opendir(dirname);
 
206
  if (!dir)
 
207
    return;
 
208
 
 
209
  while (entry = readdir(dir))
 
210
    {
 
211
      char namebuf[OBJNAMELEN], buf[16];
 
212
      FILE *file;
 
213
      unsigned int dom, bus, dev;
 
214
      struct pci_dev *d;
 
215
 
 
216
      /* ".", ".." or a special non-device perhaps */
 
217
      if (entry->d_name[0] == '.')
 
218
        continue;
 
219
 
 
220
      n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
 
221
      if (n < 0 || n >= OBJNAMELEN)
 
222
        a->error("File name too long");
 
223
      file = fopen(namebuf, "r");
 
224
      /*
 
225
       * Old versions of Linux had a fakephp which didn't have an 'address'
 
226
       * file.  There's no useful information to be gleaned from these
 
227
       * devices, pretend they're not there.
 
228
       */
 
229
      if (!file)
 
230
        continue;
 
231
 
 
232
      if (!fgets(buf, sizeof(buf), file) || sscanf(buf, "%x:%x:%x", &dom, &bus, &dev) < 3)
 
233
        a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
 
234
      else
 
235
        {
 
236
          for (d = a->devices; d; d = d->next)
 
237
            if (dom == d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
 
238
              {
 
239
                d->phy_slot = pci_malloc(a, strlen(entry->d_name) + 1);
 
240
                strcpy(d->phy_slot, entry->d_name);
 
241
              }
 
242
        }
 
243
      fclose(file);
 
244
    }
 
245
  closedir(dir);
 
246
}
 
247
 
 
248
static int
 
249
sysfs_fill_info(struct pci_dev *d, int flags)
 
250
{
 
251
  if ((flags & PCI_FILL_PHYS_SLOT) && !(d->known_fields & PCI_FILL_PHYS_SLOT))
 
252
    {
 
253
      struct pci_dev *pd;
 
254
      sysfs_fill_slots(d->access);
 
255
      for (pd = d->access->devices; pd; pd = pd->next)
 
256
        pd->known_fields |= PCI_FILL_PHYS_SLOT;
 
257
    }
 
258
  return pci_generic_fill_info(d, flags);
 
259
}
 
260
 
 
261
/* Intent of the sysfs_setup() caller */
 
262
enum
 
263
  {
 
264
    SETUP_READ_CONFIG = 0,
 
265
    SETUP_WRITE_CONFIG = 1,
 
266
    SETUP_READ_VPD = 2
 
267
  };
 
268
 
 
269
static int
 
270
sysfs_setup(struct pci_dev *d, int intent)
182
271
{
183
272
  struct pci_access *a = d->access;
184
 
 
185
 
  if (a->cached_dev != d || a->fd_rw < rw)
186
 
    {
187
 
      char namebuf[OBJNAMELEN];
188
 
      if (a->fd >= 0)
189
 
        close(a->fd);
 
273
  char namebuf[OBJNAMELEN];
 
274
 
 
275
  if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
 
276
    {
 
277
      sysfs_flush_cache(a);
 
278
      a->cached_dev = d;
 
279
    }
 
280
 
 
281
  if (intent == SETUP_READ_VPD)
 
282
    {
 
283
      if (a->fd_vpd < 0)
 
284
        {
 
285
          sysfs_obj_name(d, "vpd", namebuf);
 
286
          a->fd_vpd = open(namebuf, O_RDONLY);
 
287
          /* No warning on error; vpd may be absent or accessible only to root */
 
288
        }
 
289
      return a->fd_vpd;
 
290
    }
 
291
 
 
292
  if (a->fd < 0)
 
293
    {
190
294
      sysfs_obj_name(d, "config", namebuf);
191
 
      a->fd_rw = a->writeable || rw;
 
295
      a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
192
296
      a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
193
297
      if (a->fd < 0)
194
298
        a->warning("Cannot open %s", namebuf);
195
 
      a->cached_dev = d;
196
299
      a->fd_pos = 0;
197
300
    }
198
301
  return a->fd;
200
303
 
201
304
static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
202
305
{
203
 
  int fd = sysfs_setup(d, 0);
 
306
  int fd = sysfs_setup(d, SETUP_READ_CONFIG);
204
307
  int res;
205
308
 
206
309
  if (fd < 0)
218
321
 
219
322
static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
220
323
{
221
 
  int fd = sysfs_setup(d, 1);
 
324
  int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
222
325
  int res;
223
326
 
224
327
  if (fd < 0)
237
340
  return 1;
238
341
}
239
342
 
 
343
#ifdef PCI_HAVE_DO_READ
 
344
 
 
345
/* pread() is not available and do_read() only works for a single fd, so we
 
346
 * cannot implement read_vpd properly. */
 
347
static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
 
348
{
 
349
  return 0;
 
350
}
 
351
 
 
352
#else /* !PCI_HAVE_DO_READ */
 
353
 
 
354
static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
 
355
{
 
356
  int fd = sysfs_setup(d, SETUP_READ_VPD);
 
357
  int res;
 
358
 
 
359
  if (fd < 0)
 
360
    return 0;
 
361
  res = pread(fd, buf, len, pos);
 
362
  if (res < 0)
 
363
    {
 
364
      d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
 
365
      return 0;
 
366
    }
 
367
  else if (res != len)
 
368
    return 0;
 
369
  return 1;
 
370
}
 
371
 
 
372
#endif /* PCI_HAVE_DO_READ */
 
373
 
240
374
static void sysfs_cleanup_dev(struct pci_dev *d)
241
375
{
242
376
  struct pci_access *a = d->access;
243
377
 
244
378
  if (a->cached_dev == d)
245
 
    {
246
 
      a->cached_dev = NULL;
247
 
      close(a->fd);
248
 
      a->fd = -1;
249
 
    }
 
379
    sysfs_flush_cache(a);
250
380
}
251
381
 
252
382
struct pci_methods pm_linux_sysfs = {
257
387
  sysfs_init,
258
388
  sysfs_cleanup,
259
389
  sysfs_scan,
260
 
  pci_generic_fill_info,
 
390
  sysfs_fill_info,
261
391
  sysfs_read,
262
392
  sysfs_write,
 
393
  sysfs_read_vpd,
263
394
  NULL,                                 /* init_dev */
264
395
  sysfs_cleanup_dev
265
396
};