162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI searching functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1993 -- 1997 Drew Eckhardt, Frederic Potter,
662306a36Sopenharmony_ci *					David Mosberger-Tang
762306a36Sopenharmony_ci * Copyright (C) 1997 -- 2000 Martin Mares <mj@ucw.cz>
862306a36Sopenharmony_ci * Copyright (C) 2003 -- 2004 Greg Kroah-Hartman <greg@kroah.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include "pci.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciDECLARE_RWSEM(pci_bus_sem);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * pci_for_each_dma_alias - Iterate over DMA aliases for a device
2162306a36Sopenharmony_ci * @pdev: starting downstream device
2262306a36Sopenharmony_ci * @fn: function to call for each alias
2362306a36Sopenharmony_ci * @data: opaque data to pass to @fn
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Starting @pdev, walk up the bus calling @fn for each possible alias
2662306a36Sopenharmony_ci * of @pdev at the root bus.
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ciint pci_for_each_dma_alias(struct pci_dev *pdev,
2962306a36Sopenharmony_ci			   int (*fn)(struct pci_dev *pdev,
3062306a36Sopenharmony_ci				     u16 alias, void *data), void *data)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct pci_bus *bus;
3362306a36Sopenharmony_ci	int ret;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/*
3662306a36Sopenharmony_ci	 * The device may have an explicit alias requester ID for DMA where the
3762306a36Sopenharmony_ci	 * requester is on another PCI bus.
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	pdev = pci_real_dma_dev(pdev);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	ret = fn(pdev, pci_dev_id(pdev), data);
4262306a36Sopenharmony_ci	if (ret)
4362306a36Sopenharmony_ci		return ret;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * If the device is broken and uses an alias requester ID for
4762306a36Sopenharmony_ci	 * DMA, iterate over that too.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	if (unlikely(pdev->dma_alias_mask)) {
5062306a36Sopenharmony_ci		unsigned int devfn;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		for_each_set_bit(devfn, pdev->dma_alias_mask, MAX_NR_DEVFNS) {
5362306a36Sopenharmony_ci			ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
5462306a36Sopenharmony_ci				 data);
5562306a36Sopenharmony_ci			if (ret)
5662306a36Sopenharmony_ci				return ret;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (bus = pdev->bus; !pci_is_root_bus(bus); bus = bus->parent) {
6162306a36Sopenharmony_ci		struct pci_dev *tmp;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		/* Skip virtual buses */
6462306a36Sopenharmony_ci		if (!bus->self)
6562306a36Sopenharmony_ci			continue;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		tmp = bus->self;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		/* stop at bridge where translation unit is associated */
7062306a36Sopenharmony_ci		if (tmp->dev_flags & PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT)
7162306a36Sopenharmony_ci			return ret;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		/*
7462306a36Sopenharmony_ci		 * PCIe-to-PCI/X bridges alias transactions from downstream
7562306a36Sopenharmony_ci		 * devices using the subordinate bus number (PCI Express to
7662306a36Sopenharmony_ci		 * PCI/PCI-X Bridge Spec, rev 1.0, sec 2.3).  For all cases
7762306a36Sopenharmony_ci		 * where the upstream bus is PCI/X we alias to the bridge
7862306a36Sopenharmony_ci		 * (there are various conditions in the previous reference
7962306a36Sopenharmony_ci		 * where the bridge may take ownership of transactions, even
8062306a36Sopenharmony_ci		 * when the secondary interface is PCI-X).
8162306a36Sopenharmony_ci		 */
8262306a36Sopenharmony_ci		if (pci_is_pcie(tmp)) {
8362306a36Sopenharmony_ci			switch (pci_pcie_type(tmp)) {
8462306a36Sopenharmony_ci			case PCI_EXP_TYPE_ROOT_PORT:
8562306a36Sopenharmony_ci			case PCI_EXP_TYPE_UPSTREAM:
8662306a36Sopenharmony_ci			case PCI_EXP_TYPE_DOWNSTREAM:
8762306a36Sopenharmony_ci				continue;
8862306a36Sopenharmony_ci			case PCI_EXP_TYPE_PCI_BRIDGE:
8962306a36Sopenharmony_ci				ret = fn(tmp,
9062306a36Sopenharmony_ci					 PCI_DEVID(tmp->subordinate->number,
9162306a36Sopenharmony_ci						   PCI_DEVFN(0, 0)), data);
9262306a36Sopenharmony_ci				if (ret)
9362306a36Sopenharmony_ci					return ret;
9462306a36Sopenharmony_ci				continue;
9562306a36Sopenharmony_ci			case PCI_EXP_TYPE_PCIE_BRIDGE:
9662306a36Sopenharmony_ci				ret = fn(tmp, pci_dev_id(tmp), data);
9762306a36Sopenharmony_ci				if (ret)
9862306a36Sopenharmony_ci					return ret;
9962306a36Sopenharmony_ci				continue;
10062306a36Sopenharmony_ci			}
10162306a36Sopenharmony_ci		} else {
10262306a36Sopenharmony_ci			if (tmp->dev_flags & PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS)
10362306a36Sopenharmony_ci				ret = fn(tmp,
10462306a36Sopenharmony_ci					 PCI_DEVID(tmp->subordinate->number,
10562306a36Sopenharmony_ci						   PCI_DEVFN(0, 0)), data);
10662306a36Sopenharmony_ci			else
10762306a36Sopenharmony_ci				ret = fn(tmp, pci_dev_id(tmp), data);
10862306a36Sopenharmony_ci			if (ret)
10962306a36Sopenharmony_ci				return ret;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return ret;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct pci_bus *child;
11962306a36Sopenharmony_ci	struct pci_bus *tmp;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (bus->number == busnr)
12262306a36Sopenharmony_ci		return bus;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	list_for_each_entry(tmp, &bus->children, node) {
12562306a36Sopenharmony_ci		child = pci_do_find_bus(tmp, busnr);
12662306a36Sopenharmony_ci		if (child)
12762306a36Sopenharmony_ci			return child;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	return NULL;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/**
13362306a36Sopenharmony_ci * pci_find_bus - locate PCI bus from a given domain and bus number
13462306a36Sopenharmony_ci * @domain: number of PCI domain to search
13562306a36Sopenharmony_ci * @busnr: number of desired PCI bus
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * Given a PCI bus number and domain number, the desired PCI bus is located
13862306a36Sopenharmony_ci * in the global list of PCI buses.  If the bus is found, a pointer to its
13962306a36Sopenharmony_ci * data structure is returned.  If no bus is found, %NULL is returned.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_cistruct pci_bus *pci_find_bus(int domain, int busnr)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct pci_bus *bus = NULL;
14462306a36Sopenharmony_ci	struct pci_bus *tmp_bus;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	while ((bus = pci_find_next_bus(bus)) != NULL)  {
14762306a36Sopenharmony_ci		if (pci_domain_nr(bus) != domain)
14862306a36Sopenharmony_ci			continue;
14962306a36Sopenharmony_ci		tmp_bus = pci_do_find_bus(bus, busnr);
15062306a36Sopenharmony_ci		if (tmp_bus)
15162306a36Sopenharmony_ci			return tmp_bus;
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci	return NULL;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ciEXPORT_SYMBOL(pci_find_bus);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/**
15862306a36Sopenharmony_ci * pci_find_next_bus - begin or continue searching for a PCI bus
15962306a36Sopenharmony_ci * @from: Previous PCI bus found, or %NULL for new search.
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * Iterates through the list of known PCI buses.  A new search is
16262306a36Sopenharmony_ci * initiated by passing %NULL as the @from argument.  Otherwise if
16362306a36Sopenharmony_ci * @from is not %NULL, searches continue from next device on the
16462306a36Sopenharmony_ci * global list.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistruct pci_bus *pci_find_next_bus(const struct pci_bus *from)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct list_head *n;
16962306a36Sopenharmony_ci	struct pci_bus *b = NULL;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	down_read(&pci_bus_sem);
17262306a36Sopenharmony_ci	n = from ? from->node.next : pci_root_buses.next;
17362306a36Sopenharmony_ci	if (n != &pci_root_buses)
17462306a36Sopenharmony_ci		b = list_entry(n, struct pci_bus, node);
17562306a36Sopenharmony_ci	up_read(&pci_bus_sem);
17662306a36Sopenharmony_ci	return b;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ciEXPORT_SYMBOL(pci_find_next_bus);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/**
18162306a36Sopenharmony_ci * pci_get_slot - locate PCI device for a given PCI slot
18262306a36Sopenharmony_ci * @bus: PCI bus on which desired PCI device resides
18362306a36Sopenharmony_ci * @devfn: encodes number of PCI slot in which the desired PCI
18462306a36Sopenharmony_ci * device resides and the logical device number within that slot
18562306a36Sopenharmony_ci * in case of multi-function devices.
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * Given a PCI bus and slot/function number, the desired PCI device
18862306a36Sopenharmony_ci * is located in the list of PCI devices.
18962306a36Sopenharmony_ci * If the device is found, its reference count is increased and this
19062306a36Sopenharmony_ci * function returns a pointer to its data structure.  The caller must
19162306a36Sopenharmony_ci * decrement the reference count by calling pci_dev_put().
19262306a36Sopenharmony_ci * If no device is found, %NULL is returned.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistruct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	struct pci_dev *dev;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	down_read(&pci_bus_sem);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
20162306a36Sopenharmony_ci		if (dev->devfn == devfn)
20262306a36Sopenharmony_ci			goto out;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	dev = NULL;
20662306a36Sopenharmony_ci out:
20762306a36Sopenharmony_ci	pci_dev_get(dev);
20862306a36Sopenharmony_ci	up_read(&pci_bus_sem);
20962306a36Sopenharmony_ci	return dev;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ciEXPORT_SYMBOL(pci_get_slot);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/**
21462306a36Sopenharmony_ci * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
21562306a36Sopenharmony_ci * @domain: PCI domain/segment on which the PCI device resides.
21662306a36Sopenharmony_ci * @bus: PCI bus on which desired PCI device resides
21762306a36Sopenharmony_ci * @devfn: encodes number of PCI slot in which the desired PCI device
21862306a36Sopenharmony_ci * resides and the logical device number within that slot in case of
21962306a36Sopenharmony_ci * multi-function devices.
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * Given a PCI domain, bus, and slot/function number, the desired PCI
22262306a36Sopenharmony_ci * device is located in the list of PCI devices. If the device is
22362306a36Sopenharmony_ci * found, its reference count is increased and this function returns a
22462306a36Sopenharmony_ci * pointer to its data structure.  The caller must decrement the
22562306a36Sopenharmony_ci * reference count by calling pci_dev_put().  If no device is found,
22662306a36Sopenharmony_ci * %NULL is returned.
22762306a36Sopenharmony_ci */
22862306a36Sopenharmony_cistruct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
22962306a36Sopenharmony_ci					    unsigned int devfn)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct pci_dev *dev = NULL;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	for_each_pci_dev(dev) {
23462306a36Sopenharmony_ci		if (pci_domain_nr(dev->bus) == domain &&
23562306a36Sopenharmony_ci		    (dev->bus->number == bus && dev->devfn == devfn))
23662306a36Sopenharmony_ci			return dev;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	return NULL;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ciEXPORT_SYMBOL(pci_get_domain_bus_and_slot);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic int match_pci_dev_by_id(struct device *dev, const void *data)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
24562306a36Sopenharmony_ci	const struct pci_device_id *id = data;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (pci_match_one_device(id, pdev))
24862306a36Sopenharmony_ci		return 1;
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/*
25362306a36Sopenharmony_ci * pci_get_dev_by_id - begin or continue searching for a PCI device by id
25462306a36Sopenharmony_ci * @id: pointer to struct pci_device_id to match for the device
25562306a36Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is found
25862306a36Sopenharmony_ci * with a matching id a pointer to its device structure is returned, and the
25962306a36Sopenharmony_ci * reference count to the device is incremented.  Otherwise, %NULL is returned.
26062306a36Sopenharmony_ci * A new search is initiated by passing %NULL as the @from argument.  Otherwise
26162306a36Sopenharmony_ci * if @from is not %NULL, searches continue from next device on the global
26262306a36Sopenharmony_ci * list.  The reference count for @from is always decremented if it is not
26362306a36Sopenharmony_ci * %NULL.
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci * This is an internal function for use by the other search functions in
26662306a36Sopenharmony_ci * this file.
26762306a36Sopenharmony_ci */
26862306a36Sopenharmony_cistatic struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
26962306a36Sopenharmony_ci					 struct pci_dev *from)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct device *dev;
27262306a36Sopenharmony_ci	struct device *dev_start = NULL;
27362306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (from)
27662306a36Sopenharmony_ci		dev_start = &from->dev;
27762306a36Sopenharmony_ci	dev = bus_find_device(&pci_bus_type, dev_start, (void *)id,
27862306a36Sopenharmony_ci			      match_pci_dev_by_id);
27962306a36Sopenharmony_ci	if (dev)
28062306a36Sopenharmony_ci		pdev = to_pci_dev(dev);
28162306a36Sopenharmony_ci	pci_dev_put(from);
28262306a36Sopenharmony_ci	return pdev;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/**
28662306a36Sopenharmony_ci * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
28762306a36Sopenharmony_ci * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
28862306a36Sopenharmony_ci * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
28962306a36Sopenharmony_ci * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
29062306a36Sopenharmony_ci * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
29162306a36Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is found
29462306a36Sopenharmony_ci * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
29562306a36Sopenharmony_ci * device structure is returned, and the reference count to the device is
29662306a36Sopenharmony_ci * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
29762306a36Sopenharmony_ci * passing %NULL as the @from argument.  Otherwise if @from is not %NULL,
29862306a36Sopenharmony_ci * searches continue from next device on the global list.
29962306a36Sopenharmony_ci * The reference count for @from is always decremented if it is not %NULL.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cistruct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
30262306a36Sopenharmony_ci			       unsigned int ss_vendor, unsigned int ss_device,
30362306a36Sopenharmony_ci			       struct pci_dev *from)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct pci_device_id id = {
30662306a36Sopenharmony_ci		.vendor = vendor,
30762306a36Sopenharmony_ci		.device = device,
30862306a36Sopenharmony_ci		.subvendor = ss_vendor,
30962306a36Sopenharmony_ci		.subdevice = ss_device,
31062306a36Sopenharmony_ci	};
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return pci_get_dev_by_id(&id, from);
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ciEXPORT_SYMBOL(pci_get_subsys);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * pci_get_device - begin or continue searching for a PCI device by vendor/device id
31862306a36Sopenharmony_ci * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
31962306a36Sopenharmony_ci * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
32062306a36Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is
32362306a36Sopenharmony_ci * found with a matching @vendor and @device, the reference count to the
32462306a36Sopenharmony_ci * device is incremented and a pointer to its device structure is returned.
32562306a36Sopenharmony_ci * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
32662306a36Sopenharmony_ci * as the @from argument.  Otherwise if @from is not %NULL, searches continue
32762306a36Sopenharmony_ci * from next device on the global list.  The reference count for @from is
32862306a36Sopenharmony_ci * always decremented if it is not %NULL.
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistruct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
33162306a36Sopenharmony_ci			       struct pci_dev *from)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ciEXPORT_SYMBOL(pci_get_device);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/**
33862306a36Sopenharmony_ci * pci_get_class - begin or continue searching for a PCI device by class
33962306a36Sopenharmony_ci * @class: search for a PCI device with this class designation
34062306a36Sopenharmony_ci * @from: Previous PCI device found in search, or %NULL for new search.
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci * Iterates through the list of known PCI devices.  If a PCI device is
34362306a36Sopenharmony_ci * found with a matching @class, the reference count to the device is
34462306a36Sopenharmony_ci * incremented and a pointer to its device structure is returned.
34562306a36Sopenharmony_ci * Otherwise, %NULL is returned.
34662306a36Sopenharmony_ci * A new search is initiated by passing %NULL as the @from argument.
34762306a36Sopenharmony_ci * Otherwise if @from is not %NULL, searches continue from next device
34862306a36Sopenharmony_ci * on the global list.  The reference count for @from is always decremented
34962306a36Sopenharmony_ci * if it is not %NULL.
35062306a36Sopenharmony_ci */
35162306a36Sopenharmony_cistruct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct pci_device_id id = {
35462306a36Sopenharmony_ci		.vendor = PCI_ANY_ID,
35562306a36Sopenharmony_ci		.device = PCI_ANY_ID,
35662306a36Sopenharmony_ci		.subvendor = PCI_ANY_ID,
35762306a36Sopenharmony_ci		.subdevice = PCI_ANY_ID,
35862306a36Sopenharmony_ci		.class_mask = PCI_ANY_ID,
35962306a36Sopenharmony_ci		.class = class,
36062306a36Sopenharmony_ci	};
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return pci_get_dev_by_id(&id, from);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ciEXPORT_SYMBOL(pci_get_class);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci/**
36762306a36Sopenharmony_ci * pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
36862306a36Sopenharmony_ci * @ids: A pointer to a null terminated list of struct pci_device_id structures
36962306a36Sopenharmony_ci * that describe the type of PCI device the caller is trying to find.
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * Obvious fact: You do not have a reference to any device that might be found
37262306a36Sopenharmony_ci * by this function, so if that device is removed from the system right after
37362306a36Sopenharmony_ci * this function is finished, the value will be stale.  Use this function to
37462306a36Sopenharmony_ci * find devices that are usually built into a system, or for a general hint as
37562306a36Sopenharmony_ci * to if another device happens to be present at this specific moment in time.
37662306a36Sopenharmony_ci */
37762306a36Sopenharmony_ciint pci_dev_present(const struct pci_device_id *ids)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	struct pci_dev *found = NULL;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	while (ids->vendor || ids->subvendor || ids->class_mask) {
38262306a36Sopenharmony_ci		found = pci_get_dev_by_id(ids, NULL);
38362306a36Sopenharmony_ci		if (found) {
38462306a36Sopenharmony_ci			pci_dev_put(found);
38562306a36Sopenharmony_ci			return 1;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci		ids++;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	return 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ciEXPORT_SYMBOL(pci_dev_present);
393