]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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. | |
6 | * | |
7 | * Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk> | |
8 | * | |
9 | * Heavily based on PCI quirks handling which is | |
10 | * | |
11 | * Copyright (c) 1999 Martin Mares <mj@ucw.cz> | |
12 | */ | |
13 | ||
1da177e4 LT |
14 | #include <linux/types.h> |
15 | #include <linux/kernel.h> | |
16 | #include <linux/string.h> | |
17 | #include <linux/slab.h> | |
1da177e4 | 18 | #include <linux/pnp.h> |
a1e7e636 | 19 | #include <linux/io.h> |
1da177e4 LT |
20 | #include "base.h" |
21 | ||
1da177e4 LT |
22 | static void quirk_awe32_resources(struct pnp_dev *dev) |
23 | { | |
24 | struct pnp_port *port, *port2, *port3; | |
25 | struct pnp_option *res = dev->dependent; | |
26 | ||
27 | /* | |
28 | * Unfortunately the isapnp_add_port_resource is too tightly bound | |
29 | * into the PnP discovery sequence, and cannot be used. Link in the | |
30 | * two extra ports (at offset 0x400 and 0x800 from the one given) by | |
31 | * hand. | |
32 | */ | |
9dd78466 | 33 | for (; res; res = res->next) { |
1da177e4 LT |
34 | port2 = pnp_alloc(sizeof(struct pnp_port)); |
35 | if (!port2) | |
36 | return; | |
37 | port3 = pnp_alloc(sizeof(struct pnp_port)); | |
38 | if (!port3) { | |
39 | kfree(port2); | |
40 | return; | |
41 | } | |
42 | port = res->port; | |
43 | memcpy(port2, port, sizeof(struct pnp_port)); | |
44 | memcpy(port3, port, sizeof(struct pnp_port)); | |
45 | port->next = port2; | |
46 | port2->next = port3; | |
47 | port2->min += 0x400; | |
48 | port2->max += 0x400; | |
49 | port3->min += 0x800; | |
50 | port3->max += 0x800; | |
51 | } | |
52 | printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n"); | |
53 | } | |
54 | ||
55 | static void quirk_cmi8330_resources(struct pnp_dev *dev) | |
56 | { | |
57 | struct pnp_option *res = dev->dependent; | |
58 | unsigned long tmp; | |
59 | ||
9dd78466 | 60 | for (; res; res = res->next) { |
1da177e4 LT |
61 | |
62 | struct pnp_irq *irq; | |
63 | struct pnp_dma *dma; | |
64 | ||
9dd78466 | 65 | for (irq = res->irq; irq; irq = irq->next) { // Valid irqs are 5, 7, 10 |
1da177e4 LT |
66 | tmp = 0x04A0; |
67 | bitmap_copy(irq->map, &tmp, 16); // 0000 0100 1010 0000 | |
68 | } | |
69 | ||
9dd78466 BH |
70 | for (dma = res->dma; dma; dma = dma->next) // Valid 8bit dma channels are 1,3 |
71 | if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) == | |
72 | IORESOURCE_DMA_8BIT) | |
1da177e4 LT |
73 | dma->map = 0x000A; |
74 | } | |
75 | printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n"); | |
76 | } | |
77 | ||
78 | static void quirk_sb16audio_resources(struct pnp_dev *dev) | |
79 | { | |
80 | struct pnp_port *port; | |
81 | struct pnp_option *res = dev->dependent; | |
9dd78466 | 82 | int changed = 0; |
1da177e4 LT |
83 | |
84 | /* | |
85 | * The default range on the mpu port for these devices is 0x388-0x388. | |
86 | * Here we increase that range so that two such cards can be | |
87 | * auto-configured. | |
88 | */ | |
89 | ||
9dd78466 | 90 | for (; res; res = res->next) { |
1da177e4 | 91 | port = res->port; |
9dd78466 | 92 | if (!port) |
1da177e4 LT |
93 | continue; |
94 | port = port->next; | |
9dd78466 | 95 | if (!port) |
1da177e4 LT |
96 | continue; |
97 | port = port->next; | |
9dd78466 | 98 | if (!port) |
1da177e4 | 99 | continue; |
9dd78466 | 100 | if (port->min != port->max) |
1da177e4 LT |
101 | continue; |
102 | port->max += 0x70; | |
103 | changed = 1; | |
104 | } | |
9dd78466 BH |
105 | if (changed) |
106 | printk(KERN_INFO | |
107 | "pnp: SB audio device quirk - increasing port range\n"); | |
1da177e4 LT |
108 | } |
109 | ||
172d0496 | 110 | static int quirk_smc_fir_enabled(struct pnp_dev *dev) |
a1e7e636 | 111 | { |
172d0496 BH |
112 | unsigned long firbase; |
113 | u8 bank, high, low, chip; | |
114 | ||
115 | if (!pnp_port_valid(dev, 1)) | |
116 | return 0; | |
117 | ||
118 | firbase = pnp_port_start(dev, 1); | |
119 | ||
120 | /* Select register bank 3 */ | |
121 | bank = inb(firbase + 7); | |
122 | bank &= 0xf0; | |
123 | bank |= 3; | |
124 | outb(bank, firbase + 7); | |
125 | ||
126 | high = inb(firbase + 0); | |
9dd78466 | 127 | low = inb(firbase + 1); |
172d0496 BH |
128 | chip = inb(firbase + 2); |
129 | ||
130 | /* This corresponds to the check in smsc_ircc_present() */ | |
131 | if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) | |
132 | return 1; | |
133 | ||
134 | return 0; | |
135 | } | |
a1e7e636 | 136 | |
172d0496 BH |
137 | static void quirk_smc_enable(struct pnp_dev *dev) |
138 | { | |
41a53114 BH |
139 | struct resource fir, sir, irq; |
140 | ||
141 | pnp_activate_dev(dev); | |
142 | if (quirk_smc_fir_enabled(dev)) | |
a1e7e636 BH |
143 | return; |
144 | ||
145 | /* | |
172d0496 BH |
146 | * Sometimes the BIOS claims the device is enabled, but it reports |
147 | * the wrong FIR resources or doesn't properly configure ISA or LPC | |
148 | * bridges on the way to the device. | |
a1e7e636 | 149 | * |
172d0496 BH |
150 | * HP nc6000 and nc8000/nw8000 laptops have known problems like |
151 | * this. Fortunately, they do fix things up if we auto-configure | |
152 | * the device using its _PRS and _SRS methods. | |
a1e7e636 | 153 | */ |
41a53114 BH |
154 | dev_err(&dev->dev, "%s not responding at SIR 0x%lx, FIR 0x%lx; " |
155 | "auto-configuring\n", dev->id->id, | |
9dd78466 BH |
156 | (unsigned long)pnp_port_start(dev, 0), |
157 | (unsigned long)pnp_port_start(dev, 1)); | |
172d0496 BH |
158 | |
159 | pnp_disable_dev(dev); | |
160 | pnp_init_resource_table(&dev->res); | |
161 | pnp_auto_config_dev(dev); | |
162 | pnp_activate_dev(dev); | |
41a53114 BH |
163 | if (quirk_smc_fir_enabled(dev)) { |
164 | dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", | |
9dd78466 BH |
165 | (unsigned long)pnp_port_start(dev, 0), |
166 | (unsigned long)pnp_port_start(dev, 1)); | |
41a53114 BH |
167 | return; |
168 | } | |
169 | ||
170 | /* | |
171 | * The Toshiba Portege 4000 _CRS reports the FIR region first, | |
172 | * followed by the SIR region. The BIOS will configure the bridge, | |
173 | * but only if we call _SRS with SIR first, then FIR. It also | |
174 | * reports the IRQ as active high, when it is really active low. | |
175 | */ | |
176 | dev_err(&dev->dev, "not responding at SIR 0x%lx, FIR 0x%lx; " | |
177 | "swapping SIR/FIR and reconfiguring\n", | |
9dd78466 BH |
178 | (unsigned long)pnp_port_start(dev, 0), |
179 | (unsigned long)pnp_port_start(dev, 1)); | |
41a53114 BH |
180 | |
181 | /* | |
182 | * Clear IORESOURCE_AUTO so pnp_activate_dev() doesn't reassign | |
183 | * these resources any more. | |
184 | */ | |
185 | fir = dev->res.port_resource[0]; | |
186 | sir = dev->res.port_resource[1]; | |
187 | fir.flags &= ~IORESOURCE_AUTO; | |
188 | sir.flags &= ~IORESOURCE_AUTO; | |
189 | ||
190 | irq = dev->res.irq_resource[0]; | |
191 | irq.flags &= ~IORESOURCE_AUTO; | |
192 | irq.flags &= ~IORESOURCE_BITS; | |
193 | irq.flags |= IORESOURCE_IRQ_LOWEDGE; | |
194 | ||
195 | pnp_disable_dev(dev); | |
196 | dev->res.port_resource[0] = sir; | |
197 | dev->res.port_resource[1] = fir; | |
198 | dev->res.irq_resource[0] = irq; | |
199 | pnp_activate_dev(dev); | |
200 | ||
201 | if (quirk_smc_fir_enabled(dev)) { | |
202 | dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n", | |
9dd78466 BH |
203 | (unsigned long)pnp_port_start(dev, 0), |
204 | (unsigned long)pnp_port_start(dev, 1)); | |
41a53114 BH |
205 | return; |
206 | } | |
172d0496 | 207 | |
41a53114 BH |
208 | dev_err(&dev->dev, "giving up; try \"smsc-ircc2.nopnp\" and " |
209 | "email bjorn.helgaas@hp.com\n"); | |
a1e7e636 BH |
210 | } |
211 | ||
1da177e4 LT |
212 | /* |
213 | * PnP Quirks | |
214 | * Cards or devices that need some tweaking due to incomplete resource info | |
215 | */ | |
216 | ||
217 | static struct pnp_fixup pnp_fixups[] = { | |
218 | /* Soundblaster awe io port quirk */ | |
9dd78466 BH |
219 | {"CTL0021", quirk_awe32_resources}, |
220 | {"CTL0022", quirk_awe32_resources}, | |
221 | {"CTL0023", quirk_awe32_resources}, | |
1da177e4 | 222 | /* CMI 8330 interrupt and dma fix */ |
9dd78466 | 223 | {"@X@0001", quirk_cmi8330_resources}, |
1da177e4 | 224 | /* Soundblaster audio device io port range quirk */ |
9dd78466 BH |
225 | {"CTL0001", quirk_sb16audio_resources}, |
226 | {"CTL0031", quirk_sb16audio_resources}, | |
227 | {"CTL0041", quirk_sb16audio_resources}, | |
228 | {"CTL0042", quirk_sb16audio_resources}, | |
229 | {"CTL0043", quirk_sb16audio_resources}, | |
230 | {"CTL0044", quirk_sb16audio_resources}, | |
231 | {"CTL0045", quirk_sb16audio_resources}, | |
232 | {"SMCf010", quirk_smc_enable}, | |
233 | {""} | |
1da177e4 LT |
234 | }; |
235 | ||
236 | void pnp_fixup_device(struct pnp_dev *dev) | |
237 | { | |
238 | int i = 0; | |
239 | ||
240 | while (*pnp_fixups[i].id) { | |
9dd78466 BH |
241 | if (compare_pnp_id(dev->id, pnp_fixups[i].id)) { |
242 | pnp_dbg("Calling quirk for %s", dev->dev.bus_id); | |
1da177e4 LT |
243 | pnp_fixups[i].quirk_function(dev); |
244 | } | |
245 | i++; | |
246 | } | |
247 | } |