Commit | Line | Data |
---|---|---|
8cfab3cf | 1 | // SPDX-License-Identifier: GPL-2.0 |
df62ab5e BH |
2 | /* |
3 | * Simple stub driver to reserve a PCI device | |
c70e0d9d CW |
4 | * |
5 | * Copyright (C) 2008 Red Hat, Inc. | |
6 | * Author: | |
f7625980 | 7 | * Chris Wright |
c70e0d9d | 8 | * |
c70e0d9d CW |
9 | * Usage is simple, allocate a new id to the stub driver and bind the |
10 | * device to it. For example: | |
f7625980 | 11 | * |
c70e0d9d CW |
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 | ||
b439b1d4 TH |
22 | static char ids[1024] __initdata; |
23 | ||
24 | module_param_string(ids, ids, sizeof(ids), 0); | |
25 | MODULE_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 | ||
c70e0d9d CW |
29 | static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id) |
30 | { | |
7506dc79 | 31 | pci_info(dev, "claimed by stub\n"); |
c70e0d9d CW |
32 | return 0; |
33 | } | |
34 | ||
35 | static struct pci_driver stub_driver = { | |
36 | .name = "pci-stub", | |
37 | .id_table = NULL, /* only dynamic id's */ | |
38 | .probe = pci_stub_probe, | |
18c7a349 | 39 | .driver_managed_dma = true, |
c70e0d9d CW |
40 | }; |
41 | ||
42 | static int __init pci_stub_init(void) | |
43 | { | |
b439b1d4 TH |
44 | char *p, *id; |
45 | int rc; | |
46 | ||
47 | rc = pci_register_driver(&stub_driver); | |
48 | if (rc) | |
49 | return rc; | |
50 | ||
ee8abf78 YL |
51 | /* no ids passed actually */ |
52 | if (ids[0] == '\0') | |
53 | return 0; | |
54 | ||
b439b1d4 TH |
55 | /* add ids specified in the module parameter */ |
56 | p = ids; | |
57 | while ((id = strsep(&p, ","))) { | |
58 | unsigned int vendor, device, subvendor = PCI_ANY_ID, | |
3c78bc61 | 59 | subdevice = PCI_ANY_ID, class = 0, class_mask = 0; |
b439b1d4 TH |
60 | int fields; |
61 | ||
99a0fadf TH |
62 | if (!strlen(id)) |
63 | continue; | |
64 | ||
b439b1d4 TH |
65 | fields = sscanf(id, "%x:%x:%x:%x:%x:%x", |
66 | &vendor, &device, &subvendor, &subdevice, | |
67 | &class, &class_mask); | |
68 | ||
69 | if (fields < 2) { | |
25da8dba | 70 | pr_warn("pci-stub: invalid ID string \"%s\"\n", id); |
b439b1d4 TH |
71 | continue; |
72 | } | |
73 | ||
25da8dba | 74 | pr_info("pci-stub: add %04X:%04X sub=%04X:%04X cls=%08X/%08X\n", |
b439b1d4 TH |
75 | vendor, device, subvendor, subdevice, class, class_mask); |
76 | ||
77 | rc = pci_add_dynid(&stub_driver, vendor, device, | |
78 | subvendor, subdevice, class, class_mask, 0); | |
79 | if (rc) | |
25da8dba MK |
80 | pr_warn("pci-stub: failed to add dynamic ID (%d)\n", |
81 | rc); | |
b439b1d4 TH |
82 | } |
83 | ||
84 | return 0; | |
c70e0d9d CW |
85 | } |
86 | ||
87 | static void __exit pci_stub_exit(void) | |
88 | { | |
89 | pci_unregister_driver(&stub_driver); | |
90 | } | |
91 | ||
92 | module_init(pci_stub_init); | |
93 | module_exit(pci_stub_exit); | |
94 | ||
95 | MODULE_LICENSE("GPL"); | |
96 | MODULE_AUTHOR("Chris Wright <chrisw@sous-sol.org>"); |