linux/drivers/pci/pci-stub.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Simple stub driver to reserve a PCI device
   4 *
   5 * Copyright (C) 2008 Red Hat, Inc.
   6 * Author:
   7 *      Chris Wright
   8 *
   9 * Usage is simple, allocate a new id to the stub driver and bind the
  10 * device to it.  For example:
  11 *
  12 * # echo "8086 10f5" > /sys/bus/pci/drivers/pci-stub/new_id
  13 * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
  14 * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/pci-stub/bind
  15 * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver
  16 * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/pci-stub
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/pci.h>
  21
  22static char ids[1024] __initdata;
  23
  24module_param_string(ids, ids, sizeof(ids), 0);
  25MODULE_PARM_DESC(ids, "Initial PCI IDs to add to the stub driver, format is "
  26                 "\"vendor:device[:subvendor[:subdevice[:class[:class_mask]]]]\""
  27                 " and multiple comma separated entries can be specified");
  28
  29static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id)
  30{
  31        pci_info(dev, "claimed by stub\n");
  32        return 0;
  33}
  34
  35static struct pci_driver stub_driver = {
  36        .name           = "pci-stub",
  37        .id_table       = NULL, /* only dynamic id's */
  38        .probe          = pci_stub_probe,
  39};
  40
  41static int __init pci_stub_init(void)
  42{
  43        char *p, *id;
  44        int rc;
  45
  46        rc = pci_register_driver(&stub_driver);
  47        if (rc)
  48                return rc;
  49
  50        /* no ids passed actually */
  51        if (ids[0] == '\0')
  52                return 0;
  53
  54        /* add ids specified in the module parameter */
  55        p = ids;
  56        while ((id = strsep(&p, ","))) {
  57                unsigned int vendor, device, subvendor = PCI_ANY_ID,
  58                        subdevice = PCI_ANY_ID, class = 0, class_mask = 0;
  59                int fields;
  60
  61                if (!strlen(id))
  62                        continue;
  63
  64                fields = sscanf(id, "%x:%x:%x:%x:%x:%x",
  65                                &vendor, &device, &subvendor, &subdevice,
  66                                &class, &class_mask);
  67
  68                if (fields < 2) {
  69                        pr_warn("pci-stub: invalid ID string \"%s\"\n", id);
  70                        continue;
  71                }
  72
  73                pr_info("pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n",
  74                       vendor, device, subvendor, subdevice, class, class_mask);
  75
  76                rc = pci_add_dynid(&stub_driver, vendor, device,
  77                                   subvendor, subdevice, class, class_mask, 0);
  78                if (rc)
  79                        pr_warn("pci-stub: failed to add dynamic ID (%d)\n",
  80                                rc);
  81        }
  82
  83        return 0;
  84}
  85
  86static void __exit pci_stub_exit(void)
  87{
  88        pci_unregister_driver(&stub_driver);
  89}
  90
  91module_init(pci_stub_init);
  92module_exit(pci_stub_exit);
  93
  94MODULE_LICENSE("GPL");
  95MODULE_AUTHOR("Chris Wright <chrisw@sous-sol.org>");
  96