diff options
Diffstat (limited to 'drivers/pnp')
-rw-r--r-- | drivers/pnp/base.h | 1 | ||||
-rw-r--r-- | drivers/pnp/interface.c | 2 | ||||
-rw-r--r-- | drivers/pnp/quirks.c | 131 | ||||
-rw-r--r-- | drivers/pnp/resource.c | 2 | ||||
-rw-r--r-- | drivers/pnp/support.c | 8 |
5 files changed, 126 insertions, 18 deletions
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 4fe7c58f57e9..886dac823ed6 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h | |||
@@ -19,6 +19,7 @@ void pnp_remove_card(struct pnp_card *card); | |||
19 | int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); | 19 | int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev); |
20 | void pnp_remove_card_device(struct pnp_dev *dev); | 20 | void pnp_remove_card_device(struct pnp_dev *dev); |
21 | 21 | ||
22 | struct pnp_option *pnp_build_option(int priority); | ||
22 | struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); | 23 | struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); |
23 | struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, | 24 | struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, |
24 | int priority); | 25 | int priority); |
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 5d9301de1778..5695a79f3a52 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c | |||
@@ -424,7 +424,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, | |||
424 | start = simple_strtoul(buf, &buf, 0); | 424 | start = simple_strtoul(buf, &buf, 0); |
425 | pnp_res = pnp_add_irq_resource(dev, start, 0); | 425 | pnp_res = pnp_add_irq_resource(dev, start, 0); |
426 | if (pnp_res) | 426 | if (pnp_res) |
427 | nirq++; | 427 | pnp_res->index = nirq++; |
428 | continue; | 428 | continue; |
429 | } | 429 | } |
430 | if (!strnicmp(buf, "dma", 3)) { | 430 | if (!strnicmp(buf, "dma", 3)) { |
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index d049a2279fea..e2b7de4cb05e 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 | ||
114 | static 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 | |||
162 | static 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 | |||
208 | static 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 | {""} |
@@ -212,20 +324,15 @@ static struct pnp_fixup pnp_fixups[] = { | |||
212 | 324 | ||
213 | void pnp_fixup_device(struct pnp_dev *dev) | 325 | void pnp_fixup_device(struct pnp_dev *dev) |
214 | { | 326 | { |
215 | int i = 0; | 327 | struct pnp_fixup *f; |
216 | void (*quirk)(struct pnp_dev *); | ||
217 | |||
218 | while (*pnp_fixups[i].id) { | ||
219 | if (compare_pnp_id(dev->id, pnp_fixups[i].id)) { | ||
220 | quirk = pnp_fixups[i].quirk_function; | ||
221 | 328 | ||
329 | for (f = pnp_fixups; *f->id; f++) { | ||
330 | if (!compare_pnp_id(dev->id, f->id)) | ||
331 | continue; | ||
222 | #ifdef DEBUG | 332 | #ifdef DEBUG |
223 | dev_dbg(&dev->dev, "calling "); | 333 | dev_dbg(&dev->dev, "%s: calling ", f->id); |
224 | print_fn_descriptor_symbol("%s()\n", | 334 | print_fn_descriptor_symbol("%s\n", f->quirk_function); |
225 | (unsigned long) *quirk); | ||
226 | #endif | 335 | #endif |
227 | (*quirk)(dev); | 336 | f->quirk_function(dev); |
228 | } | ||
229 | i++; | ||
230 | } | 337 | } |
231 | } | 338 | } |
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index 2041620d5682..390b50096e30 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c | |||
@@ -28,7 +28,7 @@ static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some | |||
28 | * option registration | 28 | * option registration |
29 | */ | 29 | */ |
30 | 30 | ||
31 | static struct pnp_option *pnp_build_option(int priority) | 31 | struct pnp_option *pnp_build_option(int priority) |
32 | { | 32 | { |
33 | struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); | 33 | struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option)); |
34 | 34 | ||
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c index 3eba85ed729c..95b076c18c07 100644 --- a/drivers/pnp/support.c +++ b/drivers/pnp/support.c | |||
@@ -45,10 +45,10 @@ void pnp_eisa_id_to_string(u32 id, char *str) | |||
45 | str[0] = 'A' + ((id >> 26) & 0x3f) - 1; | 45 | str[0] = 'A' + ((id >> 26) & 0x3f) - 1; |
46 | str[1] = 'A' + ((id >> 21) & 0x1f) - 1; | 46 | str[1] = 'A' + ((id >> 21) & 0x1f) - 1; |
47 | str[2] = 'A' + ((id >> 16) & 0x1f) - 1; | 47 | str[2] = 'A' + ((id >> 16) & 0x1f) - 1; |
48 | str[3] = hex_asc((id >> 12) & 0xf); | 48 | str[3] = hex_asc_hi(id >> 8); |
49 | str[4] = hex_asc((id >> 8) & 0xf); | 49 | str[4] = hex_asc_lo(id >> 8); |
50 | str[5] = hex_asc((id >> 4) & 0xf); | 50 | str[5] = hex_asc_hi(id); |
51 | str[6] = hex_asc((id >> 0) & 0xf); | 51 | str[6] = hex_asc_lo(id); |
52 | str[7] = '\0'; | 52 | str[7] = '\0'; |
53 | } | 53 | } |
54 | 54 | ||