1 /* 2 * (C) Copyright IBM Corporation 2006 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * \file linux_sysfs.c 27 * Access PCI subsystem using Linux's sysfs interface. This interface is 28 * available starting somewhere in the late 2.5.x kernel phase, and is the 29 * preferred method on all 2.6.x kernels. 30 * 31 * \author Ian Romanick <[email protected]> 32 */ 33 34 #define _GNU_SOURCE 35 36 #include <stdlib.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <unistd.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include <sys/mman.h> 44 #include <dirent.h> 45 #include <errno.h> 46 47 #include "config.h" 48 49 #ifdef HAVE_MTRR 50 #include <asm/mtrr.h> 51 #include <sys/ioctl.h> 52 #endif 53 54 #include "pciaccess.h" 55 #include "pciaccess_private.h" 56 #include "linux_devmem.h" 57 58 static const struct pci_system_methods linux_sysfs_methods; 59 60 #define SYS_BUS_PCI "/sys/bus/pci/devices" 61 62 static int 63 pci_device_linux_sysfs_read( struct pci_device * dev, void * data, 64 pciaddr_t offset, pciaddr_t size, 65 pciaddr_t * bytes_read ); 66 67 static int populate_entries(struct pci_system * pci_sys); 68 69 /** 70 * Attempt to access PCI subsystem using Linux's sysfs interface. 71 */ 72 _pci_hidden int 73 pci_system_linux_sysfs_create( void ) 74 { 75 int err = 0; 76 struct stat st; 77 78 79 /* If the directory "/sys/bus/pci/devices" exists, then the PCI subsystem 80 * can be accessed using this interface. 81 */ 82 83 if ( stat( SYS_BUS_PCI, & st ) == 0 ) { 84 pci_sys = calloc( 1, sizeof( struct pci_system ) ); 85 if ( pci_sys != NULL ) { 86 pci_sys->methods = & linux_sysfs_methods; 87 #ifdef HAVE_MTRR 88 pci_sys->mtrr_fd = open("/proc/mtrr", O_WRONLY); 89 #endif 90 err = populate_entries(pci_sys); 91 } 92 else { 93 err = ENOMEM; 94 } 95 } 96 else { 97 err = errno; 98 } 99 100 return err; 101 } 102 103 104 /** 105 * Filter out the names "." and ".." from the scanned sysfs entries. 106 * 107 * \param d Directory entry being processed by \c scandir. 108 * 109 * \return 110 * Zero if the entry name matches either "." or "..", non-zero otherwise. 111 * 112 * \sa scandir, populate_entries 113 */ 114 static int 115 scan_sys_pci_filter( const struct dirent * d ) 116 { 117 return !((strcmp( d->d_name, "." ) == 0) 118 || (strcmp( d->d_name, ".." ) == 0)); 119 } 120 121 122 int 123 populate_entries( struct pci_system * p ) 124 { 125 struct dirent ** devices; 126 int n; 127 int i; 128 int err = 0; 129 130 131 n = scandir( SYS_BUS_PCI, & devices, scan_sys_pci_filter, alphasort ); 132 if ( n > 0 ) { 133 p->num_devices = n; 134 p->devices = calloc( n, sizeof( struct pci_device_private ) ); 135 136 if (p->devices != NULL) { 137 for (i = 0 ; i < n ; i++) { 138 uint8_t config[48]; 139 pciaddr_t bytes; 140 unsigned dom, bus, dev, func; 141 struct pci_device_private *device = 142 (struct pci_device_private *) &p->devices[i]; 143 144 145 sscanf(devices[i]->d_name, "%04x:%02x:%02x.%1u", 146 & dom, & bus, & dev, & func); 147 148 device->base.domain = dom; 149 device->base.bus = bus; 150 device->base.dev = dev; 151 device->base.func = func; 152 153 154 err = pci_device_linux_sysfs_read(& device->base, config, 0, 155 48, & bytes); 156 if ((bytes == 48) && !err) { 157 device->base.vendor_id = (uint16_t)config[0] 158 + ((uint16_t)config[1] << 8); 159 device->base.device_id = (uint16_t)config[2] 160 + ((uint16_t)config[3] << 8); 161 device->base.device_class = (uint32_t)config[9] 162 + ((uint32_t)config[10] << 8) 163 + ((uint32_t)config[11] << 16); 164 device->base.revision = config[8]; 165 device->base.subvendor_id = (uint16_t)config[44] 166 + ((uint16_t)config[45] << 8); 167 device->base.subdevice_id = (uint16_t)config[46] 168 + ((uint16_t)config[47] << 8); 169 } 170 171 if (err) { 172 break; 173 } 174 } 175 } 176 else { 177 err = ENOMEM; 178 } 179 } 180 181 for (i = 0; i < n; i++) 182 free(devices[i]); 183 free(devices); 184 185 if (err) { 186 free(p->devices); 187 p->devices = NULL; 188 } 189 190 return err; 191 } 192 193 194 static int 195 pci_device_linux_sysfs_probe( struct pci_device * dev ) 196 { 197 char name[256]; 198 uint8_t config[256]; 199 char resource[512]; 200 int fd; 201 pciaddr_t bytes; 202 unsigned i; 203 int err; 204 205 206 err = pci_device_linux_sysfs_read( dev, config, 0, 256, & bytes ); 207 if ( bytes >= 64 ) { 208 struct pci_device_private *priv = (struct pci_device_private *) dev; 209 210 dev->irq = config[60]; 211 priv->header_type = config[14]; 212 213 214 /* The PCI config registers can be used to obtain information 215 * about the memory and I/O regions for the device. However, 216 * doing so requires some tricky parsing (to correctly handle 217 * 64-bit memory regions) and requires writing to the config 218 * registers. Since we'd like to avoid having to deal with the 219 * parsing issues and non-root users can write to PCI config 220 * registers, we use a different file in the device's sysfs 221 * directory called "resource". 222 * 223 * The resource file contains all of the needed information in 224 * a format that is consistent across all platforms. Each BAR 225 * and the expansion ROM have a single line of data containing 226 * 3, 64-bit hex values: the first address in the region, 227 * the last address in the region, and the region's flags. 228 */ 229 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource", 230 SYS_BUS_PCI, 231 dev->domain, 232 dev->bus, 233 dev->dev, 234 dev->func ); 235 fd = open( name, O_RDONLY ); 236 if ( fd != -1 ) { 237 char * next; 238 pciaddr_t low_addr; 239 pciaddr_t high_addr; 240 pciaddr_t flags; 241 242 243 bytes = read( fd, resource, 512 ); 244 resource[511] = '\0'; 245 246 close( fd ); 247 248 next = resource; 249 for ( i = 0 ; i < 6 ; i++ ) { 250 251 dev->regions[i].base_addr = strtoull( next, & next, 16 ); 252 high_addr = strtoull( next, & next, 16 ); 253 flags = strtoull( next, & next, 16 ); 254 255 if ( dev->regions[i].base_addr != 0 ) { 256 dev->regions[i].size = (high_addr 257 - dev->regions[i].base_addr) + 1; 258 259 dev->regions[i].is_IO = (flags & 0x01); 260 dev->regions[i].is_64 = (flags & 0x04); 261 dev->regions[i].is_prefetchable = (flags & 0x08); 262 } 263 } 264 265 low_addr = strtoull( next, & next, 16 ); 266 high_addr = strtoull( next, & next, 16 ); 267 flags = strtoull( next, & next, 16 ); 268 if ( low_addr != 0 ) { 269 priv->rom_base = low_addr; 270 dev->rom_size = (high_addr - low_addr) + 1; 271 } 272 } 273 } 274 275 return err; 276 } 277 278 279 static int 280 pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer ) 281 { 282 char name[256]; 283 int fd; 284 struct stat st; 285 int err = 0; 286 size_t rom_size; 287 size_t total_bytes; 288 289 290 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/rom", 291 SYS_BUS_PCI, 292 dev->domain, 293 dev->bus, 294 dev->dev, 295 dev->func ); 296 297 fd = open( name, O_RDWR ); 298 if ( fd == -1 ) { 299 #ifdef LINUX_ROM 300 /* If reading the ROM using sysfs fails, fall back to the old 301 * /dev/mem based interface. 302 * disable this for newer kernels using configure 303 */ 304 return pci_device_linux_devmem_read_rom(dev, buffer); 305 #else 306 return errno; 307 #endif 308 } 309 310 311 if ( fstat( fd, & st ) == -1 ) { 312 close( fd ); 313 return errno; 314 } 315 316 rom_size = st.st_size; 317 if ( rom_size == 0 ) 318 rom_size = 0x10000; 319 320 /* This is a quirky thing on Linux. Even though the ROM and the file 321 * for the ROM in sysfs are read-only, the string "1" must be written to 322 * the file to enable the ROM. After the data has been read, "0" must be 323 * written to the file to disable the ROM. 324 */ 325 write( fd, "1", 1 ); 326 lseek( fd, 0, SEEK_SET ); 327 328 for ( total_bytes = 0 ; total_bytes < rom_size ; /* empty */ ) { 329 const int bytes = read( fd, (char *) buffer + total_bytes, 330 rom_size - total_bytes ); 331 if ( bytes == -1 ) { 332 err = errno; 333 break; 334 } 335 else if ( bytes == 0 ) { 336 break; 337 } 338 339 total_bytes += bytes; 340 } 341 342 343 lseek( fd, 0, SEEK_SET ); 344 write( fd, "0", 1 ); 345 346 close( fd ); 347 return err; 348 } 349 350 351 static int 352 pci_device_linux_sysfs_read( struct pci_device * dev, void * data, 353 pciaddr_t offset, pciaddr_t size, 354 pciaddr_t * bytes_read ) 355 { 356 char name[256]; 357 pciaddr_t temp_size = size; 358 int err = 0; 359 int fd; 360 char *data_bytes = data; 361 362 if ( bytes_read != NULL ) { 363 *bytes_read = 0; 364 } 365 366 /* Each device has a directory under sysfs. Within that directory there 367 * is a file named "config". This file used to access the PCI config 368 * space. It is used here to obtain most of the information about the 369 * device. 370 */ 371 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config", 372 SYS_BUS_PCI, 373 dev->domain, 374 dev->bus, 375 dev->dev, 376 dev->func ); 377 378 fd = open( name, O_RDONLY ); 379 if ( fd == -1 ) { 380 return errno; 381 } 382 383 384 while ( temp_size > 0 ) { 385 const ssize_t bytes = pread64( fd, data_bytes, temp_size, offset ); 386 387 /* If zero bytes were read, then we assume it's the end of the 388 * config file. 389 */ 390 if ( bytes <= 0 ) { 391 err = errno; 392 break; 393 } 394 395 temp_size -= bytes; 396 offset += bytes; 397 data_bytes += bytes; 398 } 399 400 if ( bytes_read != NULL ) { 401 *bytes_read = size - temp_size; 402 } 403 404 close( fd ); 405 return err; 406 } 407 408 409 static int 410 pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, 411 pciaddr_t offset, pciaddr_t size, 412 pciaddr_t * bytes_written ) 413 { 414 char name[256]; 415 pciaddr_t temp_size = size; 416 int err = 0; 417 int fd; 418 const char *data_bytes = data; 419 420 if ( bytes_written != NULL ) { 421 *bytes_written = 0; 422 } 423 424 /* Each device has a directory under sysfs. Within that directory there 425 * is a file named "config". This file used to access the PCI config 426 * space. It is used here to obtain most of the information about the 427 * device. 428 */ 429 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config", 430 SYS_BUS_PCI, 431 dev->domain, 432 dev->bus, 433 dev->dev, 434 dev->func ); 435 436 fd = open( name, O_WRONLY ); 437 if ( fd == -1 ) { 438 return errno; 439 } 440 441 442 while ( temp_size > 0 ) { 443 const ssize_t bytes = pwrite64( fd, data_bytes, temp_size, offset ); 444 445 /* If zero bytes were written, then we assume it's the end of the 446 * config file. 447 */ 448 if ( bytes <= 0 ) { 449 err = errno; 450 break; 451 } 452 453 temp_size -= bytes; 454 offset += bytes; 455 data_bytes += bytes; 456 } 457 458 if ( bytes_written != NULL ) { 459 *bytes_written = size - temp_size; 460 } 461 462 close( fd ); 463 return err; 464 } 465 466 static int 467 pci_device_linux_sysfs_map_range_wc(struct pci_device *dev, 468 struct pci_device_mapping *map) 469 { 470 char name[256]; 471 int fd; 472 const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 473 ? (PROT_READ | PROT_WRITE) : PROT_READ; 474 const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 475 ? O_RDWR : O_RDONLY; 476 const off_t offset = map->base - dev->regions[map->region].base_addr; 477 478 snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_wc", 479 SYS_BUS_PCI, 480 dev->domain, 481 dev->bus, 482 dev->dev, 483 dev->func, 484 map->region); 485 fd = open(name, open_flags); 486 if (fd == -1) 487 return errno; 488 489 map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); 490 if (map->memory == MAP_FAILED) { 491 map->memory = NULL; 492 close(fd); 493 return errno; 494 } 495 496 close(fd); 497 498 return 0; 499 } 500 501 /** 502 * Map a memory region for a device using the Linux sysfs interface. 503 * 504 * \param dev Device whose memory region is to be mapped. 505 * \param map Parameters of the mapping that is to be created. 506 * 507 * \return 508 * Zero on success or an \c errno value on failure. 509 * 510 * \sa pci_device_map_rrange, pci_device_linux_sysfs_unmap_range 511 * 512 * \todo 513 * Some older 2.6.x kernels don't implement the resourceN files. On those 514 * systems /dev/mem must be used. On these systems it is also possible that 515 * \c mmap64 may need to be used. 516 */ 517 static int 518 pci_device_linux_sysfs_map_range(struct pci_device *dev, 519 struct pci_device_mapping *map) 520 { 521 char name[256]; 522 int fd; 523 int err = 0; 524 const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 525 ? (PROT_READ | PROT_WRITE) : PROT_READ; 526 const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) 527 ? O_RDWR : O_RDONLY; 528 const off_t offset = map->base - dev->regions[map->region].base_addr; 529 #ifdef HAVE_MTRR 530 struct mtrr_sentry sentry = { 531 .base = map->base, 532 .size = map->size, 533 .type = MTRR_TYPE_UNCACHABLE 534 }; 535 #endif 536 537 /* For WC mappings, try sysfs resourceN_wc file first */ 538 if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) && 539 !pci_device_linux_sysfs_map_range_wc(dev, map)) 540 return 0; 541 542 snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u", 543 SYS_BUS_PCI, 544 dev->domain, 545 dev->bus, 546 dev->dev, 547 dev->func, 548 map->region); 549 550 fd = open(name, open_flags); 551 if (fd == -1) { 552 return errno; 553 } 554 555 556 map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); 557 if (map->memory == MAP_FAILED) { 558 map->memory = NULL; 559 close(fd); 560 return errno; 561 } 562 563 #ifdef HAVE_MTRR 564 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { 565 sentry.type = MTRR_TYPE_WRBACK; 566 } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { 567 sentry.type = MTRR_TYPE_WRCOMB; 568 } 569 570 if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { 571 if (ioctl(pci_sys->mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) < 0) { 572 /* FIXME: Should we report an error in this case? 573 */ 574 fprintf(stderr, "error setting MTRR " 575 "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", 576 sentry.base, sentry.size, sentry.type, 577 strerror(errno), errno); 578 /* err = errno;*/ 579 } 580 /* KLUDGE ALERT -- rewrite the PTEs to turn off the CD and WT bits */ 581 mprotect (map->memory, map->size, PROT_NONE); 582 err = mprotect (map->memory, map->size, PROT_READ|PROT_WRITE); 583 584 if (err != 0) { 585 fprintf(stderr, "mprotect(PROT_READ | PROT_WRITE) failed: %s\n", 586 strerror(errno)); 587 fprintf(stderr, "remapping without mprotect performance kludge.\n"); 588 589 munmap(map->memory, map->size); 590 map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); 591 if (map->memory == MAP_FAILED) { 592 map->memory = NULL; 593 close(fd); 594 return errno; 595 } 596 } 597 } 598 #endif 599 600 close(fd); 601 602 return 0; 603 } 604 605 /** 606 * Unmap a memory region for a device using the Linux sysfs interface. 607 * 608 * \param dev Device whose memory region is to be unmapped. 609 * \param map Parameters of the mapping that is to be destroyed. 610 * 611 * \return 612 * Zero on success or an \c errno value on failure. 613 * 614 * \sa pci_device_map_rrange, pci_device_linux_sysfs_map_range 615 * 616 * \todo 617 * Some older 2.6.x kernels don't implement the resourceN files. On those 618 * systems /dev/mem must be used. On these systems it is also possible that 619 * \c mmap64 may need to be used. 620 */ 621 static int 622 pci_device_linux_sysfs_unmap_range(struct pci_device *dev, 623 struct pci_device_mapping *map) 624 { 625 int err = 0; 626 #ifdef HAVE_MTRR 627 struct mtrr_sentry sentry = { 628 .base = map->base, 629 .size = map->size, 630 .type = MTRR_TYPE_UNCACHABLE 631 }; 632 #endif 633 634 err = pci_device_generic_unmap_range (dev, map); 635 if (err) 636 return err; 637 638 #ifdef HAVE_MTRR 639 if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { 640 sentry.type = MTRR_TYPE_WRBACK; 641 } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { 642 sentry.type = MTRR_TYPE_WRCOMB; 643 } 644 645 if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { 646 if (ioctl(pci_sys->mtrr_fd, MTRRIOC_DEL_ENTRY, &sentry) < 0) { 647 /* FIXME: Should we report an error in this case? 648 */ 649 fprintf(stderr, "error setting MTRR " 650 "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", 651 sentry.base, sentry.size, sentry.type, 652 strerror(errno), errno); 653 /* err = errno;*/ 654 } 655 } 656 #endif 657 658 return err; 659 } 660 661 static void pci_device_linux_sysfs_enable(struct pci_device *dev) 662 { 663 char name[256]; 664 int fd; 665 666 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/enable", 667 SYS_BUS_PCI, 668 dev->domain, 669 dev->bus, 670 dev->dev, 671 dev->func ); 672 673 fd = open( name, O_RDWR ); 674 if (fd == -1) 675 return; 676 677 write( fd, "1", 1 ); 678 close(fd); 679 } 680 681 static int pci_device_linux_sysfs_boot_vga(struct pci_device *dev) 682 { 683 char name[256]; 684 char reply[3]; 685 int fd, bytes_read; 686 int ret = 0; 687 688 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/boot_vga", 689 SYS_BUS_PCI, 690 dev->domain, 691 dev->bus, 692 dev->dev, 693 dev->func ); 694 695 fd = open( name, O_RDONLY ); 696 if (fd == -1) 697 return 0; 698 699 bytes_read = read(fd, reply, 1); 700 if (bytes_read != 1) 701 goto out; 702 if (reply[0] == '1') 703 ret = 1; 704 out: 705 close(fd); 706 return ret; 707 } 708 709 static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev) 710 { 711 char name[256]; 712 struct stat dummy; 713 int ret; 714 715 snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/driver", 716 SYS_BUS_PCI, 717 dev->domain, 718 dev->bus, 719 dev->dev, 720 dev->func ); 721 722 ret = stat(name, &dummy); 723 if (ret < 0) 724 return 0; 725 return 1; 726 } 727 728 static struct pci_io_handle * 729 pci_device_linux_sysfs_open_device_io(struct pci_io_handle *ret, 730 struct pci_device *dev, int bar, 731 pciaddr_t base, pciaddr_t size) 732 { 733 char name[PATH_MAX]; 734 735 snprintf(name, PATH_MAX, "%s/%04x:%02x:%02x.%1u/resource%d", 736 SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, bar); 737 738 ret->fd = open(name, O_RDWR); 739 740 if (ret->fd < 0) 741 return NULL; 742 743 ret->base = base; 744 ret->size = size; 745 746 return ret; 747 } 748 749 static struct pci_io_handle * 750 pci_device_linux_sysfs_open_legacy_io(struct pci_io_handle *ret, 751 struct pci_device *dev, pciaddr_t base, 752 pciaddr_t size) 753 { 754 char name[PATH_MAX]; 755 756 /* First check if there's a legacy io method for the device */ 757 while (dev) { 758 snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_io", 759 dev->domain, dev->bus); 760 761 ret->fd = open(name, O_RDWR); 762 if (ret->fd >= 0) 763 break; 764 765 dev = pci_device_get_parent_bridge(dev); 766 } 767 768 /* If not, /dev/port is the best we can do */ 769 if (!dev) 770 ret->fd = open("/dev/port", O_RDWR); 771 772 if (ret->fd < 0) 773 return NULL; 774 775 ret->base = base; 776 ret->size = size; 777 778 return ret; 779 } 780 781 static void 782 pci_device_linux_sysfs_close_io(struct pci_device *dev, 783 struct pci_io_handle *handle) 784 { 785 close(handle->fd); 786 } 787 788 static uint32_t 789 pci_device_linux_sysfs_read32(struct pci_io_handle *handle, uint32_t port) 790 { 791 uint32_t ret; 792 793 pread(handle->fd, &ret, 4, port + handle->base); 794 795 return ret; 796 } 797 798 static uint16_t 799 pci_device_linux_sysfs_read16(struct pci_io_handle *handle, uint32_t port) 800 { 801 uint16_t ret; 802 803 pread(handle->fd, &ret, 2, port + handle->base); 804 805 return ret; 806 } 807 808 static uint8_t 809 pci_device_linux_sysfs_read8(struct pci_io_handle *handle, uint32_t port) 810 { 811 uint8_t ret; 812 813 pread(handle->fd, &ret, 1, port + handle->base); 814 815 return ret; 816 } 817 818 static void 819 pci_device_linux_sysfs_write32(struct pci_io_handle *handle, uint32_t port, 820 uint32_t data) 821 { 822 pwrite(handle->fd, &data, 4, port + handle->base); 823 } 824 825 static void 826 pci_device_linux_sysfs_write16(struct pci_io_handle *handle, uint32_t port, 827 uint16_t data) 828 { 829 pwrite(handle->fd, &data, 2, port + handle->base); 830 } 831 832 static void 833 pci_device_linux_sysfs_write8(struct pci_io_handle *handle, uint32_t port, 834 uint8_t data) 835 { 836 pwrite(handle->fd, &data, 1, port + handle->base); 837 } 838 839 static const struct pci_system_methods linux_sysfs_methods = { 840 .destroy = NULL, 841 .destroy_device = NULL, 842 .read_rom = pci_device_linux_sysfs_read_rom, 843 .probe = pci_device_linux_sysfs_probe, 844 .map_range = pci_device_linux_sysfs_map_range, 845 .unmap_range = pci_device_linux_sysfs_unmap_range, 846 847 .read = pci_device_linux_sysfs_read, 848 .write = pci_device_linux_sysfs_write, 849 850 .fill_capabilities = pci_fill_capabilities_generic, 851 .enable = pci_device_linux_sysfs_enable, 852 .boot_vga = pci_device_linux_sysfs_boot_vga, 853 .has_kernel_driver = pci_device_linux_sysfs_has_kernel_driver, 854 855 .open_device_io = pci_device_linux_sysfs_open_device_io, 856 .open_legacy_io = pci_device_linux_sysfs_open_legacy_io, 857 .close_io = pci_device_linux_sysfs_close_io, 858 .read32 = pci_device_linux_sysfs_read32, 859 .read16 = pci_device_linux_sysfs_read16, 860 .read8 = pci_device_linux_sysfs_read8, 861 .write32 = pci_device_linux_sysfs_write32, 862 .write16 = pci_device_linux_sysfs_write16, 863 .write8 = pci_device_linux_sysfs_write8, 864 }; 865