aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pnp/quirks.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index a1af2f989482..ffdb12a59c40 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -111,6 +111,113 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
111 dev_info(&dev->dev, "SB audio device quirk - increased port range\n"); 111 dev_info(&dev->dev, "SB audio device quirk - increased port range\n");
112} 112}
113 113
114static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
115{
116 struct pnp_option *head = NULL;
117 struct pnp_option *prev = NULL;
118 struct pnp_option *res;
119
120 /*
121 * Build a functional IRQ-less variant of each MPU option.
122 */
123
124 for (res = dev->dependent; res; res = res->next) {
125 struct pnp_option *curr;
126 struct pnp_port *port;
127 struct pnp_port *copy;
128
129 port = res->port;
130 if (!port || !res->irq)
131 continue;
132
133 copy = pnp_alloc(sizeof *copy);
134 if (!copy)
135 break;
136
137 copy->min = port->min;
138 copy->max = port->max;
139 copy->align = port->align;
140 copy->size = port->size;
141 copy->flags = port->flags;
142
143 curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
144 if (!curr) {
145 kfree(copy);
146 break;
147 }
148 curr->port = copy;
149
150 if (prev)
151 prev->next = curr;
152 else
153 head = curr;
154 prev = curr;
155 }
156 if (head)
157 dev_info(&dev->dev, "adding IRQ-less MPU options\n");
158
159 return head;
160}
161
162static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
163{
164 struct pnp_option *res;
165 struct pnp_irq *irq;
166
167 /*
168 * Distribute the independent IRQ over the dependent options
169 */
170
171 res = dev->independent;
172 if (!res)
173 return;
174
175 irq = res->irq;
176 if (!irq || irq->next)
177 return;
178
179 res = dev->dependent;
180 if (!res)
181 return;
182
183 while (1) {
184 struct pnp_irq *copy;
185
186 copy = pnp_alloc(sizeof *copy);
187 if (!copy)
188 break;
189
190 memcpy(copy->map, irq->map, sizeof copy->map);
191 copy->flags = irq->flags;
192
193 copy->next = res->irq; /* Yes, this is NULL */
194 res->irq = copy;
195
196 if (!res->next)
197 break;
198 res = res->next;
199 }
200 kfree(irq);
201
202 res->next = quirk_isapnp_mpu_options(dev);
203
204 res = dev->independent;
205 res->irq = NULL;
206}
207
208static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)
209{
210 struct pnp_option *res;
211
212 res = dev->dependent;
213 if (!res)
214 return;
215
216 while (res->next)
217 res = res->next;
218
219 res->next = quirk_isapnp_mpu_options(dev);
220}
114 221
115#include <linux/pci.h> 222#include <linux/pci.h>
116 223
@@ -205,6 +312,11 @@ static struct pnp_fixup pnp_fixups[] = {
205 {"CTL0043", quirk_sb16audio_resources}, 312 {"CTL0043", quirk_sb16audio_resources},
206 {"CTL0044", quirk_sb16audio_resources}, 313 {"CTL0044", quirk_sb16audio_resources},
207 {"CTL0045", quirk_sb16audio_resources}, 314 {"CTL0045", quirk_sb16audio_resources},
315 /* Add IRQ-less MPU options */
316 {"ADS7151", quirk_ad1815_mpu_resources},
317 {"ADS7181", quirk_isapnp_mpu_resources},
318 {"AZT0002", quirk_isapnp_mpu_resources},
319 /* PnP resources that might overlap PCI BARs */
208 {"PNP0c01", quirk_system_pci_resources}, 320 {"PNP0c01", quirk_system_pci_resources},
209 {"PNP0c02", quirk_system_pci_resources}, 321 {"PNP0c02", quirk_system_pci_resources},
210 {""} 322 {""}