2 * The PCI Library -- Configuration Access via /sys/bus/pci
4 * Copyright (c) 2003 Matthew Wilcox <willy@fc.hp.com>
5 * Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
20 #include <sys/types.h>
26 sysfs_config(struct pci_access
*a
)
28 a
->method_params
[PCI_ACCESS_SYS_BUS_PCI
] = PATH_SYS_BUS_PCI
;
32 sysfs_name(struct pci_access
*a
)
34 return a
->method_params
[PCI_ACCESS_SYS_BUS_PCI
];
38 sysfs_detect(struct pci_access
*a
)
40 if (access(sysfs_name(a
), R_OK
))
42 a
->debug("...cannot open %s", sysfs_name(a
));
45 a
->debug("...using %s", sysfs_name(a
));
50 sysfs_init(struct pci_access
*a
)
56 sysfs_cleanup(struct pci_access
*a
)
65 #define OBJNAMELEN 1024
67 sysfs_obj_name(struct pci_dev
*d
, char *object
, char *buf
)
69 int n
= snprintf(buf
, OBJNAMELEN
, "%s/devices/%04x:%02x:%02x.%d/%s",
70 sysfs_name(d
->access
), d
->domain
, d
->bus
, d
->dev
, d
->func
, object
);
71 if (n
< 0 || n
>= OBJNAMELEN
)
72 d
->access
->error("File name too long");
76 sysfs_get_value(struct pci_dev
*d
, char *object
)
78 struct pci_access
*a
= d
->access
;
80 char namebuf
[OBJNAMELEN
], buf
[256];
82 sysfs_obj_name(d
, object
, namebuf
);
83 fd
= open(namebuf
, O_RDONLY
);
85 a
->error("Cannot open %s: %s", namebuf
, strerror(errno
));
86 n
= read(fd
, buf
, sizeof(buf
));
89 a
->error("Error reading %s: %s", namebuf
, strerror(errno
));
90 if (n
>= (int) sizeof(buf
))
91 a
->error("Value in %s too long", namebuf
);
93 return strtol(buf
, NULL
, 0);
97 sysfs_get_resources(struct pci_dev
*d
)
99 struct pci_access
*a
= d
->access
;
100 char namebuf
[OBJNAMELEN
], buf
[256];
104 sysfs_obj_name(d
, "resource", namebuf
);
105 file
= fopen(namebuf
, "r");
107 a
->error("Cannot open %s: %s", namebuf
, strerror(errno
));
108 for (i
= 0; i
< 8; i
++)
110 unsigned long long start
, end
, size
;
111 if (!fgets(buf
, sizeof(buf
), file
))
113 if (sscanf(buf
, "%llx %llx", &start
, &end
) != 2)
114 a
->error("Syntax error in %s", namebuf
);
115 if (start
!= (unsigned long long)(pciaddr_t
) start
||
116 end
!= (unsigned long long)(pciaddr_t
) end
)
118 a
->warning("Resource %d in %s has a 64-bit address, ignoring", namebuf
);
122 size
= end
- start
+ 1;
127 d
->base_addr
[i
] = start
;
132 d
->rom_base_addr
= start
;
139 static void sysfs_scan(struct pci_access
*a
)
143 struct dirent
*entry
;
146 n
= snprintf(dirname
, sizeof(dirname
), "%s/devices", sysfs_name(a
));
147 if (n
< 0 || n
>= (int) sizeof(dirname
))
148 a
->error("Directory name too long");
149 dir
= opendir(dirname
);
151 a
->error("Cannot open %s", dirname
);
152 while ((entry
= readdir(dir
)))
155 unsigned int dom
, bus
, dev
, func
;
157 /* ".", ".." or a special non-device perhaps */
158 if (entry
->d_name
[0] == '.')
161 d
= pci_alloc_dev(a
);
162 if (sscanf(entry
->d_name
, "%x:%x:%x.%d", &dom
, &bus
, &dev
, &func
) < 4)
163 a
->error("sysfs_scan: Couldn't parse entry name %s", entry
->d_name
);
170 sysfs_get_resources(d
);
171 d
->irq
= sysfs_get_value(d
, "irq");
172 d
->known_fields
= PCI_FILL_IRQ
| PCI_FILL_BASES
| PCI_FILL_ROM_BASE
| PCI_FILL_SIZES
;
175 * We prefer reading these from the config registers, it's faster.
176 * However, it would be possible and maybe even useful to hack the kernel
177 * to believe that some device has a different ID. If you do it, just
178 * enable this piece of code. --mj
180 d
->vendor_id
= sysfs_get_value(d
, "vendor");
181 d
->device_id
= sysfs_get_value(d
, "device");
182 d
->known_fields
|= PCI_FILL_IDENT
;
191 sysfs_setup(struct pci_dev
*d
, int rw
)
193 struct pci_access
*a
= d
->access
;
195 if (a
->cached_dev
!= d
|| a
->fd_rw
< rw
)
197 char namebuf
[OBJNAMELEN
];
200 sysfs_obj_name(d
, "config", namebuf
);
201 a
->fd_rw
= a
->writeable
|| rw
;
202 a
->fd
= open(namebuf
, a
->fd_rw
? O_RDWR
: O_RDONLY
);
204 a
->warning("Cannot open %s", namebuf
);
211 static int sysfs_read(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
213 int fd
= sysfs_setup(d
, 0);
218 res
= do_read(d
, fd
, buf
, len
, pos
);
221 d
->access
->warning("sysfs_read: read failed: %s", strerror(errno
));
229 static int sysfs_write(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
231 int fd
= sysfs_setup(d
, 1);
236 res
= do_write(d
, fd
, buf
, len
, pos
);
239 d
->access
->warning("sysfs_write: write failed: %s", strerror(errno
));
244 d
->access
->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len
, pos
, res
);
250 static void sysfs_cleanup_dev(struct pci_dev
*d
)
252 struct pci_access
*a
= d
->access
;
254 if (a
->cached_dev
== d
)
256 a
->cached_dev
= NULL
;
262 struct pci_methods pm_linux_sysfs
= {
269 pci_generic_fill_info
,