Annotation of embedaddon/pciutils/lib/sysfs.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  *     The PCI Library -- Configuration Access via /sys/bus/pci
                      3:  *
                      4:  *     Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
                      5:  *     Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
                      6:  *
                      7:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      8:  */
                      9: 
                     10: #define _GNU_SOURCE
                     11: 
                     12: #include <stdio.h>
                     13: #include <stdlib.h>
                     14: #include <string.h>
                     15: #include <stdarg.h>
                     16: #include <unistd.h>
                     17: #include <errno.h>
                     18: #include <dirent.h>
                     19: #include <fcntl.h>
                     20: #include <sys/types.h>
                     21: 
                     22: #include "internal.h"
                     23: #include "pread.h"
                     24: 
                     25: static void
                     26: sysfs_config(struct pci_access *a)
                     27: {
                     28:   pci_define_param(a, "sysfs.path", PCI_PATH_SYS_BUS_PCI, "Path to the sysfs device tree");
                     29: }
                     30: 
                     31: static inline char *
                     32: sysfs_name(struct pci_access *a)
                     33: {
                     34:   return pci_get_param(a, "sysfs.path");
                     35: }
                     36: 
                     37: static int
                     38: sysfs_detect(struct pci_access *a)
                     39: {
                     40:   if (access(sysfs_name(a), R_OK))
                     41:     {
                     42:       a->debug("...cannot open %s", sysfs_name(a));
                     43:       return 0;
                     44:     }
                     45:   a->debug("...using %s", sysfs_name(a));
                     46:   return 1;
                     47: }
                     48: 
                     49: static void
                     50: sysfs_init(struct pci_access *a)
                     51: {
                     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;
                     70: }
                     71: 
                     72: static void
                     73: sysfs_cleanup(struct pci_access *a)
                     74: {
                     75:   sysfs_flush_cache(a);
                     76: }
                     77: 
                     78: #define OBJNAMELEN 1024
                     79: static void
                     80: sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
                     81: {
                     82:   int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
                     83:                   sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
                     84:   if (n < 0 || n >= OBJNAMELEN)
                     85:     d->access->error("File name too long");
                     86: }
                     87: 
                     88: static int
                     89: sysfs_get_value(struct pci_dev *d, char *object)
                     90: {
                     91:   struct pci_access *a = d->access;
                     92:   int fd, n;
                     93:   char namebuf[OBJNAMELEN], buf[256];
                     94: 
                     95:   sysfs_obj_name(d, object, namebuf);
                     96:   fd = open(namebuf, O_RDONLY);
                     97:   if (fd < 0)
                     98:     a->error("Cannot open %s: %s", namebuf, strerror(errno));
                     99:   n = read(fd, buf, sizeof(buf));
                    100:   close(fd);
                    101:   if (n < 0)
                    102:     a->error("Error reading %s: %s", namebuf, strerror(errno));
                    103:   if (n >= (int) sizeof(buf))
                    104:     a->error("Value in %s too long", namebuf);
                    105:   buf[n] = 0;
                    106:   return strtol(buf, NULL, 0);
                    107: }
                    108: 
                    109: static void
                    110: sysfs_get_resources(struct pci_dev *d)
                    111: {
                    112:   struct pci_access *a = d->access;
                    113:   char namebuf[OBJNAMELEN], buf[256];
                    114:   FILE *file;
                    115:   int i;
                    116: 
                    117:   sysfs_obj_name(d, "resource", namebuf);
                    118:   file = fopen(namebuf, "r");
                    119:   if (!file)
                    120:     a->error("Cannot open %s: %s", namebuf, strerror(errno));
                    121:   for (i = 0; i < 7; i++)
                    122:     {
                    123:       unsigned long long start, end, size, flags;
                    124:       if (!fgets(buf, sizeof(buf), file))
                    125:        break;
                    126:       if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
                    127:        a->error("Syntax error in %s", namebuf);
                    128:       if (start)
                    129:        size = end - start + 1;
                    130:       else
                    131:        size = 0;
                    132:       flags &= PCI_ADDR_FLAG_MASK;
                    133:       if (i < 6)
                    134:        {
                    135:          d->base_addr[i] = start | flags;
                    136:          d->size[i] = size;
                    137:        }
                    138:       else
                    139:        {
                    140:          d->rom_base_addr = start | flags;
                    141:          d->rom_size = size;
                    142:        }
                    143:     }
                    144:   fclose(file);
                    145: }
                    146: 
                    147: static void sysfs_scan(struct pci_access *a)
                    148: {
                    149:   char dirname[1024];
                    150:   DIR *dir;
                    151:   struct dirent *entry;
                    152:   int n;
                    153: 
                    154:   n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a));
                    155:   if (n < 0 || n >= (int) sizeof(dirname))
                    156:     a->error("Directory name too long");
                    157:   dir = opendir(dirname);
                    158:   if (!dir)
                    159:     a->error("Cannot open %s", dirname);
                    160:   while ((entry = readdir(dir)))
                    161:     {
                    162:       struct pci_dev *d;
                    163:       unsigned int dom, bus, dev, func;
                    164: 
                    165:       /* ".", ".." or a special non-device perhaps */
                    166:       if (entry->d_name[0] == '.')
                    167:        continue;
                    168: 
                    169:       d = pci_alloc_dev(a);
                    170:       if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
                    171:        a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
                    172:       d->domain = dom;
                    173:       d->bus = bus;
                    174:       d->dev = dev;
                    175:       d->func = func;
                    176:       if (!a->buscentric)
                    177:        {
                    178:          sysfs_get_resources(d);
                    179:          d->irq = sysfs_get_value(d, "irq");
                    180:          /*
                    181:           *  We could read these faster from the config registers, but we want to give
                    182:           *  the kernel a chance to fix up ID's and especially classes of broken devices.
                    183:           */
                    184:          d->vendor_id = sysfs_get_value(d, "vendor");
                    185:          d->device_id = sysfs_get_value(d, "device");
                    186:          d->device_class = sysfs_get_value(d, "class") >> 8;
                    187:          d->known_fields = PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES;
                    188:        }
                    189:       pci_link_dev(a, d);
                    190:     }
                    191:   closedir(dir);
                    192: }
                    193: 
                    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)
                    271: {
                    272:   struct pci_access *a = d->access;
                    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:     {
                    294:       sysfs_obj_name(d, "config", namebuf);
                    295:       a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
                    296:       a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
                    297:       if (a->fd < 0)
                    298:        a->warning("Cannot open %s", namebuf);
                    299:       a->fd_pos = 0;
                    300:     }
                    301:   return a->fd;
                    302: }
                    303: 
                    304: static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
                    305: {
                    306:   int fd = sysfs_setup(d, SETUP_READ_CONFIG);
                    307:   int res;
                    308: 
                    309:   if (fd < 0)
                    310:     return 0;
                    311:   res = do_read(d, fd, buf, len, pos);
                    312:   if (res < 0)
                    313:     {
                    314:       d->access->warning("sysfs_read: read failed: %s", strerror(errno));
                    315:       return 0;
                    316:     }
                    317:   else if (res != len)
                    318:     return 0;
                    319:   return 1;
                    320: }
                    321: 
                    322: static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
                    323: {
                    324:   int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
                    325:   int res;
                    326: 
                    327:   if (fd < 0)
                    328:     return 0;
                    329:   res = do_write(d, fd, buf, len, pos);
                    330:   if (res < 0)
                    331:     {
                    332:       d->access->warning("sysfs_write: write failed: %s", strerror(errno));
                    333:       return 0;
                    334:     }
                    335:   else if (res != len)
                    336:     {
                    337:       d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
                    338:       return 0;
                    339:     }
                    340:   return 1;
                    341: }
                    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: 
                    374: static void sysfs_cleanup_dev(struct pci_dev *d)
                    375: {
                    376:   struct pci_access *a = d->access;
                    377: 
                    378:   if (a->cached_dev == d)
                    379:     sysfs_flush_cache(a);
                    380: }
                    381: 
                    382: struct pci_methods pm_linux_sysfs = {
                    383:   "linux-sysfs",
                    384:   "The sys filesystem on Linux",
                    385:   sysfs_config,
                    386:   sysfs_detect,
                    387:   sysfs_init,
                    388:   sysfs_cleanup,
                    389:   sysfs_scan,
                    390:   sysfs_fill_info,
                    391:   sysfs_read,
                    392:   sysfs_write,
                    393:   sysfs_read_vpd,
                    394:   NULL,                                        /* init_dev */
                    395:   sysfs_cleanup_dev
                    396: };

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>