|
|
1.1 ! root 1: /* pci-scan.c: Linux PCI network adapter support code. */ ! 2: /* ! 3: Originally written 1999-2003 by Donald Becker. ! 4: ! 5: This software may be used and distributed according to the terms ! 6: of the GNU General Public License (GPL), incorporated herein by ! 7: reference. Drivers interacting with these functions are derivative ! 8: works and thus also must be licensed under the GPL and include an explicit ! 9: GPL notice. ! 10: ! 11: This code provides common scan and activate functions for PCI network ! 12: interfaces. ! 13: ! 14: The author may be reached as [email protected], or ! 15: Donald Becker ! 16: Scyld Computing Corporation ! 17: 914 Bay Ridge Road, Suite 220 ! 18: Annapolis MD 21403 ! 19: ! 20: Other contributers: ! 21: */ ! 22: static const char version[] = ! 23: "pci-scan.c:v1.12 7/30/2003 Donald Becker <[email protected]>" ! 24: " http://www.scyld.com/linux/drivers.html\n"; ! 25: ! 26: /* A few user-configurable values that may be modified when a module. */ ! 27: ! 28: static int msg_level = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ ! 29: static int min_pci_latency = 32; ! 30: ! 31: #if ! defined(__KERNEL__) ! 32: #define __KERNEL__ 1 ! 33: #endif ! 34: #if !defined(__OPTIMIZE__) ! 35: #warning You must compile this file with the correct options! ! 36: #warning See the last lines of the source file. ! 37: #error You must compile this driver with the proper options, including "-O". ! 38: #endif ! 39: ! 40: #if defined(MODULE) && ! defined(EXPORT_SYMTAB) ! 41: #define EXPORT_SYMTAB ! 42: #endif ! 43: ! 44: #include <linux/config.h> ! 45: #if defined(CONFIG_SMP) && ! defined(__SMP__) ! 46: #define __SMP__ ! 47: #endif ! 48: #if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS) ! 49: #define MODVERSIONS ! 50: #endif ! 51: ! 52: #include <linux/version.h> ! 53: #if defined(MODVERSIONS) ! 54: #include <linux/modversions.h> ! 55: #endif ! 56: #if LINUX_VERSION_CODE < 0x20500 && defined(MODVERSIONS) ! 57: /* Another interface semantics screw-up. */ ! 58: #include <linux/module.h> ! 59: #include <linux/modversions.h> ! 60: #else ! 61: #include <linux/module.h> ! 62: #endif ! 63: ! 64: #include <linux/kernel.h> ! 65: #include <linux/mm.h> ! 66: #include <linux/errno.h> ! 67: #include <linux/types.h> ! 68: #include <linux/pci.h> ! 69: #include <linux/ioport.h> ! 70: #if LINUX_VERSION_CODE >= 0x20300 ! 71: /* Bogus change in the middle of a "stable" kernel series. ! 72: Also, in 2.4.7+ slab must come before interrupt.h to avoid breakage. */ ! 73: #include <linux/slab.h> ! 74: #else ! 75: #include <linux/malloc.h> ! 76: #endif ! 77: #include <asm/io.h> ! 78: #include "pci-scan.h" ! 79: #include "kern_compat.h" ! 80: #if defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 ! 81: #include <linux/apm_bios.h> ! 82: #endif ! 83: #ifdef CONFIG_PM ! 84: /* New in 2.4 kernels, pointlessly incompatible with earlier APM. */ ! 85: #include <linux/pm.h> ! 86: #endif ! 87: ! 88: #if (LINUX_VERSION_CODE >= 0x20100) && defined(MODULE) ! 89: char kernel_version[] = UTS_RELEASE; ! 90: #endif ! 91: #if (LINUX_VERSION_CODE < 0x20100) ! 92: #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ ! 93: #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ ! 94: #define PCI_CAP_ID_PM 0x01 /* Power Management */ ! 95: #endif ! 96: ! 97: int (*register_hotswap_hook)(struct drv_id_info *did); ! 98: void (*unregister_hotswap_hook)(struct drv_id_info *did); ! 99: ! 100: #if LINUX_VERSION_CODE > 0x20118 && defined(MODULE) ! 101: MODULE_LICENSE("GPL"); ! 102: MODULE_PARM(msg_level, "i"); ! 103: MODULE_PARM(min_pci_latency, "i"); ! 104: MODULE_PARM_DESC(msg_level, "Enable additional status messages (0-7)"); ! 105: MODULE_PARM_DESC(min_pci_latency, ! 106: "Minimum value for the PCI Latency Timer settings"); ! 107: #if defined(EXPORT_SYMTAB) ! 108: EXPORT_SYMBOL_NOVERS(pci_drv_register); ! 109: EXPORT_SYMBOL_NOVERS(pci_drv_unregister); ! 110: EXPORT_SYMBOL_NOVERS(acpi_wake); ! 111: EXPORT_SYMBOL_NOVERS(acpi_set_pwr_state); ! 112: EXPORT_SYMBOL_NOVERS(register_hotswap_hook); ! 113: EXPORT_SYMBOL_NOVERS(unregister_hotswap_hook); ! 114: #endif ! 115: #endif ! 116: ! 117: /* List of registered drivers. */ ! 118: static struct drv_id_info *drv_list; ! 119: /* List of detected PCI devices, for APM events. */ ! 120: static struct dev_info { ! 121: struct dev_info *next; ! 122: void *dev; ! 123: struct drv_id_info *drv_id; ! 124: int flags; ! 125: } *dev_list; ! 126: ! 127: /* ! 128: This code is not intended to support every configuration. ! 129: It is intended to minimize duplicated code by providing the functions ! 130: needed in almost every PCI driver. ! 131: ! 132: The "no kitchen sink" policy: ! 133: Additional features and code will be added to this module only if more ! 134: than half of the drivers for common hardware would benefit from the feature. ! 135: */ ! 136: ! 137: /* ! 138: Ideally we would detect and number all cards of a type (e.g. network) in ! 139: PCI slot order. ! 140: But that does not work with hot-swap card, CardBus cards and added drivers. ! 141: So instead we detect just the each chip table in slot order. ! 142: ! 143: This routine takes a PCI ID table, scans the PCI bus, and calls the ! 144: associated attach/probe1 routine with the hardware already activated and ! 145: single I/O or memory address already mapped. ! 146: ! 147: This routine will later be supplemented with CardBus and hot-swap PCI ! 148: support using the same table. Thus the pci_chip_tbl[] should not be ! 149: marked as __initdata. ! 150: */ ! 151: ! 152: #if LINUX_VERSION_CODE >= 0x20200 ! 153: /* Grrrr.. complex abstaction layers with negative benefit. */ ! 154: int pci_drv_register(struct drv_id_info *drv_id, void *initial_device) ! 155: { ! 156: int chip_idx, cards_found = 0; ! 157: struct pci_dev *pdev = NULL; ! 158: struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl; ! 159: struct drv_id_info *drv; ! 160: void *newdev; ! 161: ! 162: ! 163: /* Ignore a double-register attempt. */ ! 164: for (drv = drv_list; drv; drv = drv->next) ! 165: if (drv == drv_id) ! 166: return -EBUSY; ! 167: ! 168: while ((pdev = pci_find_class(drv_id->pci_class, pdev)) != 0) { ! 169: u32 pci_id, pci_subsys_id, pci_class_rev; ! 170: u16 pci_command, new_command; ! 171: int pci_flags; ! 172: long pciaddr; /* Bus address. */ ! 173: long ioaddr; /* Mapped address for this processor. */ ! 174: ! 175: pci_read_config_dword(pdev, PCI_VENDOR_ID, &pci_id); ! 176: /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */ ! 177: pci_read_config_dword(pdev, 0x2c, &pci_subsys_id); ! 178: pci_read_config_dword(pdev, PCI_REVISION_ID, &pci_class_rev); ! 179: ! 180: if (msg_level > 3) ! 181: printk(KERN_DEBUG "PCI ID %8.8x subsystem ID is %8.8x.\n", ! 182: pci_id, pci_subsys_id); ! 183: for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { ! 184: struct pci_id_info *chip = &pci_tbl[chip_idx]; ! 185: if ((pci_id & chip->id.pci_mask) == chip->id.pci ! 186: && (pci_subsys_id&chip->id.subsystem_mask) == chip->id.subsystem ! 187: && (pci_class_rev&chip->id.revision_mask) == chip->id.revision) ! 188: break; ! 189: } ! 190: if (pci_tbl[chip_idx].name == 0) /* Compiled out! */ ! 191: continue; ! 192: ! 193: pci_flags = pci_tbl[chip_idx].pci_flags; ! 194: #if LINUX_VERSION_CODE >= 0x2030C ! 195: /* Wow. A oversized, hard-to-use abstraction. Bogus. */ ! 196: pciaddr = pdev->resource[(pci_flags >> 4) & 7].start; ! 197: #else ! 198: pciaddr = pdev->base_address[(pci_flags >> 4) & 7]; ! 199: #if defined(__alpha__) /* Really any machine with 64 bit addressing. */ ! 200: if (pci_flags & PCI_ADDR_64BITS) ! 201: pciaddr |= ((long)pdev->base_address[((pci_flags>>4)&7)+ 1]) << 32; ! 202: #endif ! 203: #endif ! 204: if (msg_level > 2) ! 205: printk(KERN_INFO "Found %s at PCI address %#lx, mapped IRQ %d.\n", ! 206: pci_tbl[chip_idx].name, pciaddr, pdev->irq); ! 207: ! 208: if ( ! (pci_flags & PCI_UNUSED_IRQ) && ! 209: (pdev->irq == 0 || pdev->irq == 255)) { ! 210: if (pdev->bus->number == 32) /* Broken CardBus activation. */ ! 211: printk(KERN_WARNING "Resources for CardBus device '%s' have" ! 212: " not been allocated.\n" ! 213: KERN_WARNING "Activation has been delayed.\n", ! 214: pci_tbl[chip_idx].name); ! 215: else ! 216: printk(KERN_WARNING "PCI device '%s' was not assigned an " ! 217: "IRQ.\n" ! 218: KERN_WARNING "It will not be activated.\n", ! 219: pci_tbl[chip_idx].name); ! 220: continue; ! 221: } ! 222: if ((pci_flags & PCI_BASE_ADDRESS_SPACE_IO)) { ! 223: ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK; ! 224: if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) ! 225: continue; ! 226: } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK, ! 227: pci_tbl[chip_idx].io_size)) == 0) { ! 228: printk(KERN_INFO "Failed to map PCI address %#lx for device " ! 229: "'%s'.\n", pciaddr, pci_tbl[chip_idx].name); ! 230: continue; ! 231: } ! 232: if ( ! (pci_flags & PCI_NO_ACPI_WAKE)) ! 233: acpi_wake(pdev); ! 234: pci_read_config_word(pdev, PCI_COMMAND, &pci_command); ! 235: new_command = pci_command | (pci_flags & 7); ! 236: if (pci_command != new_command) { ! 237: printk(KERN_INFO " The PCI BIOS has not enabled the" ! 238: " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", ! 239: pdev->bus->number, pdev->devfn, pci_command, new_command); ! 240: pci_write_config_word(pdev, PCI_COMMAND, new_command); ! 241: } ! 242: ! 243: newdev = drv_id->probe1(pdev, initial_device, ! 244: ioaddr, pdev->irq, chip_idx, cards_found); ! 245: if (newdev == NULL) ! 246: continue; ! 247: initial_device = 0; ! 248: cards_found++; ! 249: if (pci_flags & PCI_COMMAND_MASTER) { ! 250: pci_set_master(pdev); ! 251: if ( ! (pci_flags & PCI_NO_MIN_LATENCY)) { ! 252: u8 pci_latency; ! 253: pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); ! 254: if (pci_latency < min_pci_latency) { ! 255: printk(KERN_INFO " PCI latency timer (CFLT) is " ! 256: "unreasonably low at %d. Setting to %d clocks.\n", ! 257: pci_latency, min_pci_latency); ! 258: pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ! 259: min_pci_latency); ! 260: } ! 261: } ! 262: } ! 263: { ! 264: struct dev_info *devp = ! 265: kmalloc(sizeof(struct dev_info), GFP_KERNEL); ! 266: if (devp == 0) ! 267: continue; ! 268: devp->next = dev_list; ! 269: devp->dev = newdev; ! 270: devp->drv_id = drv_id; ! 271: dev_list = devp; ! 272: } ! 273: } ! 274: ! 275: if (((drv_id->flags & PCI_HOTSWAP) ! 276: && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0) ! 277: || cards_found) { ! 278: MOD_INC_USE_COUNT; ! 279: drv_id->next = drv_list; ! 280: drv_list = drv_id; ! 281: return 0; ! 282: } else ! 283: return -ENODEV; ! 284: } ! 285: #else ! 286: int pci_drv_register(struct drv_id_info *drv_id, void *initial_device) ! 287: { ! 288: int pci_index, cards_found = 0; ! 289: unsigned char pci_bus, pci_device_fn; ! 290: struct pci_dev *pdev; ! 291: struct pci_id_info *pci_tbl = drv_id->pci_dev_tbl; ! 292: void *newdev; ! 293: ! 294: if ( ! pcibios_present()) ! 295: return -ENODEV; ! 296: ! 297: for (pci_index = 0; pci_index < 0xff; pci_index++) { ! 298: u32 pci_id, subsys_id, pci_class_rev; ! 299: u16 pci_command, new_command; ! 300: int chip_idx, irq, pci_flags; ! 301: long pciaddr; ! 302: long ioaddr; ! 303: u32 pci_busaddr; ! 304: u8 pci_irq_line; ! 305: ! 306: if (pcibios_find_class (drv_id->pci_class, pci_index, ! 307: &pci_bus, &pci_device_fn) ! 308: != PCIBIOS_SUCCESSFUL) ! 309: break; ! 310: pcibios_read_config_dword(pci_bus, pci_device_fn, ! 311: PCI_VENDOR_ID, &pci_id); ! 312: /* Offset 0x2c is PCI_SUBSYSTEM_ID aka PCI_SUBSYSTEM_VENDOR_ID. */ ! 313: pcibios_read_config_dword(pci_bus, pci_device_fn, 0x2c, &subsys_id); ! 314: pcibios_read_config_dword(pci_bus, pci_device_fn, ! 315: PCI_REVISION_ID, &pci_class_rev); ! 316: ! 317: for (chip_idx = 0; pci_tbl[chip_idx].name; chip_idx++) { ! 318: struct pci_id_info *chip = &pci_tbl[chip_idx]; ! 319: if ((pci_id & chip->id.pci_mask) == chip->id.pci ! 320: && (subsys_id & chip->id.subsystem_mask) == chip->id.subsystem ! 321: && (pci_class_rev&chip->id.revision_mask) == chip->id.revision) ! 322: break; ! 323: } ! 324: if (pci_tbl[chip_idx].name == 0) /* Compiled out! */ ! 325: continue; ! 326: ! 327: pci_flags = pci_tbl[chip_idx].pci_flags; ! 328: pdev = pci_find_slot(pci_bus, pci_device_fn); ! 329: pcibios_read_config_byte(pci_bus, pci_device_fn, ! 330: PCI_INTERRUPT_LINE, &pci_irq_line); ! 331: irq = pci_irq_line; ! 332: pcibios_read_config_dword(pci_bus, pci_device_fn, ! 333: ((pci_flags >> 2) & 0x1C) + 0x10, ! 334: &pci_busaddr); ! 335: pciaddr = pci_busaddr; ! 336: #if defined(__alpha__) ! 337: if (pci_flags & PCI_ADDR_64BITS) { ! 338: pcibios_read_config_dword(pci_bus, pci_device_fn, ! 339: ((pci_flags >> 2) & 0x1C) + 0x14, ! 340: &pci_busaddr); ! 341: pciaddr |= ((long)pci_busaddr)<<32; ! 342: } ! 343: #endif ! 344: ! 345: if (msg_level > 2) ! 346: printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n", ! 347: pci_tbl[chip_idx].name, pciaddr, irq); ! 348: ! 349: if ( ! (pci_flags & PCI_UNUSED_IRQ) && ! 350: (irq == 0 || irq >= 16)) { ! 351: if (pci_bus == 32) /* Broken CardBus activation. */ ! 352: printk(KERN_WARNING "Resources for CardBus device '%s' have" ! 353: " not been allocated.\n" ! 354: KERN_WARNING "It will not be activated.\n", ! 355: pci_tbl[chip_idx].name); ! 356: else ! 357: printk(KERN_WARNING "PCI device '%s' was not assigned an " ! 358: "IRQ.\n" ! 359: KERN_WARNING "It will not be activated.\n", ! 360: pci_tbl[chip_idx].name); ! 361: continue; ! 362: } ! 363: ! 364: if ((pciaddr & PCI_BASE_ADDRESS_SPACE_IO)) { ! 365: ioaddr = pciaddr & PCI_BASE_ADDRESS_IO_MASK; ! 366: if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) ! 367: continue; ! 368: } else if ((ioaddr = (long)ioremap(pciaddr & PCI_BASE_ADDRESS_MEM_MASK, ! 369: pci_tbl[chip_idx].io_size)) == 0) { ! 370: printk(KERN_INFO "Failed to map PCI address %#lx.\n", ! 371: pciaddr); ! 372: continue; ! 373: } ! 374: ! 375: if ( ! (pci_flags & PCI_NO_ACPI_WAKE)) ! 376: acpi_wake(pdev); ! 377: pcibios_read_config_word(pci_bus, pci_device_fn, ! 378: PCI_COMMAND, &pci_command); ! 379: new_command = pci_command | (pci_flags & 7); ! 380: if (pci_command != new_command) { ! 381: printk(KERN_INFO " The PCI BIOS has not enabled the" ! 382: " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", ! 383: pci_bus, pci_device_fn, pci_command, new_command); ! 384: pcibios_write_config_word(pci_bus, pci_device_fn, ! 385: PCI_COMMAND, new_command); ! 386: } ! 387: ! 388: newdev = drv_id->probe1(pdev, initial_device, ! 389: ioaddr, irq, chip_idx, cards_found); ! 390: ! 391: if (newdev && (pci_flags & PCI_COMMAND_MASTER) && ! 392: ! (pci_flags & PCI_NO_MIN_LATENCY)) { ! 393: u8 pci_latency; ! 394: pcibios_read_config_byte(pci_bus, pci_device_fn, ! 395: PCI_LATENCY_TIMER, &pci_latency); ! 396: if (pci_latency < min_pci_latency) { ! 397: printk(KERN_INFO " PCI latency timer (CFLT) is " ! 398: "unreasonably low at %d. Setting to %d clocks.\n", ! 399: pci_latency, min_pci_latency); ! 400: pcibios_write_config_byte(pci_bus, pci_device_fn, ! 401: PCI_LATENCY_TIMER, min_pci_latency); ! 402: } ! 403: } ! 404: if (newdev) { ! 405: struct dev_info *devp = ! 406: kmalloc(sizeof(struct dev_info), GFP_KERNEL); ! 407: if (devp) { ! 408: devp->next = dev_list; ! 409: devp->dev = newdev; ! 410: devp->drv_id = drv_id; ! 411: dev_list = devp; ! 412: } ! 413: } ! 414: initial_device = 0; ! 415: cards_found++; ! 416: } ! 417: ! 418: if (((drv_id->flags & PCI_HOTSWAP) ! 419: && register_hotswap_hook && (*register_hotswap_hook)(drv_id) == 0) ! 420: || cards_found) { ! 421: MOD_INC_USE_COUNT; ! 422: drv_id->next = drv_list; ! 423: drv_list = drv_id; ! 424: return 0; ! 425: } else ! 426: return cards_found ? 0 : -ENODEV; ! 427: } ! 428: #endif ! 429: ! 430: void pci_drv_unregister(struct drv_id_info *drv_id) ! 431: { ! 432: struct drv_id_info **drvp; ! 433: struct dev_info **devip = &dev_list; ! 434: ! 435: if (unregister_hotswap_hook) ! 436: (*unregister_hotswap_hook)(drv_id); ! 437: ! 438: for (drvp = &drv_list; *drvp; drvp = &(*drvp)->next) ! 439: if (*drvp == drv_id) { ! 440: *drvp = (*drvp)->next; ! 441: MOD_DEC_USE_COUNT; ! 442: break; ! 443: } ! 444: while (*devip) { ! 445: struct dev_info *thisdevi = *devip; ! 446: if (thisdevi->drv_id == drv_id) { ! 447: *devip = thisdevi->next; ! 448: kfree(thisdevi); ! 449: } else ! 450: devip = &(*devip)->next; ! 451: } ! 452: ! 453: return; ! 454: } ! 455: ! 456: #if LINUX_VERSION_CODE < 0x20400 ! 457: /* ! 458: Search PCI configuration space for the specified capability registers. ! 459: Return the index, or 0 on failure. ! 460: The 2.4 kernel now includes this function. ! 461: */ ! 462: int pci_find_capability(struct pci_dev *pdev, int findtype) ! 463: { ! 464: u16 pci_status, cap_type; ! 465: u8 pci_cap_idx; ! 466: int cap_idx; ! 467: ! 468: pci_read_config_word(pdev, PCI_STATUS, &pci_status); ! 469: if ( ! (pci_status & PCI_STATUS_CAP_LIST)) ! 470: return 0; ! 471: pci_read_config_byte(pdev, PCI_CAPABILITY_LIST, &pci_cap_idx); ! 472: cap_idx = pci_cap_idx; ! 473: for (cap_idx = pci_cap_idx; cap_idx; cap_idx = (cap_type >> 8) & 0xff) { ! 474: pci_read_config_word(pdev, cap_idx, &cap_type); ! 475: if ((cap_type & 0xff) == findtype) ! 476: return cap_idx; ! 477: } ! 478: return 0; ! 479: } ! 480: #endif ! 481: ! 482: /* Change a device from D3 (sleep) to D0 (active). ! 483: Return the old power state. ! 484: This is more complicated than you might first expect since most cards ! 485: forget all PCI config info during the transition! */ ! 486: int acpi_wake(struct pci_dev *pdev) ! 487: { ! 488: u32 base[5], romaddr; ! 489: u16 pci_command, pwr_command; ! 490: u8 pci_latency, pci_cacheline, irq; ! 491: int i, pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); ! 492: ! 493: if (pwr_cmd_idx == 0) ! 494: return 0; ! 495: pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); ! 496: if ((pwr_command & 3) == 0) ! 497: return 0; ! 498: pci_read_config_word(pdev, PCI_COMMAND, &pci_command); ! 499: for (i = 0; i < 5; i++) ! 500: pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, ! 501: &base[i]); ! 502: pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &romaddr); ! 503: pci_read_config_byte( pdev, PCI_LATENCY_TIMER, &pci_latency); ! 504: pci_read_config_byte( pdev, PCI_CACHE_LINE_SIZE, &pci_cacheline); ! 505: pci_read_config_byte( pdev, PCI_INTERRUPT_LINE, &irq); ! 506: ! 507: pci_write_config_word(pdev, pwr_cmd_idx + 4, 0x0000); ! 508: for (i = 0; i < 5; i++) ! 509: if (base[i]) ! 510: pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0 + i*4, ! 511: base[i]); ! 512: pci_write_config_dword(pdev, PCI_ROM_ADDRESS, romaddr); ! 513: pci_write_config_byte( pdev, PCI_INTERRUPT_LINE, irq); ! 514: pci_write_config_byte( pdev, PCI_CACHE_LINE_SIZE, pci_cacheline); ! 515: pci_write_config_byte( pdev, PCI_LATENCY_TIMER, pci_latency); ! 516: pci_write_config_word( pdev, PCI_COMMAND, pci_command | 5); ! 517: return pwr_command & 3; ! 518: } ! 519: ! 520: int acpi_set_pwr_state(struct pci_dev *pdev, enum acpi_pwr_state new_state) ! 521: { ! 522: u16 pwr_command; ! 523: int pwr_cmd_idx = pci_find_capability(pdev, PCI_CAP_ID_PM); ! 524: ! 525: if (pwr_cmd_idx == 0) ! 526: return 0; ! 527: pci_read_config_word(pdev, pwr_cmd_idx + 4, &pwr_command); ! 528: if ((pwr_command & 3) == ACPI_D3 && new_state != ACPI_D3) ! 529: acpi_wake(pdev); /* The complicated sequence. */ ! 530: pci_write_config_word(pdev, pwr_cmd_idx + 4, ! 531: (pwr_command & ~3) | new_state); ! 532: return pwr_command & 3; ! 533: } ! 534: ! 535: #if defined(CONFIG_PM) ! 536: static int handle_pm_event(struct pm_dev *dev, int event, void *data) ! 537: { ! 538: static int down = 0; ! 539: struct dev_info *devi; ! 540: int pwr_cmd = -1; ! 541: ! 542: if (msg_level > 1) ! 543: printk(KERN_DEBUG "pci-scan: Handling power event %d for driver " ! 544: "list %s...\n", ! 545: event, drv_list->name); ! 546: switch (event) { ! 547: case PM_SUSPEND: ! 548: if (down) { ! 549: printk(KERN_DEBUG "pci-scan: Received extra suspend event\n"); ! 550: break; ! 551: } ! 552: down = 1; ! 553: for (devi = dev_list; devi; devi = devi->next) ! 554: if (devi->drv_id->pwr_event) ! 555: devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND); ! 556: break; ! 557: case PM_RESUME: ! 558: if (!down) { ! 559: printk(KERN_DEBUG "pci-scan: Received bogus resume event\n"); ! 560: break; ! 561: } ! 562: for (devi = dev_list; devi; devi = devi->next) { ! 563: if (devi->drv_id->pwr_event) { ! 564: if (msg_level > 3) ! 565: printk(KERN_DEBUG "pci-scan: Calling resume for %s " ! 566: "device.\n", devi->drv_id->name); ! 567: devi->drv_id->pwr_event(devi->dev, DRV_RESUME); ! 568: } ! 569: } ! 570: down = 0; ! 571: break; ! 572: case PM_SET_WAKEUP: pwr_cmd = DRV_PWR_WakeOn; break; ! 573: case PM_EJECT: pwr_cmd = DRV_DETACH; break; ! 574: default: ! 575: printk(KERN_DEBUG "pci-scan: Unknown power management event %d.\n", ! 576: event); ! 577: } ! 578: if (pwr_cmd >= 0) ! 579: for (devi = dev_list; devi; devi = devi->next) ! 580: if (devi->drv_id->pwr_event) ! 581: devi->drv_id->pwr_event(devi->dev, pwr_cmd); ! 582: ! 583: return 0; ! 584: } ! 585: ! 586: #elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 ! 587: static int handle_apm_event(apm_event_t event) ! 588: { ! 589: static int down = 0; ! 590: struct dev_info *devi; ! 591: ! 592: if (msg_level > 1) ! 593: printk(KERN_DEBUG "pci-scan: Handling APM event %d for driver " ! 594: "list %s...\n", ! 595: event, drv_list->name); ! 596: return 0; ! 597: switch (event) { ! 598: case APM_SYS_SUSPEND: ! 599: case APM_USER_SUSPEND: ! 600: if (down) { ! 601: printk(KERN_DEBUG "pci-scan: Received extra suspend event\n"); ! 602: break; ! 603: } ! 604: down = 1; ! 605: for (devi = dev_list; devi; devi = devi->next) ! 606: if (devi->drv_id->pwr_event) ! 607: devi->drv_id->pwr_event(devi->dev, DRV_SUSPEND); ! 608: break; ! 609: case APM_NORMAL_RESUME: ! 610: case APM_CRITICAL_RESUME: ! 611: if (!down) { ! 612: printk(KERN_DEBUG "pci-scan: Received bogus resume event\n"); ! 613: break; ! 614: } ! 615: for (devi = dev_list; devi; devi = devi->next) ! 616: if (devi->drv_id->pwr_event) ! 617: devi->drv_id->pwr_event(devi->dev, DRV_RESUME); ! 618: down = 0; ! 619: break; ! 620: } ! 621: return 0; ! 622: } ! 623: #endif /* CONFIG_APM */ ! 624: ! 625: #ifdef MODULE ! 626: int init_module(void) ! 627: { ! 628: if (msg_level) /* Emit version even if no cards detected. */ ! 629: printk(KERN_INFO "%s", version); ! 630: ! 631: #if defined(CONFIG_PM) ! 632: pm_register(PM_PCI_DEV, 0, &handle_pm_event); ! 633: #elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 ! 634: apm_register_callback(&handle_apm_event); ! 635: #endif ! 636: return 0; ! 637: } ! 638: void cleanup_module(void) ! 639: { ! 640: #if defined(CONFIG_PM) ! 641: pm_unregister_all(&handle_pm_event); ! 642: #elif defined(CONFIG_APM) && LINUX_VERSION_CODE < 0x20400 ! 643: apm_unregister_callback(&handle_apm_event); ! 644: #endif ! 645: if (dev_list != NULL) ! 646: printk(KERN_WARNING "pci-scan: Unfreed device references.\n"); ! 647: return; ! 648: } ! 649: #endif ! 650: ! 651: ! 652: /* ! 653: * Local variables: ! 654: * compile-command: "gcc -DMODULE -D__KERNEL__ -DEXPORT_SYMTAB -Wall -Wstrict-prototypes -O6 -c pci-scan.c" ! 655: * c-indent-level: 4 ! 656: * c-basic-offset: 4 ! 657: * tab-width: 4 ! 658: * End: ! 659: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.