Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * pnpacpi -- PnP ACPI driver | |
3 | * | |
4 | * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> | |
5 | * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> | |
40ab4f4c BH |
6 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. |
7 | * Bjorn Helgaas <bjorn.helgaas@hp.com> | |
50eca3eb | 8 | * |
1da177e4 LT |
9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation; either version 2, or (at your option) any | |
12 | * later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | #include <linux/kernel.h> | |
24 | #include <linux/acpi.h> | |
25 | #include <linux/pci.h> | |
02d83b5d BH |
26 | #include <linux/pnp.h> |
27 | #include "../base.h" | |
1da177e4 LT |
28 | #include "pnpacpi.h" |
29 | ||
30 | #ifdef CONFIG_IA64 | |
31 | #define valid_IRQ(i) (1) | |
32 | #else | |
33 | #define valid_IRQ(i) (((i) != 0) && ((i) != 2)) | |
34 | #endif | |
35 | ||
36 | /* | |
37 | * Allocated Resources | |
38 | */ | |
cd7ec927 | 39 | static int irq_flags(int triggering, int polarity, int shareable) |
1da177e4 | 40 | { |
cd7ec927 BH |
41 | int flags; |
42 | ||
50eca3eb | 43 | if (triggering == ACPI_LEVEL_SENSITIVE) { |
1c6e7d0a | 44 | if (polarity == ACPI_ACTIVE_LOW) |
cd7ec927 | 45 | flags = IORESOURCE_IRQ_LOWLEVEL; |
1da177e4 | 46 | else |
cd7ec927 | 47 | flags = IORESOURCE_IRQ_HIGHLEVEL; |
9dd78466 | 48 | } else { |
1c6e7d0a | 49 | if (polarity == ACPI_ACTIVE_LOW) |
cd7ec927 | 50 | flags = IORESOURCE_IRQ_LOWEDGE; |
1da177e4 | 51 | else |
cd7ec927 | 52 | flags = IORESOURCE_IRQ_HIGHEDGE; |
1da177e4 | 53 | } |
cd7ec927 | 54 | |
a993273b | 55 | if (shareable == ACPI_SHARED) |
cd7ec927 BH |
56 | flags |= IORESOURCE_IRQ_SHAREABLE; |
57 | ||
58 | return flags; | |
1da177e4 LT |
59 | } |
60 | ||
e9fe9e18 | 61 | static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, |
a993273b | 62 | int *polarity, int *shareable) |
1da177e4 | 63 | { |
e9fe9e18 BH |
64 | switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | |
65 | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { | |
1da177e4 | 66 | case IORESOURCE_IRQ_LOWLEVEL: |
50eca3eb BM |
67 | *triggering = ACPI_LEVEL_SENSITIVE; |
68 | *polarity = ACPI_ACTIVE_LOW; | |
1da177e4 | 69 | break; |
1c6e7d0a | 70 | case IORESOURCE_IRQ_HIGHLEVEL: |
50eca3eb BM |
71 | *triggering = ACPI_LEVEL_SENSITIVE; |
72 | *polarity = ACPI_ACTIVE_HIGH; | |
1da177e4 LT |
73 | break; |
74 | case IORESOURCE_IRQ_LOWEDGE: | |
50eca3eb BM |
75 | *triggering = ACPI_EDGE_SENSITIVE; |
76 | *polarity = ACPI_ACTIVE_LOW; | |
1da177e4 LT |
77 | break; |
78 | case IORESOURCE_IRQ_HIGHEDGE: | |
50eca3eb BM |
79 | *triggering = ACPI_EDGE_SENSITIVE; |
80 | *polarity = ACPI_ACTIVE_HIGH; | |
1da177e4 | 81 | break; |
e9fe9e18 BH |
82 | default: |
83 | dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n", | |
84 | flags); | |
85 | *triggering = ACPI_EDGE_SENSITIVE; | |
86 | *polarity = ACPI_ACTIVE_HIGH; | |
87 | break; | |
1da177e4 | 88 | } |
a993273b BH |
89 | |
90 | if (flags & IORESOURCE_IRQ_SHAREABLE) | |
91 | *shareable = ACPI_SHARED; | |
92 | else | |
93 | *shareable = ACPI_EXCLUSIVE; | |
1da177e4 LT |
94 | } |
95 | ||
4ab55d8d | 96 | static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, |
07d4e9af BH |
97 | u32 gsi, int triggering, |
98 | int polarity, int shareable) | |
1da177e4 | 99 | { |
dbddd038 | 100 | int irq, flags; |
61fd47e0 | 101 | int p, t; |
dbed12da | 102 | |
5acf9141 BH |
103 | if (!valid_IRQ(gsi)) { |
104 | pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); | |
dbed12da | 105 | return; |
5acf9141 | 106 | } |
dbed12da | 107 | |
61fd47e0 SL |
108 | /* |
109 | * in IO-APIC mode, use overrided attribute. Two reasons: | |
110 | * 1. BIOS bug in DSDT | |
111 | * 2. BIOS uses IO-APIC mode Interrupt Source Override | |
112 | */ | |
113 | if (!acpi_get_override_irq(gsi, &t, &p)) { | |
114 | t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; | |
115 | p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; | |
116 | ||
117 | if (triggering != t || polarity != p) { | |
af11cb2d | 118 | dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", |
61fd47e0 SL |
119 | gsi, t ? "edge":"level", p ? "low":"high"); |
120 | triggering = t; | |
121 | polarity = p; | |
122 | } | |
123 | } | |
124 | ||
dbddd038 | 125 | flags = irq_flags(triggering, polarity, shareable); |
50eca3eb | 126 | irq = acpi_register_gsi(gsi, triggering, polarity); |
dbddd038 BH |
127 | if (irq >= 0) |
128 | pcibios_penalize_isa_irq(irq, 1); | |
129 | else | |
130 | flags |= IORESOURCE_DISABLED; | |
dbed12da | 131 | |
dbddd038 | 132 | pnp_add_irq_resource(dev, irq, flags); |
1da177e4 LT |
133 | } |
134 | ||
958a1fdd BH |
135 | static int dma_flags(struct pnp_dev *dev, int type, int bus_master, |
136 | int transfer) | |
362ea087 MK |
137 | { |
138 | int flags = 0; | |
139 | ||
140 | if (bus_master) | |
141 | flags |= IORESOURCE_DMA_MASTER; | |
142 | switch (type) { | |
143 | case ACPI_COMPATIBILITY: | |
144 | flags |= IORESOURCE_DMA_COMPATIBLE; | |
145 | break; | |
146 | case ACPI_TYPE_A: | |
147 | flags |= IORESOURCE_DMA_TYPEA; | |
148 | break; | |
149 | case ACPI_TYPE_B: | |
150 | flags |= IORESOURCE_DMA_TYPEB; | |
151 | break; | |
152 | case ACPI_TYPE_F: | |
153 | flags |= IORESOURCE_DMA_TYPEF; | |
154 | break; | |
155 | default: | |
156 | /* Set a default value ? */ | |
157 | flags |= IORESOURCE_DMA_COMPATIBLE; | |
958a1fdd | 158 | dev_err(&dev->dev, "invalid DMA type %d\n", type); |
362ea087 MK |
159 | } |
160 | switch (transfer) { | |
161 | case ACPI_TRANSFER_8: | |
162 | flags |= IORESOURCE_DMA_8BIT; | |
163 | break; | |
164 | case ACPI_TRANSFER_8_16: | |
165 | flags |= IORESOURCE_DMA_8AND16BIT; | |
166 | break; | |
167 | case ACPI_TRANSFER_16: | |
168 | flags |= IORESOURCE_DMA_16BIT; | |
169 | break; | |
170 | default: | |
171 | /* Set a default value ? */ | |
172 | flags |= IORESOURCE_DMA_8AND16BIT; | |
958a1fdd | 173 | dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer); |
362ea087 MK |
174 | } |
175 | ||
176 | return flags; | |
177 | } | |
178 | ||
cc8c2e30 BH |
179 | static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, |
180 | u64 len, int io_decode) | |
1da177e4 | 181 | { |
cc8c2e30 BH |
182 | int flags = 0; |
183 | u64 end = start + len - 1; | |
07d4e9af | 184 | |
cc8c2e30 | 185 | if (io_decode == ACPI_DECODE_16) |
08c9f262 | 186 | flags |= IORESOURCE_IO_16BIT_ADDR; |
cc8c2e30 BH |
187 | if (len == 0 || end >= 0x10003) |
188 | flags |= IORESOURCE_DISABLED; | |
189 | ||
190 | pnp_add_io_resource(dev, start, end, flags); | |
1da177e4 LT |
191 | } |
192 | ||
40ab4f4c BH |
193 | /* |
194 | * Device CSRs that do not appear in PCI config space should be described | |
195 | * via ACPI. This would normally be done with Address Space Descriptors | |
196 | * marked as "consumer-only," but old versions of Windows and Linux ignore | |
197 | * the producer/consumer flag, so HP invented a vendor-defined resource to | |
198 | * describe the location and size of CSR space. | |
199 | */ | |
200 | static struct acpi_vendor_uuid hp_ccsr_uuid = { | |
201 | .subtype = 2, | |
202 | .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, | |
203 | 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, | |
204 | }; | |
205 | ||
206 | static int vendor_resource_matches(struct pnp_dev *dev, | |
207 | struct acpi_resource_vendor_typed *vendor, | |
208 | struct acpi_vendor_uuid *match, | |
209 | int expected_len) | |
210 | { | |
211 | int uuid_len = sizeof(vendor->uuid); | |
212 | u8 uuid_subtype = vendor->uuid_subtype; | |
213 | u8 *uuid = vendor->uuid; | |
214 | int actual_len; | |
215 | ||
216 | /* byte_length includes uuid_subtype and uuid */ | |
217 | actual_len = vendor->byte_length - uuid_len - 1; | |
218 | ||
219 | if (uuid_subtype == match->subtype && | |
220 | uuid_len == sizeof(match->data) && | |
221 | memcmp(uuid, match->data, uuid_len) == 0) { | |
222 | if (expected_len && expected_len != actual_len) { | |
223 | dev_err(&dev->dev, "wrong vendor descriptor size; " | |
224 | "expected %d, found %d bytes\n", | |
225 | expected_len, actual_len); | |
226 | return 0; | |
227 | } | |
228 | ||
229 | return 1; | |
230 | } | |
231 | ||
232 | return 0; | |
233 | } | |
234 | ||
235 | static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, | |
236 | struct acpi_resource_vendor_typed *vendor) | |
237 | { | |
238 | if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) { | |
239 | u64 start, length; | |
240 | ||
241 | memcpy(&start, vendor->byte_data, sizeof(start)); | |
242 | memcpy(&length, vendor->byte_data + 8, sizeof(length)); | |
243 | ||
244 | pnp_add_mem_resource(dev, start, start + length - 1, 0); | |
245 | } | |
246 | } | |
247 | ||
4ab55d8d | 248 | static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, |
d6180f36 | 249 | u64 start, u64 len, |
07d4e9af | 250 | int write_protect) |
1da177e4 | 251 | { |
d6180f36 BH |
252 | int flags = 0; |
253 | u64 end = start + len - 1; | |
254 | ||
255 | if (len == 0) | |
256 | flags |= IORESOURCE_DISABLED; | |
257 | if (write_protect == ACPI_READ_WRITE_MEMORY) | |
258 | flags |= IORESOURCE_MEM_WRITEABLE; | |
259 | ||
260 | pnp_add_mem_resource(dev, start, end, flags); | |
1da177e4 LT |
261 | } |
262 | ||
4ab55d8d | 263 | static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, |
07d4e9af | 264 | struct acpi_resource *res) |
1acfb7f2 BH |
265 | { |
266 | struct acpi_resource_address64 addr, *p = &addr; | |
267 | acpi_status status; | |
268 | ||
269 | status = acpi_resource_to_address64(res, p); | |
270 | if (!ACPI_SUCCESS(status)) { | |
af11cb2d | 271 | dev_warn(&dev->dev, "failed to convert resource type %d\n", |
9dd78466 | 272 | res->type); |
1acfb7f2 BH |
273 | return; |
274 | } | |
275 | ||
2b8de5f5 | 276 | if (p->producer_consumer == ACPI_PRODUCER) |
277 | return; | |
278 | ||
1acfb7f2 | 279 | if (p->resource_type == ACPI_MEMORY_RANGE) |
4ab55d8d | 280 | pnpacpi_parse_allocated_memresource(dev, |
07d4e9af BH |
281 | p->minimum, p->address_length, |
282 | p->info.mem.write_protect); | |
1acfb7f2 | 283 | else if (p->resource_type == ACPI_IO_RANGE) |
4ab55d8d | 284 | pnpacpi_parse_allocated_ioresource(dev, |
07d4e9af BH |
285 | p->minimum, p->address_length, |
286 | p->granularity == 0xfff ? ACPI_DECODE_10 : | |
287 | ACPI_DECODE_16); | |
1acfb7f2 | 288 | } |
1da177e4 LT |
289 | |
290 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |
9dd78466 | 291 | void *data) |
1da177e4 | 292 | { |
4ab55d8d | 293 | struct pnp_dev *dev = data; |
9570a20e BH |
294 | struct acpi_resource_irq *irq; |
295 | struct acpi_resource_dma *dma; | |
296 | struct acpi_resource_io *io; | |
297 | struct acpi_resource_fixed_io *fixed_io; | |
40ab4f4c | 298 | struct acpi_resource_vendor_typed *vendor_typed; |
9570a20e BH |
299 | struct acpi_resource_memory24 *memory24; |
300 | struct acpi_resource_memory32 *memory32; | |
301 | struct acpi_resource_fixed_memory32 *fixed_memory32; | |
302 | struct acpi_resource_extended_irq *extended_irq; | |
dc16f5f2 | 303 | int i, flags; |
1da177e4 | 304 | |
eca008c8 | 305 | switch (res->type) { |
50eca3eb | 306 | case ACPI_RESOURCE_TYPE_IRQ: |
dbed12da BH |
307 | /* |
308 | * Per spec, only one interrupt per descriptor is allowed in | |
309 | * _CRS, but some firmware violates this, so parse them all. | |
310 | */ | |
9570a20e | 311 | irq = &res->data.irq; |
5acf9141 BH |
312 | if (irq->interrupt_count == 0) |
313 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | |
314 | else { | |
315 | for (i = 0; i < irq->interrupt_count; i++) { | |
316 | pnpacpi_parse_allocated_irqresource(dev, | |
317 | irq->interrupts[i], | |
318 | irq->triggering, | |
319 | irq->polarity, | |
320 | irq->sharable); | |
321 | } | |
322 | ||
323 | /* | |
324 | * The IRQ encoder puts a single interrupt in each | |
325 | * descriptor, so if a _CRS descriptor has more than | |
326 | * one interrupt, we won't be able to re-encode it. | |
327 | */ | |
328 | if (pnp_can_write(dev) && irq->interrupt_count > 1) { | |
329 | dev_warn(&dev->dev, "multiple interrupts in " | |
330 | "_CRS descriptor; configuration can't " | |
331 | "be changed\n"); | |
332 | dev->capabilities &= ~PNP_WRITE; | |
333 | } | |
1da177e4 LT |
334 | } |
335 | break; | |
336 | ||
50eca3eb | 337 | case ACPI_RESOURCE_TYPE_DMA: |
9570a20e | 338 | dma = &res->data.dma; |
5acf9141 | 339 | if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) |
958a1fdd | 340 | flags = dma_flags(dev, dma->type, dma->bus_master, |
dc16f5f2 | 341 | dma->transfer); |
5acf9141 BH |
342 | else |
343 | flags = IORESOURCE_DISABLED; | |
344 | pnp_add_dma_resource(dev, dma->channels[0], flags); | |
1da177e4 | 345 | break; |
0af5853b | 346 | |
50eca3eb | 347 | case ACPI_RESOURCE_TYPE_IO: |
9570a20e | 348 | io = &res->data.io; |
4ab55d8d | 349 | pnpacpi_parse_allocated_ioresource(dev, |
9570a20e BH |
350 | io->minimum, |
351 | io->address_length, | |
352 | io->io_decode); | |
1da177e4 | 353 | break; |
0af5853b LB |
354 | |
355 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | |
356 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | |
357 | break; | |
358 | ||
50eca3eb | 359 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
9570a20e | 360 | fixed_io = &res->data.fixed_io; |
4ab55d8d | 361 | pnpacpi_parse_allocated_ioresource(dev, |
9570a20e BH |
362 | fixed_io->address, |
363 | fixed_io->address_length, | |
07d4e9af | 364 | ACPI_DECODE_10); |
1da177e4 | 365 | break; |
0af5853b LB |
366 | |
367 | case ACPI_RESOURCE_TYPE_VENDOR: | |
40ab4f4c BH |
368 | vendor_typed = &res->data.vendor_typed; |
369 | pnpacpi_parse_allocated_vendor(dev, vendor_typed); | |
0af5853b LB |
370 | break; |
371 | ||
372 | case ACPI_RESOURCE_TYPE_END_TAG: | |
373 | break; | |
374 | ||
50eca3eb | 375 | case ACPI_RESOURCE_TYPE_MEMORY24: |
9570a20e | 376 | memory24 = &res->data.memory24; |
4ab55d8d | 377 | pnpacpi_parse_allocated_memresource(dev, |
9570a20e BH |
378 | memory24->minimum, |
379 | memory24->address_length, | |
380 | memory24->write_protect); | |
1da177e4 | 381 | break; |
50eca3eb | 382 | case ACPI_RESOURCE_TYPE_MEMORY32: |
9570a20e | 383 | memory32 = &res->data.memory32; |
4ab55d8d | 384 | pnpacpi_parse_allocated_memresource(dev, |
9570a20e BH |
385 | memory32->minimum, |
386 | memory32->address_length, | |
387 | memory32->write_protect); | |
1da177e4 | 388 | break; |
50eca3eb | 389 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
9570a20e | 390 | fixed_memory32 = &res->data.fixed_memory32; |
4ab55d8d | 391 | pnpacpi_parse_allocated_memresource(dev, |
9570a20e BH |
392 | fixed_memory32->address, |
393 | fixed_memory32->address_length, | |
394 | fixed_memory32->write_protect); | |
1da177e4 | 395 | break; |
50eca3eb | 396 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
50eca3eb | 397 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
50eca3eb | 398 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
4ab55d8d | 399 | pnpacpi_parse_allocated_address_space(dev, res); |
1da177e4 | 400 | break; |
0af5853b LB |
401 | |
402 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | |
2b8de5f5 | 403 | if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER) |
404 | return AE_OK; | |
0af5853b LB |
405 | break; |
406 | ||
407 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | |
9570a20e | 408 | extended_irq = &res->data.extended_irq; |
2b8de5f5 | 409 | |
5acf9141 BH |
410 | if (extended_irq->interrupt_count == 0) |
411 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | |
412 | else { | |
413 | for (i = 0; i < extended_irq->interrupt_count; i++) { | |
414 | pnpacpi_parse_allocated_irqresource(dev, | |
415 | extended_irq->interrupts[i], | |
416 | extended_irq->triggering, | |
417 | extended_irq->polarity, | |
418 | extended_irq->sharable); | |
419 | } | |
420 | ||
421 | /* | |
422 | * The IRQ encoder puts a single interrupt in each | |
423 | * descriptor, so if a _CRS descriptor has more than | |
424 | * one interrupt, we won't be able to re-encode it. | |
425 | */ | |
426 | if (pnp_can_write(dev) && | |
427 | extended_irq->interrupt_count > 1) { | |
428 | dev_warn(&dev->dev, "multiple interrupts in " | |
429 | "_CRS descriptor; configuration can't " | |
430 | "be changed\n"); | |
431 | dev->capabilities &= ~PNP_WRITE; | |
432 | } | |
0af5853b LB |
433 | } |
434 | break; | |
435 | ||
436 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | |
1da177e4 | 437 | break; |
0af5853b | 438 | |
1da177e4 | 439 | default: |
af11cb2d BH |
440 | dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", |
441 | res->type); | |
1da177e4 LT |
442 | return AE_ERROR; |
443 | } | |
1c6e7d0a | 444 | |
1da177e4 LT |
445 | return AE_OK; |
446 | } | |
447 | ||
d152cf5d | 448 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) |
1da177e4 | 449 | { |
4ab55d8d | 450 | acpi_handle handle = dev->data; |
d152cf5d | 451 | acpi_status status; |
4ab55d8d | 452 | |
2f53432c | 453 | pnp_dbg(&dev->dev, "parse allocated resources\n"); |
72dcc883 | 454 | |
f4490002 | 455 | pnp_init_resources(dev); |
1da177e4 | 456 | |
d152cf5d BH |
457 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
458 | pnpacpi_allocated_resource, dev); | |
459 | ||
460 | if (ACPI_FAILURE(status)) { | |
461 | if (status != AE_NOT_FOUND) | |
462 | dev_err(&dev->dev, "can't evaluate _CRS: %d", status); | |
463 | return -EPERM; | |
464 | } | |
465 | return 0; | |
1da177e4 LT |
466 | } |
467 | ||
c1caf06c | 468 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, |
1f32ca31 | 469 | unsigned int option_flags, |
2bb9a6b3 | 470 | struct acpi_resource_dma *p) |
1da177e4 LT |
471 | { |
472 | int i; | |
c227536b | 473 | unsigned char map = 0, flags; |
1da177e4 | 474 | |
50eca3eb | 475 | if (p->channel_count == 0) |
1da177e4 | 476 | return; |
1da177e4 | 477 | |
9dd78466 | 478 | for (i = 0; i < p->channel_count; i++) |
c227536b | 479 | map |= 1 << p->channels[i]; |
1da177e4 | 480 | |
958a1fdd | 481 | flags = dma_flags(dev, p->type, p->bus_master, p->transfer); |
1f32ca31 | 482 | pnp_register_dma_resource(dev, option_flags, map, flags); |
1da177e4 LT |
483 | } |
484 | ||
c1caf06c | 485 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, |
1f32ca31 | 486 | unsigned int option_flags, |
2bb9a6b3 | 487 | struct acpi_resource_irq *p) |
1da177e4 LT |
488 | { |
489 | int i; | |
c227536b BH |
490 | pnp_irq_mask_t map; |
491 | unsigned char flags; | |
1c6e7d0a | 492 | |
50eca3eb | 493 | if (p->interrupt_count == 0) |
1da177e4 | 494 | return; |
1da177e4 | 495 | |
c227536b | 496 | bitmap_zero(map.bits, PNP_IRQ_NR); |
9dd78466 | 497 | for (i = 0; i < p->interrupt_count; i++) |
1da177e4 | 498 | if (p->interrupts[i]) |
c227536b | 499 | __set_bit(p->interrupts[i], map.bits); |
1da177e4 | 500 | |
c227536b | 501 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
1f32ca31 | 502 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
1da177e4 LT |
503 | } |
504 | ||
c1caf06c | 505 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, |
1f32ca31 | 506 | unsigned int option_flags, |
2bb9a6b3 | 507 | struct acpi_resource_extended_irq *p) |
1da177e4 LT |
508 | { |
509 | int i; | |
c227536b BH |
510 | pnp_irq_mask_t map; |
511 | unsigned char flags; | |
1da177e4 | 512 | |
50eca3eb | 513 | if (p->interrupt_count == 0) |
1da177e4 | 514 | return; |
1da177e4 | 515 | |
c227536b | 516 | bitmap_zero(map.bits, PNP_IRQ_NR); |
fe2cf598 BH |
517 | for (i = 0; i < p->interrupt_count; i++) { |
518 | if (p->interrupts[i]) { | |
519 | if (p->interrupts[i] < PNP_IRQ_NR) | |
520 | __set_bit(p->interrupts[i], map.bits); | |
521 | else | |
522 | dev_err(&dev->dev, "ignoring IRQ %d option " | |
523 | "(too large for %d entry bitmap)\n", | |
524 | p->interrupts[i], PNP_IRQ_NR); | |
525 | } | |
526 | } | |
1da177e4 | 527 | |
c227536b | 528 | flags = irq_flags(p->triggering, p->polarity, p->sharable); |
1f32ca31 | 529 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
1da177e4 LT |
530 | } |
531 | ||
c1caf06c | 532 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, |
1f32ca31 | 533 | unsigned int option_flags, |
2bb9a6b3 | 534 | struct acpi_resource_io *io) |
1da177e4 | 535 | { |
c227536b | 536 | unsigned char flags = 0; |
1da177e4 | 537 | |
50eca3eb | 538 | if (io->address_length == 0) |
1da177e4 | 539 | return; |
c227536b BH |
540 | |
541 | if (io->io_decode == ACPI_DECODE_16) | |
542 | flags = IORESOURCE_IO_16BIT_ADDR; | |
1f32ca31 | 543 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, |
c227536b | 544 | io->alignment, io->address_length, flags); |
1da177e4 LT |
545 | } |
546 | ||
c1caf06c | 547 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, |
1f32ca31 | 548 | unsigned int option_flags, |
2bb9a6b3 | 549 | struct acpi_resource_fixed_io *io) |
1da177e4 | 550 | { |
50eca3eb | 551 | if (io->address_length == 0) |
1da177e4 | 552 | return; |
c227536b | 553 | |
1f32ca31 BH |
554 | pnp_register_port_resource(dev, option_flags, io->address, io->address, |
555 | 0, io->address_length, IORESOURCE_IO_FIXED); | |
1da177e4 LT |
556 | } |
557 | ||
c1caf06c | 558 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, |
1f32ca31 | 559 | unsigned int option_flags, |
2bb9a6b3 | 560 | struct acpi_resource_memory24 *p) |
1da177e4 | 561 | { |
c227536b | 562 | unsigned char flags = 0; |
1da177e4 | 563 | |
50eca3eb | 564 | if (p->address_length == 0) |
1da177e4 | 565 | return; |
1da177e4 | 566 | |
c227536b BH |
567 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
568 | flags = IORESOURCE_MEM_WRITEABLE; | |
1f32ca31 | 569 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
c227536b | 570 | p->alignment, p->address_length, flags); |
1da177e4 LT |
571 | } |
572 | ||
c1caf06c | 573 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, |
1f32ca31 | 574 | unsigned int option_flags, |
2bb9a6b3 | 575 | struct acpi_resource_memory32 *p) |
1da177e4 | 576 | { |
c227536b | 577 | unsigned char flags = 0; |
1da177e4 | 578 | |
50eca3eb | 579 | if (p->address_length == 0) |
1da177e4 | 580 | return; |
1da177e4 | 581 | |
c227536b BH |
582 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
583 | flags = IORESOURCE_MEM_WRITEABLE; | |
1f32ca31 | 584 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
c227536b | 585 | p->alignment, p->address_length, flags); |
1da177e4 LT |
586 | } |
587 | ||
c1caf06c | 588 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, |
1f32ca31 | 589 | unsigned int option_flags, |
2bb9a6b3 | 590 | struct acpi_resource_fixed_memory32 *p) |
1da177e4 | 591 | { |
c227536b | 592 | unsigned char flags = 0; |
1da177e4 | 593 | |
50eca3eb | 594 | if (p->address_length == 0) |
1da177e4 | 595 | return; |
1da177e4 | 596 | |
c227536b BH |
597 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
598 | flags = IORESOURCE_MEM_WRITEABLE; | |
1f32ca31 | 599 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, |
c227536b | 600 | 0, p->address_length, flags); |
1da177e4 LT |
601 | } |
602 | ||
c1caf06c | 603 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, |
1f32ca31 | 604 | unsigned int option_flags, |
2bb9a6b3 | 605 | struct acpi_resource *r) |
6f957eaf BH |
606 | { |
607 | struct acpi_resource_address64 addr, *p = &addr; | |
608 | acpi_status status; | |
c227536b | 609 | unsigned char flags = 0; |
6f957eaf BH |
610 | |
611 | status = acpi_resource_to_address64(r, p); | |
958a1fdd BH |
612 | if (ACPI_FAILURE(status)) { |
613 | dev_warn(&dev->dev, "can't convert resource type %d\n", | |
9dd78466 | 614 | r->type); |
6f957eaf BH |
615 | return; |
616 | } | |
617 | ||
618 | if (p->address_length == 0) | |
619 | return; | |
620 | ||
621 | if (p->resource_type == ACPI_MEMORY_RANGE) { | |
c227536b BH |
622 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
623 | flags = IORESOURCE_MEM_WRITEABLE; | |
1f32ca31 BH |
624 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
625 | p->minimum, 0, p->address_length, | |
626 | flags); | |
c227536b | 627 | } else if (p->resource_type == ACPI_IO_RANGE) |
1f32ca31 BH |
628 | pnp_register_port_resource(dev, option_flags, p->minimum, |
629 | p->minimum, 0, p->address_length, | |
c227536b | 630 | IORESOURCE_IO_FIXED); |
6f957eaf BH |
631 | } |
632 | ||
1da177e4 | 633 | struct acpipnp_parse_option_s { |
1da177e4 | 634 | struct pnp_dev *dev; |
1f32ca31 | 635 | unsigned int option_flags; |
1da177e4 LT |
636 | }; |
637 | ||
2bb9a6b3 TR |
638 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, |
639 | void *data) | |
1da177e4 | 640 | { |
e2a1a6f1 | 641 | int priority; |
4721a4cc | 642 | struct acpipnp_parse_option_s *parse_data = data; |
1da177e4 | 643 | struct pnp_dev *dev = parse_data->dev; |
1f32ca31 | 644 | unsigned int option_flags = parse_data->option_flags; |
1da177e4 | 645 | |
eca008c8 | 646 | switch (res->type) { |
9dd78466 | 647 | case ACPI_RESOURCE_TYPE_IRQ: |
1f32ca31 | 648 | pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); |
9dd78466 | 649 | break; |
0af5853b | 650 | |
9dd78466 | 651 | case ACPI_RESOURCE_TYPE_DMA: |
1f32ca31 | 652 | pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); |
9dd78466 | 653 | break; |
0af5853b | 654 | |
9dd78466 BH |
655 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
656 | switch (res->data.start_dpf.compatibility_priority) { | |
657 | case ACPI_GOOD_CONFIGURATION: | |
658 | priority = PNP_RES_PRIORITY_PREFERRED; | |
1da177e4 | 659 | break; |
0af5853b | 660 | |
9dd78466 BH |
661 | case ACPI_ACCEPTABLE_CONFIGURATION: |
662 | priority = PNP_RES_PRIORITY_ACCEPTABLE; | |
b008b8d7 | 663 | break; |
0af5853b | 664 | |
9dd78466 BH |
665 | case ACPI_SUB_OPTIMAL_CONFIGURATION: |
666 | priority = PNP_RES_PRIORITY_FUNCTIONAL; | |
0af5853b | 667 | break; |
9dd78466 BH |
668 | default: |
669 | priority = PNP_RES_PRIORITY_INVALID; | |
0af5853b | 670 | break; |
9dd78466 | 671 | } |
1f32ca31 | 672 | parse_data->option_flags = pnp_new_dependent_set(dev, priority); |
9dd78466 | 673 | break; |
0af5853b | 674 | |
9dd78466 | 675 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
1f32ca31 | 676 | parse_data->option_flags = 0; |
9dd78466 | 677 | break; |
0af5853b | 678 | |
9dd78466 | 679 | case ACPI_RESOURCE_TYPE_IO: |
1f32ca31 | 680 | pnpacpi_parse_port_option(dev, option_flags, &res->data.io); |
9dd78466 | 681 | break; |
0af5853b | 682 | |
9dd78466 | 683 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
1f32ca31 | 684 | pnpacpi_parse_fixed_port_option(dev, option_flags, |
c1caf06c | 685 | &res->data.fixed_io); |
9dd78466 | 686 | break; |
0af5853b | 687 | |
9dd78466 BH |
688 | case ACPI_RESOURCE_TYPE_VENDOR: |
689 | case ACPI_RESOURCE_TYPE_END_TAG: | |
690 | break; | |
0af5853b | 691 | |
9dd78466 | 692 | case ACPI_RESOURCE_TYPE_MEMORY24: |
1f32ca31 BH |
693 | pnpacpi_parse_mem24_option(dev, option_flags, |
694 | &res->data.memory24); | |
9dd78466 | 695 | break; |
0af5853b | 696 | |
9dd78466 | 697 | case ACPI_RESOURCE_TYPE_MEMORY32: |
1f32ca31 BH |
698 | pnpacpi_parse_mem32_option(dev, option_flags, |
699 | &res->data.memory32); | |
9dd78466 | 700 | break; |
0af5853b | 701 | |
9dd78466 | 702 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
1f32ca31 | 703 | pnpacpi_parse_fixed_mem32_option(dev, option_flags, |
9dd78466 BH |
704 | &res->data.fixed_memory32); |
705 | break; | |
0af5853b | 706 | |
9dd78466 BH |
707 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
708 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
709 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
1f32ca31 | 710 | pnpacpi_parse_address_option(dev, option_flags, res); |
9dd78466 | 711 | break; |
0af5853b | 712 | |
9dd78466 BH |
713 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
714 | break; | |
715 | ||
716 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | |
1f32ca31 | 717 | pnpacpi_parse_ext_irq_option(dev, option_flags, |
c1caf06c | 718 | &res->data.extended_irq); |
9dd78466 BH |
719 | break; |
720 | ||
721 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | |
722 | break; | |
723 | ||
724 | default: | |
af11cb2d BH |
725 | dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", |
726 | res->type); | |
9dd78466 | 727 | return AE_ERROR; |
1da177e4 | 728 | } |
1c6e7d0a | 729 | |
1da177e4 LT |
730 | return AE_OK; |
731 | } | |
732 | ||
d152cf5d | 733 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) |
1da177e4 | 734 | { |
4ab55d8d | 735 | acpi_handle handle = dev->data; |
1da177e4 LT |
736 | acpi_status status; |
737 | struct acpipnp_parse_option_s parse_data; | |
738 | ||
2f53432c | 739 | pnp_dbg(&dev->dev, "parse resource options\n"); |
72dcc883 | 740 | |
1da177e4 | 741 | parse_data.dev = dev; |
1f32ca31 BH |
742 | parse_data.option_flags = 0; |
743 | ||
50eca3eb | 744 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, |
9dd78466 | 745 | pnpacpi_option_resource, &parse_data); |
1da177e4 | 746 | |
d152cf5d BH |
747 | if (ACPI_FAILURE(status)) { |
748 | if (status != AE_NOT_FOUND) | |
749 | dev_err(&dev->dev, "can't evaluate _PRS: %d", status); | |
750 | return -EPERM; | |
751 | } | |
752 | return 0; | |
1da177e4 LT |
753 | } |
754 | ||
b5f2490b | 755 | static int pnpacpi_supported_resource(struct acpi_resource *res) |
1da177e4 | 756 | { |
eca008c8 | 757 | switch (res->type) { |
50eca3eb | 758 | case ACPI_RESOURCE_TYPE_IRQ: |
50eca3eb BM |
759 | case ACPI_RESOURCE_TYPE_DMA: |
760 | case ACPI_RESOURCE_TYPE_IO: | |
761 | case ACPI_RESOURCE_TYPE_FIXED_IO: | |
762 | case ACPI_RESOURCE_TYPE_MEMORY24: | |
763 | case ACPI_RESOURCE_TYPE_MEMORY32: | |
764 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | |
50eca3eb BM |
765 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
766 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
767 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
0af5853b | 768 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
b5f2490b | 769 | return 1; |
1da177e4 | 770 | } |
b5f2490b BH |
771 | return 0; |
772 | } | |
773 | ||
774 | /* | |
775 | * Set resource | |
776 | */ | |
777 | static acpi_status pnpacpi_count_resources(struct acpi_resource *res, | |
9dd78466 | 778 | void *data) |
b5f2490b | 779 | { |
4721a4cc | 780 | int *res_cnt = data; |
b5f2490b BH |
781 | |
782 | if (pnpacpi_supported_resource(res)) | |
783 | (*res_cnt)++; | |
1da177e4 LT |
784 | return AE_OK; |
785 | } | |
786 | ||
1c6e7d0a | 787 | static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) |
1da177e4 | 788 | { |
4721a4cc | 789 | struct acpi_resource **resource = data; |
b5f2490b BH |
790 | |
791 | if (pnpacpi_supported_resource(res)) { | |
eca008c8 | 792 | (*resource)->type = res->type; |
b5f2490b | 793 | (*resource)->length = sizeof(struct acpi_resource); |
36d872a3 BH |
794 | if (res->type == ACPI_RESOURCE_TYPE_IRQ) |
795 | (*resource)->data.irq.descriptor_length = | |
796 | res->data.irq.descriptor_length; | |
1da177e4 | 797 | (*resource)++; |
1da177e4 LT |
798 | } |
799 | ||
800 | return AE_OK; | |
801 | } | |
802 | ||
cdef6254 | 803 | int pnpacpi_build_resource_template(struct pnp_dev *dev, |
9dd78466 | 804 | struct acpi_buffer *buffer) |
1da177e4 | 805 | { |
cdef6254 | 806 | acpi_handle handle = dev->data; |
1da177e4 LT |
807 | struct acpi_resource *resource; |
808 | int res_cnt = 0; | |
809 | acpi_status status; | |
810 | ||
50eca3eb | 811 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
9dd78466 | 812 | pnpacpi_count_resources, &res_cnt); |
1da177e4 | 813 | if (ACPI_FAILURE(status)) { |
d152cf5d | 814 | dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); |
1da177e4 LT |
815 | return -EINVAL; |
816 | } | |
817 | if (!res_cnt) | |
818 | return -EINVAL; | |
819 | buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1; | |
cd861280 | 820 | buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); |
1da177e4 LT |
821 | if (!buffer->pointer) |
822 | return -ENOMEM; | |
72dcc883 | 823 | |
1da177e4 | 824 | resource = (struct acpi_resource *)buffer->pointer; |
50eca3eb | 825 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
9dd78466 | 826 | pnpacpi_type_resources, &resource); |
1da177e4 LT |
827 | if (ACPI_FAILURE(status)) { |
828 | kfree(buffer->pointer); | |
d152cf5d | 829 | dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); |
1da177e4 LT |
830 | return -EINVAL; |
831 | } | |
832 | /* resource will pointer the end resource now */ | |
50eca3eb | 833 | resource->type = ACPI_RESOURCE_TYPE_END_TAG; |
1da177e4 LT |
834 | |
835 | return 0; | |
836 | } | |
837 | ||
72dcc883 BH |
838 | static void pnpacpi_encode_irq(struct pnp_dev *dev, |
839 | struct acpi_resource *resource, | |
9dd78466 | 840 | struct resource *p) |
1da177e4 | 841 | { |
9570a20e | 842 | struct acpi_resource_irq *irq = &resource->data.irq; |
a993273b | 843 | int triggering, polarity, shareable; |
1c6e7d0a | 844 | |
aee3ad81 BH |
845 | if (!pnp_resource_enabled(p)) { |
846 | irq->interrupt_count = 0; | |
2f53432c | 847 | pnp_dbg(&dev->dev, " encode irq (%s)\n", |
aee3ad81 BH |
848 | p ? "disabled" : "missing"); |
849 | return; | |
850 | } | |
851 | ||
a993273b | 852 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
9570a20e BH |
853 | irq->triggering = triggering; |
854 | irq->polarity = polarity; | |
a993273b | 855 | irq->sharable = shareable; |
9570a20e BH |
856 | irq->interrupt_count = 1; |
857 | irq->interrupts[0] = p->start; | |
72dcc883 | 858 | |
2f53432c | 859 | pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", |
36d872a3 | 860 | (int) p->start, |
72dcc883 BH |
861 | triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", |
862 | polarity == ACPI_ACTIVE_LOW ? "low" : "high", | |
36d872a3 BH |
863 | irq->sharable == ACPI_SHARED ? "shared" : "exclusive", |
864 | irq->descriptor_length); | |
1da177e4 LT |
865 | } |
866 | ||
72dcc883 BH |
867 | static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, |
868 | struct acpi_resource *resource, | |
9dd78466 | 869 | struct resource *p) |
1da177e4 | 870 | { |
9570a20e | 871 | struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; |
a993273b | 872 | int triggering, polarity, shareable; |
1c6e7d0a | 873 | |
aee3ad81 BH |
874 | if (!pnp_resource_enabled(p)) { |
875 | extended_irq->interrupt_count = 0; | |
2f53432c | 876 | pnp_dbg(&dev->dev, " encode extended irq (%s)\n", |
aee3ad81 BH |
877 | p ? "disabled" : "missing"); |
878 | return; | |
879 | } | |
880 | ||
a993273b | 881 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
9570a20e BH |
882 | extended_irq->producer_consumer = ACPI_CONSUMER; |
883 | extended_irq->triggering = triggering; | |
884 | extended_irq->polarity = polarity; | |
a993273b | 885 | extended_irq->sharable = shareable; |
9570a20e BH |
886 | extended_irq->interrupt_count = 1; |
887 | extended_irq->interrupts[0] = p->start; | |
72dcc883 | 888 | |
2f53432c | 889 | pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, |
72dcc883 BH |
890 | triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", |
891 | polarity == ACPI_ACTIVE_LOW ? "low" : "high", | |
892 | extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); | |
1da177e4 LT |
893 | } |
894 | ||
72dcc883 BH |
895 | static void pnpacpi_encode_dma(struct pnp_dev *dev, |
896 | struct acpi_resource *resource, | |
9dd78466 | 897 | struct resource *p) |
1da177e4 | 898 | { |
9570a20e BH |
899 | struct acpi_resource_dma *dma = &resource->data.dma; |
900 | ||
aee3ad81 BH |
901 | if (!pnp_resource_enabled(p)) { |
902 | dma->channel_count = 0; | |
2f53432c | 903 | pnp_dbg(&dev->dev, " encode dma (%s)\n", |
aee3ad81 BH |
904 | p ? "disabled" : "missing"); |
905 | return; | |
906 | } | |
907 | ||
1da177e4 | 908 | /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ |
ccc4c7bb | 909 | switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { |
9dd78466 | 910 | case IORESOURCE_DMA_TYPEA: |
9570a20e | 911 | dma->type = ACPI_TYPE_A; |
9dd78466 BH |
912 | break; |
913 | case IORESOURCE_DMA_TYPEB: | |
9570a20e | 914 | dma->type = ACPI_TYPE_B; |
9dd78466 BH |
915 | break; |
916 | case IORESOURCE_DMA_TYPEF: | |
9570a20e | 917 | dma->type = ACPI_TYPE_F; |
9dd78466 BH |
918 | break; |
919 | default: | |
9570a20e | 920 | dma->type = ACPI_COMPATIBILITY; |
ccc4c7bb VP |
921 | } |
922 | ||
923 | switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { | |
9dd78466 | 924 | case IORESOURCE_DMA_8BIT: |
9570a20e | 925 | dma->transfer = ACPI_TRANSFER_8; |
9dd78466 BH |
926 | break; |
927 | case IORESOURCE_DMA_8AND16BIT: | |
9570a20e | 928 | dma->transfer = ACPI_TRANSFER_8_16; |
9dd78466 BH |
929 | break; |
930 | default: | |
9570a20e | 931 | dma->transfer = ACPI_TRANSFER_16; |
ccc4c7bb VP |
932 | } |
933 | ||
9570a20e BH |
934 | dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); |
935 | dma->channel_count = 1; | |
936 | dma->channels[0] = p->start; | |
72dcc883 | 937 | |
2f53432c | 938 | pnp_dbg(&dev->dev, " encode dma %d " |
72dcc883 BH |
939 | "type %#x transfer %#x master %d\n", |
940 | (int) p->start, dma->type, dma->transfer, dma->bus_master); | |
1da177e4 LT |
941 | } |
942 | ||
72dcc883 BH |
943 | static void pnpacpi_encode_io(struct pnp_dev *dev, |
944 | struct acpi_resource *resource, | |
9dd78466 | 945 | struct resource *p) |
1da177e4 | 946 | { |
9570a20e BH |
947 | struct acpi_resource_io *io = &resource->data.io; |
948 | ||
aee3ad81 BH |
949 | if (pnp_resource_enabled(p)) { |
950 | /* Note: pnp_assign_port copies pnp_port->flags into p->flags */ | |
08c9f262 | 951 | io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ? |
aee3ad81 BH |
952 | ACPI_DECODE_16 : ACPI_DECODE_10; |
953 | io->minimum = p->start; | |
954 | io->maximum = p->end; | |
955 | io->alignment = 0; /* Correct? */ | |
956 | io->address_length = p->end - p->start + 1; | |
957 | } else { | |
958 | io->minimum = 0; | |
959 | io->address_length = 0; | |
960 | } | |
72dcc883 | 961 | |
2f53432c | 962 | pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, |
aee3ad81 | 963 | io->minimum + io->address_length - 1, io->io_decode); |
1da177e4 LT |
964 | } |
965 | ||
72dcc883 BH |
966 | static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, |
967 | struct acpi_resource *resource, | |
9dd78466 | 968 | struct resource *p) |
1da177e4 | 969 | { |
9570a20e BH |
970 | struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; |
971 | ||
aee3ad81 BH |
972 | if (pnp_resource_enabled(p)) { |
973 | fixed_io->address = p->start; | |
974 | fixed_io->address_length = p->end - p->start + 1; | |
975 | } else { | |
976 | fixed_io->address = 0; | |
977 | fixed_io->address_length = 0; | |
978 | } | |
72dcc883 | 979 | |
2f53432c | 980 | pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, |
aee3ad81 | 981 | fixed_io->address + fixed_io->address_length - 1); |
1da177e4 LT |
982 | } |
983 | ||
72dcc883 BH |
984 | static void pnpacpi_encode_mem24(struct pnp_dev *dev, |
985 | struct acpi_resource *resource, | |
9dd78466 | 986 | struct resource *p) |
1da177e4 | 987 | { |
9570a20e BH |
988 | struct acpi_resource_memory24 *memory24 = &resource->data.memory24; |
989 | ||
aee3ad81 BH |
990 | if (pnp_resource_enabled(p)) { |
991 | /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */ | |
992 | memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? | |
993 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
994 | memory24->minimum = p->start; | |
995 | memory24->maximum = p->end; | |
996 | memory24->alignment = 0; | |
997 | memory24->address_length = p->end - p->start + 1; | |
998 | } else { | |
999 | memory24->minimum = 0; | |
1000 | memory24->address_length = 0; | |
1001 | } | |
1002 | ||
2f53432c | 1003 | pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
1004 | memory24->minimum, |
1005 | memory24->minimum + memory24->address_length - 1, | |
72dcc883 | 1006 | memory24->write_protect); |
1da177e4 LT |
1007 | } |
1008 | ||
72dcc883 BH |
1009 | static void pnpacpi_encode_mem32(struct pnp_dev *dev, |
1010 | struct acpi_resource *resource, | |
9dd78466 | 1011 | struct resource *p) |
1da177e4 | 1012 | { |
9570a20e BH |
1013 | struct acpi_resource_memory32 *memory32 = &resource->data.memory32; |
1014 | ||
aee3ad81 BH |
1015 | if (pnp_resource_enabled(p)) { |
1016 | memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? | |
1017 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
1018 | memory32->minimum = p->start; | |
1019 | memory32->maximum = p->end; | |
1020 | memory32->alignment = 0; | |
1021 | memory32->address_length = p->end - p->start + 1; | |
1022 | } else { | |
1023 | memory32->minimum = 0; | |
1024 | memory32->alignment = 0; | |
1025 | } | |
72dcc883 | 1026 | |
2f53432c | 1027 | pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
1028 | memory32->minimum, |
1029 | memory32->minimum + memory32->address_length - 1, | |
72dcc883 | 1030 | memory32->write_protect); |
1da177e4 LT |
1031 | } |
1032 | ||
72dcc883 BH |
1033 | static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, |
1034 | struct acpi_resource *resource, | |
9dd78466 | 1035 | struct resource *p) |
1da177e4 | 1036 | { |
9570a20e BH |
1037 | struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; |
1038 | ||
aee3ad81 BH |
1039 | if (pnp_resource_enabled(p)) { |
1040 | fixed_memory32->write_protect = | |
1041 | p->flags & IORESOURCE_MEM_WRITEABLE ? | |
1042 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
1043 | fixed_memory32->address = p->start; | |
1044 | fixed_memory32->address_length = p->end - p->start + 1; | |
1045 | } else { | |
1046 | fixed_memory32->address = 0; | |
1047 | fixed_memory32->address_length = 0; | |
1048 | } | |
72dcc883 | 1049 | |
2f53432c | 1050 | pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
1051 | fixed_memory32->address, |
1052 | fixed_memory32->address + fixed_memory32->address_length - 1, | |
72dcc883 | 1053 | fixed_memory32->write_protect); |
1da177e4 LT |
1054 | } |
1055 | ||
4ab55d8d | 1056 | int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) |
1da177e4 LT |
1057 | { |
1058 | int i = 0; | |
1059 | /* pnpacpi_build_resource_template allocates extra mem */ | |
9dd78466 | 1060 | int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1; |
4721a4cc | 1061 | struct acpi_resource *resource = buffer->pointer; |
1da177e4 LT |
1062 | int port = 0, irq = 0, dma = 0, mem = 0; |
1063 | ||
2f53432c | 1064 | pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt); |
1da177e4 | 1065 | while (i < res_cnt) { |
9dd78466 | 1066 | switch (resource->type) { |
50eca3eb | 1067 | case ACPI_RESOURCE_TYPE_IRQ: |
72dcc883 | 1068 | pnpacpi_encode_irq(dev, resource, |
7e2cf31f | 1069 | pnp_get_resource(dev, IORESOURCE_IRQ, irq)); |
1da177e4 LT |
1070 | irq++; |
1071 | break; | |
1072 | ||
50eca3eb | 1073 | case ACPI_RESOURCE_TYPE_DMA: |
72dcc883 | 1074 | pnpacpi_encode_dma(dev, resource, |
7e2cf31f | 1075 | pnp_get_resource(dev, IORESOURCE_DMA, dma)); |
1c6e7d0a | 1076 | dma++; |
1da177e4 | 1077 | break; |
50eca3eb | 1078 | case ACPI_RESOURCE_TYPE_IO: |
72dcc883 | 1079 | pnpacpi_encode_io(dev, resource, |
7e2cf31f | 1080 | pnp_get_resource(dev, IORESOURCE_IO, port)); |
1c6e7d0a | 1081 | port++; |
1da177e4 | 1082 | break; |
50eca3eb | 1083 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
72dcc883 | 1084 | pnpacpi_encode_fixed_io(dev, resource, |
7e2cf31f | 1085 | pnp_get_resource(dev, IORESOURCE_IO, port)); |
1c6e7d0a | 1086 | port++; |
1da177e4 | 1087 | break; |
50eca3eb | 1088 | case ACPI_RESOURCE_TYPE_MEMORY24: |
72dcc883 | 1089 | pnpacpi_encode_mem24(dev, resource, |
7e2cf31f | 1090 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 1091 | mem++; |
1da177e4 | 1092 | break; |
50eca3eb | 1093 | case ACPI_RESOURCE_TYPE_MEMORY32: |
72dcc883 | 1094 | pnpacpi_encode_mem32(dev, resource, |
7e2cf31f | 1095 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 1096 | mem++; |
1da177e4 | 1097 | break; |
50eca3eb | 1098 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
72dcc883 | 1099 | pnpacpi_encode_fixed_mem32(dev, resource, |
7e2cf31f | 1100 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 1101 | mem++; |
1da177e4 | 1102 | break; |
0af5853b | 1103 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
72dcc883 | 1104 | pnpacpi_encode_ext_irq(dev, resource, |
7e2cf31f | 1105 | pnp_get_resource(dev, IORESOURCE_IRQ, irq)); |
0af5853b LB |
1106 | irq++; |
1107 | break; | |
1108 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | |
1109 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | |
1110 | case ACPI_RESOURCE_TYPE_VENDOR: | |
1111 | case ACPI_RESOURCE_TYPE_END_TAG: | |
1112 | case ACPI_RESOURCE_TYPE_ADDRESS16: | |
1113 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
1114 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
1115 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | |
1116 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | |
9dd78466 | 1117 | default: /* other type */ |
af11cb2d BH |
1118 | dev_warn(&dev->dev, "can't encode unknown resource " |
1119 | "type %d\n", resource->type); | |
1da177e4 LT |
1120 | return -EINVAL; |
1121 | } | |
1c6e7d0a BH |
1122 | resource++; |
1123 | i++; | |
1da177e4 LT |
1124 | } |
1125 | return 0; | |
1126 | } |