Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[wrt350n-kernel.git] / drivers / pnp / quirks.c
blob48a0ea8090e352c5db554277f8a7598d94db915d
1 /*
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>
9 * Heavily based on PCI quirks handling which is
11 * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
14 #include <linux/types.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/slab.h>
18 #include <linux/pnp.h>
19 #include <linux/io.h>
20 <<<<<<< HEAD:drivers/pnp/quirks.c
21 #include <linux/dmi.h>
22 =======
23 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
24 #include <linux/kallsyms.h>
25 #include "base.h"
27 static void quirk_awe32_resources(struct pnp_dev *dev)
29 struct pnp_port *port, *port2, *port3;
30 struct pnp_option *res = dev->dependent;
33 * Unfortunately the isapnp_add_port_resource is too tightly bound
34 * into the PnP discovery sequence, and cannot be used. Link in the
35 * two extra ports (at offset 0x400 and 0x800 from the one given) by
36 * hand.
38 for (; res; res = res->next) {
39 port2 = pnp_alloc(sizeof(struct pnp_port));
40 if (!port2)
41 return;
42 port3 = pnp_alloc(sizeof(struct pnp_port));
43 if (!port3) {
44 kfree(port2);
45 return;
47 port = res->port;
48 memcpy(port2, port, sizeof(struct pnp_port));
49 memcpy(port3, port, sizeof(struct pnp_port));
50 port->next = port2;
51 port2->next = port3;
52 port2->min += 0x400;
53 port2->max += 0x400;
54 port3->min += 0x800;
55 port3->max += 0x800;
57 printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n");
60 static void quirk_cmi8330_resources(struct pnp_dev *dev)
62 struct pnp_option *res = dev->dependent;
63 unsigned long tmp;
65 for (; res; res = res->next) {
67 struct pnp_irq *irq;
68 struct pnp_dma *dma;
70 for (irq = res->irq; irq; irq = irq->next) { // Valid irqs are 5, 7, 10
71 tmp = 0x04A0;
72 bitmap_copy(irq->map, &tmp, 16); // 0000 0100 1010 0000
75 for (dma = res->dma; dma; dma = dma->next) // Valid 8bit dma channels are 1,3
76 if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
77 IORESOURCE_DMA_8BIT)
78 dma->map = 0x000A;
80 printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
83 static void quirk_sb16audio_resources(struct pnp_dev *dev)
85 struct pnp_port *port;
86 struct pnp_option *res = dev->dependent;
87 int changed = 0;
90 * The default range on the mpu port for these devices is 0x388-0x388.
91 * Here we increase that range so that two such cards can be
92 * auto-configured.
95 for (; res; res = res->next) {
96 port = res->port;
97 if (!port)
98 continue;
99 port = port->next;
100 if (!port)
101 continue;
102 port = port->next;
103 if (!port)
104 continue;
105 if (port->min != port->max)
106 continue;
107 port->max += 0x70;
108 changed = 1;
110 if (changed)
111 printk(KERN_INFO
112 "pnp: SB audio device quirk - increasing port range\n");
115 <<<<<<< HEAD:drivers/pnp/quirks.c
116 static void quirk_supermicro_h8dce_system(struct pnp_dev *dev)
117 =======
119 #include <linux/pci.h>
121 static void quirk_system_pci_resources(struct pnp_dev *dev)
122 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
124 <<<<<<< HEAD:drivers/pnp/quirks.c
125 int i;
126 static struct dmi_system_id supermicro_h8dce[] = {
128 .ident = "Supermicro H8DCE",
129 .matches = {
130 DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
131 DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"),
137 if (!dmi_check_system(supermicro_h8dce))
138 return;
139 =======
140 struct pci_dev *pdev = NULL;
141 resource_size_t pnp_start, pnp_end, pci_start, pci_end;
142 int i, j;
143 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
146 <<<<<<< HEAD:drivers/pnp/quirks.c
147 * On the Supermicro H8DCE, there's a system device with resources
148 * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP
149 * system device claims them, the sata_nv driver won't be able to.
150 * More details at:
151 * https://bugzilla.redhat.com/show_bug.cgi?id=280641
152 * https://bugzilla.redhat.com/show_bug.cgi?id=313491
153 * http://lkml.org/lkml/2008/1/9/449
154 * http://thread.gmane.org/gmane.linux.acpi.devel/27312
155 =======
156 * Some BIOSes have PNP motherboard devices with resources that
157 * partially overlap PCI BARs. The PNP system driver claims these
158 * motherboard resources, which prevents the normal PCI driver from
159 * requesting them later.
161 * This patch disables the PNP resources that conflict with PCI BARs
162 * so they won't be claimed by the PNP system driver.
163 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
165 <<<<<<< HEAD:drivers/pnp/quirks.c
166 for (i = 0; i < PNP_MAX_MEM; i++) {
167 if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) &&
168 (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) {
169 dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent"
170 " conflict with sata_nv PCI device\n",
171 (unsigned long long) pnp_mem_start(dev, i),
172 (unsigned long long) (pnp_mem_start(dev, i) +
173 pnp_mem_len(dev, i) - 1));
174 pnp_mem_flags(dev, i) = 0;
175 =======
176 for_each_pci_dev(pdev) {
177 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
178 if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM) ||
179 pci_resource_len(pdev, i) == 0)
180 continue;
182 pci_start = pci_resource_start(pdev, i);
183 pci_end = pci_resource_end(pdev, i);
184 for (j = 0; j < PNP_MAX_MEM; j++) {
185 if (!pnp_mem_valid(dev, j) ||
186 pnp_mem_len(dev, j) == 0)
187 continue;
189 pnp_start = pnp_mem_start(dev, j);
190 pnp_end = pnp_mem_end(dev, j);
193 * If the PNP region doesn't overlap the PCI
194 * region at all, there's no problem.
196 if (pnp_end < pci_start || pnp_start > pci_end)
197 continue;
200 * If the PNP region completely encloses (or is
201 * at least as large as) the PCI region, that's
202 * also OK. For example, this happens when the
203 * PNP device describes a bridge with PCI
204 * behind it.
206 if (pnp_start <= pci_start &&
207 pnp_end >= pci_end)
208 continue;
211 * Otherwise, the PNP region overlaps *part* of
212 * the PCI region, and that might prevent a PCI
213 * driver from requesting its resources.
215 dev_warn(&dev->dev, "mem resource "
216 "(0x%llx-0x%llx) overlaps %s BAR %d "
217 "(0x%llx-0x%llx), disabling\n",
218 (unsigned long long) pnp_start,
219 (unsigned long long) pnp_end,
220 pci_name(pdev), i,
221 (unsigned long long) pci_start,
222 (unsigned long long) pci_end);
223 pnp_mem_flags(dev, j) = 0;
225 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
231 * PnP Quirks
232 * Cards or devices that need some tweaking due to incomplete resource info
235 static struct pnp_fixup pnp_fixups[] = {
236 /* Soundblaster awe io port quirk */
237 {"CTL0021", quirk_awe32_resources},
238 {"CTL0022", quirk_awe32_resources},
239 {"CTL0023", quirk_awe32_resources},
240 /* CMI 8330 interrupt and dma fix */
241 {"@X@0001", quirk_cmi8330_resources},
242 /* Soundblaster audio device io port range quirk */
243 {"CTL0001", quirk_sb16audio_resources},
244 {"CTL0031", quirk_sb16audio_resources},
245 {"CTL0041", quirk_sb16audio_resources},
246 {"CTL0042", quirk_sb16audio_resources},
247 {"CTL0043", quirk_sb16audio_resources},
248 {"CTL0044", quirk_sb16audio_resources},
249 {"CTL0045", quirk_sb16audio_resources},
250 <<<<<<< HEAD:drivers/pnp/quirks.c
251 {"PNP0c01", quirk_supermicro_h8dce_system},
252 {"PNP0c02", quirk_supermicro_h8dce_system},
253 =======
254 {"PNP0c01", quirk_system_pci_resources},
255 {"PNP0c02", quirk_system_pci_resources},
256 >>>>>>> 264e3e889d86e552b4191d69bb60f4f3b383135a:drivers/pnp/quirks.c
257 {""}
260 void pnp_fixup_device(struct pnp_dev *dev)
262 int i = 0;
263 void (*quirk)(struct pnp_dev *);
265 while (*pnp_fixups[i].id) {
266 if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
267 quirk = pnp_fixups[i].quirk_function;
269 #ifdef DEBUG
270 dev_dbg(&dev->dev, "calling quirk 0x%p", quirk);
271 print_fn_descriptor_symbol(": %s()\n",
272 (unsigned long) *quirk);
273 #endif
274 (*quirk)(dev);
276 i++;