Annotation of Gnu-Mach/linux/src/drivers/net/pci-scan.c, revision 1.1

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:  */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.