2 * This file contains quirk handling code for PnP devices
3 * Some devices do not report all their resources, and need to have extra
4 * resources added. This is most easily accomplished at initialisation time
5 * when building up the resource structure for the first time.
7 * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk>
8 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
9 * Bjorn Helgaas <bjorn.helgaas@hp.com>
11 * Heavily based on PCI quirks handling which is
13 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/slab.h>
20 #include <linux/pnp.h>
22 #include <linux/kallsyms.h>
25 static void quirk_awe32_add_ports(struct pnp_dev
*dev
,
26 struct pnp_option
*option
,
29 struct pnp_option
*new_option
;
31 new_option
= kmalloc(sizeof(struct pnp_option
), GFP_KERNEL
);
33 dev_err(&dev
->dev
, "couldn't add ioport region to option set "
34 "%d\n", pnp_option_set(option
));
38 *new_option
= *option
;
39 new_option
->u
.port
.min
+= offset
;
40 new_option
->u
.port
.max
+= offset
;
41 list_add(&new_option
->list
, &option
->list
);
43 dev_info(&dev
->dev
, "added ioport region %#llx-%#llx to set %d\n",
44 (unsigned long long) new_option
->u
.port
.min
,
45 (unsigned long long) new_option
->u
.port
.max
,
46 pnp_option_set(option
));
49 static void quirk_awe32_resources(struct pnp_dev
*dev
)
51 struct pnp_option
*option
;
52 unsigned int set
= ~0;
55 * Add two extra ioport regions (at offset 0x400 and 0x800 from the
56 * one given) to every dependent option set.
58 list_for_each_entry(option
, &dev
->options
, list
) {
59 if (pnp_option_is_dependent(option
) &&
60 pnp_option_set(option
) != set
) {
61 set
= pnp_option_set(option
);
62 quirk_awe32_add_ports(dev
, option
, 0x800);
63 quirk_awe32_add_ports(dev
, option
, 0x400);
68 static void quirk_cmi8330_resources(struct pnp_dev
*dev
)
70 struct pnp_option
*option
;
74 list_for_each_entry(option
, &dev
->options
, list
) {
75 if (!pnp_option_is_dependent(option
))
78 if (option
->type
== IORESOURCE_IRQ
) {
80 bitmap_zero(irq
->map
.bits
, PNP_IRQ_NR
);
81 __set_bit(5, irq
->map
.bits
);
82 __set_bit(7, irq
->map
.bits
);
83 __set_bit(10, irq
->map
.bits
);
84 dev_info(&dev
->dev
, "set possible IRQs in "
85 "option set %d to 5, 7, 10\n",
86 pnp_option_set(option
));
87 } else if (option
->type
== IORESOURCE_DMA
) {
89 if ((dma
->flags
& IORESOURCE_DMA_TYPE_MASK
) ==
90 IORESOURCE_DMA_8BIT
&&
92 dev_info(&dev
->dev
, "changing possible "
93 "DMA channel mask in option set %d "
94 "from %#02x to 0x0A (1, 3)\n",
95 pnp_option_set(option
), dma
->map
);
102 static void quirk_sb16audio_resources(struct pnp_dev
*dev
)
104 struct pnp_option
*option
;
105 unsigned int prev_option_flags
= ~0, n
= 0;
106 struct pnp_port
*port
;
109 * The default range on the OPL port for these devices is 0x388-0x388.
110 * Here we increase that range so that two such cards can be
113 list_for_each_entry(option
, &dev
->options
, list
) {
114 if (prev_option_flags
!= option
->flags
) {
115 prev_option_flags
= option
->flags
;
119 if (pnp_option_is_dependent(option
) &&
120 option
->type
== IORESOURCE_IO
) {
122 port
= &option
->u
.port
;
123 if (n
== 3 && port
->min
== port
->max
) {
125 dev_info(&dev
->dev
, "increased option port "
126 "range from %#llx-%#llx to "
128 (unsigned long long) port
->min
,
129 (unsigned long long) port
->min
,
130 (unsigned long long) port
->min
,
131 (unsigned long long) port
->max
);
137 static struct pnp_option
*pnp_clone_dependent_set(struct pnp_dev
*dev
,
140 struct pnp_option
*tail
= NULL
, *first_new_option
= NULL
;
141 struct pnp_option
*option
, *new_option
;
144 list_for_each_entry(option
, &dev
->options
, list
) {
145 if (pnp_option_is_dependent(option
))
149 dev_err(&dev
->dev
, "no dependent option sets\n");
153 flags
= pnp_new_dependent_set(dev
, PNP_RES_PRIORITY_FUNCTIONAL
);
154 list_for_each_entry(option
, &dev
->options
, list
) {
155 if (pnp_option_is_dependent(option
) &&
156 pnp_option_set(option
) == set
) {
157 new_option
= kmalloc(sizeof(struct pnp_option
),
160 dev_err(&dev
->dev
, "couldn't clone dependent "
165 *new_option
= *option
;
166 new_option
->flags
= flags
;
167 if (!first_new_option
)
168 first_new_option
= new_option
;
170 list_add(&new_option
->list
, &tail
->list
);
175 return first_new_option
;
179 static void quirk_add_irq_optional_dependent_sets(struct pnp_dev
*dev
)
181 struct pnp_option
*new_option
;
182 unsigned int num_sets
, i
, set
;
185 num_sets
= dev
->num_dependent_sets
;
186 for (i
= 0; i
< num_sets
; i
++) {
187 new_option
= pnp_clone_dependent_set(dev
, i
);
191 set
= pnp_option_set(new_option
);
192 while (new_option
&& pnp_option_set(new_option
) == set
) {
193 if (new_option
->type
== IORESOURCE_IRQ
) {
194 irq
= &new_option
->u
.irq
;
195 irq
->flags
|= IORESOURCE_IRQ_OPTIONAL
;
197 dbg_pnp_show_option(dev
, new_option
);
198 new_option
= list_entry(new_option
->list
.next
,
199 struct pnp_option
, list
);
202 dev_info(&dev
->dev
, "added dependent option set %d (same as "
203 "set %d except IRQ optional)\n", set
, i
);
207 static void quirk_ad1815_mpu_resources(struct pnp_dev
*dev
)
209 struct pnp_option
*option
;
210 struct pnp_irq
*irq
= NULL
;
211 unsigned int independent_irqs
= 0;
213 list_for_each_entry(option
, &dev
->options
, list
) {
214 if (option
->type
== IORESOURCE_IRQ
&&
215 !pnp_option_is_dependent(option
)) {
217 irq
= &option
->u
.irq
;
221 if (independent_irqs
!= 1)
224 irq
->flags
|= IORESOURCE_IRQ_OPTIONAL
;
225 dev_info(&dev
->dev
, "made independent IRQ optional\n");
228 #include <linux/pci.h>
230 static void quirk_system_pci_resources(struct pnp_dev
*dev
)
232 struct pci_dev
*pdev
= NULL
;
233 struct resource
*res
;
234 resource_size_t pnp_start
, pnp_end
, pci_start
, pci_end
;
238 * Some BIOSes have PNP motherboard devices with resources that
239 * partially overlap PCI BARs. The PNP system driver claims these
240 * motherboard resources, which prevents the normal PCI driver from
241 * requesting them later.
243 * This patch disables the PNP resources that conflict with PCI BARs
244 * so they won't be claimed by the PNP system driver.
246 for_each_pci_dev(pdev
) {
247 for (i
= 0; i
< DEVICE_COUNT_RESOURCE
; i
++) {
250 type
= pci_resource_flags(pdev
, i
) &
251 (IORESOURCE_IO
| IORESOURCE_MEM
);
252 if (!type
|| pci_resource_len(pdev
, i
) == 0)
255 pci_start
= pci_resource_start(pdev
, i
);
256 pci_end
= pci_resource_end(pdev
, i
);
258 (res
= pnp_get_resource(dev
, type
, j
)); j
++) {
259 if (res
->start
== 0 && res
->end
== 0)
262 pnp_start
= res
->start
;
266 * If the PNP region doesn't overlap the PCI
267 * region at all, there's no problem.
269 if (pnp_end
< pci_start
|| pnp_start
> pci_end
)
273 * If the PNP region completely encloses (or is
274 * at least as large as) the PCI region, that's
275 * also OK. For example, this happens when the
276 * PNP device describes a bridge with PCI
279 if (pnp_start
<= pci_start
&&
284 * Otherwise, the PNP region overlaps *part* of
285 * the PCI region, and that might prevent a PCI
286 * driver from requesting its resources.
289 "disabling %pR because it overlaps "
290 "%s BAR %d %pR\n", res
,
291 pci_name(pdev
), i
, &pdev
->resource
[i
]);
292 res
->flags
|= IORESOURCE_DISABLED
;
300 * Cards or devices that need some tweaking due to incomplete resource info
303 static struct pnp_fixup pnp_fixups
[] = {
304 /* Soundblaster awe io port quirk */
305 {"CTL0021", quirk_awe32_resources
},
306 {"CTL0022", quirk_awe32_resources
},
307 {"CTL0023", quirk_awe32_resources
},
308 /* CMI 8330 interrupt and dma fix */
309 {"@X@0001", quirk_cmi8330_resources
},
310 /* Soundblaster audio device io port range quirk */
311 {"CTL0001", quirk_sb16audio_resources
},
312 {"CTL0031", quirk_sb16audio_resources
},
313 {"CTL0041", quirk_sb16audio_resources
},
314 {"CTL0042", quirk_sb16audio_resources
},
315 {"CTL0043", quirk_sb16audio_resources
},
316 {"CTL0044", quirk_sb16audio_resources
},
317 {"CTL0045", quirk_sb16audio_resources
},
318 /* Add IRQ-optional MPU options */
319 {"ADS7151", quirk_ad1815_mpu_resources
},
320 {"ADS7181", quirk_add_irq_optional_dependent_sets
},
321 {"AZT0002", quirk_add_irq_optional_dependent_sets
},
322 /* PnP resources that might overlap PCI BARs */
323 {"PNP0c01", quirk_system_pci_resources
},
324 {"PNP0c02", quirk_system_pci_resources
},
328 void pnp_fixup_device(struct pnp_dev
*dev
)
332 for (f
= pnp_fixups
; *f
->id
; f
++) {
333 if (!compare_pnp_id(dev
->id
, f
->id
))
335 pnp_dbg(&dev
->dev
, "%s: calling %pF\n", f
->id
,
337 f
->quirk_function(dev
);