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 | 26 | #include <linux/pnp.h> |
5a0e3ad6 | 27 | #include <linux/slab.h> |
02d83b5d | 28 | #include "../base.h" |
1da177e4 LT |
29 | #include "pnpacpi.h" |
30 | ||
e9fe9e18 | 31 | static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, |
a993273b | 32 | int *polarity, int *shareable) |
1da177e4 | 33 | { |
e9fe9e18 BH |
34 | switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | |
35 | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { | |
1da177e4 | 36 | case IORESOURCE_IRQ_LOWLEVEL: |
50eca3eb BM |
37 | *triggering = ACPI_LEVEL_SENSITIVE; |
38 | *polarity = ACPI_ACTIVE_LOW; | |
1da177e4 | 39 | break; |
1c6e7d0a | 40 | case IORESOURCE_IRQ_HIGHLEVEL: |
50eca3eb BM |
41 | *triggering = ACPI_LEVEL_SENSITIVE; |
42 | *polarity = ACPI_ACTIVE_HIGH; | |
1da177e4 LT |
43 | break; |
44 | case IORESOURCE_IRQ_LOWEDGE: | |
50eca3eb BM |
45 | *triggering = ACPI_EDGE_SENSITIVE; |
46 | *polarity = ACPI_ACTIVE_LOW; | |
1da177e4 LT |
47 | break; |
48 | case IORESOURCE_IRQ_HIGHEDGE: | |
50eca3eb BM |
49 | *triggering = ACPI_EDGE_SENSITIVE; |
50 | *polarity = ACPI_ACTIVE_HIGH; | |
1da177e4 | 51 | break; |
e9fe9e18 BH |
52 | default: |
53 | dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n", | |
54 | flags); | |
55 | *triggering = ACPI_EDGE_SENSITIVE; | |
56 | *polarity = ACPI_ACTIVE_HIGH; | |
57 | break; | |
1da177e4 | 58 | } |
a993273b BH |
59 | |
60 | if (flags & IORESOURCE_IRQ_SHAREABLE) | |
61 | *shareable = ACPI_SHARED; | |
62 | else | |
63 | *shareable = ACPI_EXCLUSIVE; | |
1da177e4 LT |
64 | } |
65 | ||
958a1fdd BH |
66 | static int dma_flags(struct pnp_dev *dev, int type, int bus_master, |
67 | int transfer) | |
362ea087 MK |
68 | { |
69 | int flags = 0; | |
70 | ||
71 | if (bus_master) | |
72 | flags |= IORESOURCE_DMA_MASTER; | |
73 | switch (type) { | |
74 | case ACPI_COMPATIBILITY: | |
75 | flags |= IORESOURCE_DMA_COMPATIBLE; | |
76 | break; | |
77 | case ACPI_TYPE_A: | |
78 | flags |= IORESOURCE_DMA_TYPEA; | |
79 | break; | |
80 | case ACPI_TYPE_B: | |
81 | flags |= IORESOURCE_DMA_TYPEB; | |
82 | break; | |
83 | case ACPI_TYPE_F: | |
84 | flags |= IORESOURCE_DMA_TYPEF; | |
85 | break; | |
86 | default: | |
87 | /* Set a default value ? */ | |
88 | flags |= IORESOURCE_DMA_COMPATIBLE; | |
958a1fdd | 89 | dev_err(&dev->dev, "invalid DMA type %d\n", type); |
362ea087 MK |
90 | } |
91 | switch (transfer) { | |
92 | case ACPI_TRANSFER_8: | |
93 | flags |= IORESOURCE_DMA_8BIT; | |
94 | break; | |
95 | case ACPI_TRANSFER_8_16: | |
96 | flags |= IORESOURCE_DMA_8AND16BIT; | |
97 | break; | |
98 | case ACPI_TRANSFER_16: | |
99 | flags |= IORESOURCE_DMA_16BIT; | |
100 | break; | |
101 | default: | |
102 | /* Set a default value ? */ | |
103 | flags |= IORESOURCE_DMA_8AND16BIT; | |
958a1fdd | 104 | dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer); |
362ea087 MK |
105 | } |
106 | ||
107 | return flags; | |
108 | } | |
109 | ||
046d9ce6 RW |
110 | /* |
111 | * Allocated Resources | |
112 | */ | |
07d4e9af | 113 | |
046d9ce6 RW |
114 | static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) |
115 | { | |
116 | if (!(r->flags & IORESOURCE_DISABLED)) | |
117 | pcibios_penalize_isa_irq(r->start, 1); | |
cc8c2e30 | 118 | |
046d9ce6 | 119 | pnp_add_resource(dev, r); |
1da177e4 LT |
120 | } |
121 | ||
40ab4f4c BH |
122 | /* |
123 | * Device CSRs that do not appear in PCI config space should be described | |
124 | * via ACPI. This would normally be done with Address Space Descriptors | |
125 | * marked as "consumer-only," but old versions of Windows and Linux ignore | |
126 | * the producer/consumer flag, so HP invented a vendor-defined resource to | |
127 | * describe the location and size of CSR space. | |
128 | */ | |
129 | static struct acpi_vendor_uuid hp_ccsr_uuid = { | |
130 | .subtype = 2, | |
131 | .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, | |
132 | 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, | |
133 | }; | |
134 | ||
135 | static int vendor_resource_matches(struct pnp_dev *dev, | |
136 | struct acpi_resource_vendor_typed *vendor, | |
137 | struct acpi_vendor_uuid *match, | |
138 | int expected_len) | |
139 | { | |
140 | int uuid_len = sizeof(vendor->uuid); | |
141 | u8 uuid_subtype = vendor->uuid_subtype; | |
142 | u8 *uuid = vendor->uuid; | |
143 | int actual_len; | |
144 | ||
145 | /* byte_length includes uuid_subtype and uuid */ | |
146 | actual_len = vendor->byte_length - uuid_len - 1; | |
147 | ||
148 | if (uuid_subtype == match->subtype && | |
149 | uuid_len == sizeof(match->data) && | |
150 | memcmp(uuid, match->data, uuid_len) == 0) { | |
151 | if (expected_len && expected_len != actual_len) { | |
152 | dev_err(&dev->dev, "wrong vendor descriptor size; " | |
153 | "expected %d, found %d bytes\n", | |
154 | expected_len, actual_len); | |
155 | return 0; | |
156 | } | |
157 | ||
158 | return 1; | |
159 | } | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
164 | static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, | |
165 | struct acpi_resource_vendor_typed *vendor) | |
166 | { | |
167 | if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) { | |
168 | u64 start, length; | |
169 | ||
170 | memcpy(&start, vendor->byte_data, sizeof(start)); | |
171 | memcpy(&length, vendor->byte_data + 8, sizeof(length)); | |
172 | ||
173 | pnp_add_mem_resource(dev, start, start + length - 1, 0); | |
174 | } | |
175 | } | |
176 | ||
1da177e4 | 177 | static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, |
9dd78466 | 178 | void *data) |
1da177e4 | 179 | { |
4ab55d8d | 180 | struct pnp_dev *dev = data; |
9570a20e | 181 | struct acpi_resource_dma *dma; |
40ab4f4c | 182 | struct acpi_resource_vendor_typed *vendor_typed; |
046d9ce6 | 183 | struct resource r; |
dc16f5f2 | 184 | int i, flags; |
1da177e4 | 185 | |
ae59ae91 | 186 | if (acpi_dev_resource_address_space(res, &r) |
046d9ce6 RW |
187 | || acpi_dev_resource_ext_address_space(res, &r)) { |
188 | pnp_add_resource(dev, &r); | |
189 | return AE_OK; | |
190 | } | |
191 | ||
192 | r.flags = 0; | |
193 | if (acpi_dev_resource_interrupt(res, 0, &r)) { | |
194 | pnpacpi_add_irqresource(dev, &r); | |
195 | for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) | |
196 | pnpacpi_add_irqresource(dev, &r); | |
5acf9141 | 197 | |
046d9ce6 | 198 | if (i > 1) { |
5acf9141 BH |
199 | /* |
200 | * The IRQ encoder puts a single interrupt in each | |
201 | * descriptor, so if a _CRS descriptor has more than | |
202 | * one interrupt, we won't be able to re-encode it. | |
203 | */ | |
046d9ce6 | 204 | if (pnp_can_write(dev)) { |
5acf9141 BH |
205 | dev_warn(&dev->dev, "multiple interrupts in " |
206 | "_CRS descriptor; configuration can't " | |
207 | "be changed\n"); | |
208 | dev->capabilities &= ~PNP_WRITE; | |
209 | } | |
1da177e4 | 210 | } |
046d9ce6 RW |
211 | return AE_OK; |
212 | } else if (r.flags & IORESOURCE_DISABLED) { | |
213 | pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); | |
214 | return AE_OK; | |
215 | } | |
1da177e4 | 216 | |
046d9ce6 | 217 | switch (res->type) { |
ae59ae91 ZR |
218 | case ACPI_RESOURCE_TYPE_MEMORY24: |
219 | case ACPI_RESOURCE_TYPE_MEMORY32: | |
220 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | |
221 | if (acpi_dev_resource_memory(res, &r)) | |
222 | pnp_add_resource(dev, &r); | |
223 | break; | |
224 | case ACPI_RESOURCE_TYPE_IO: | |
225 | case ACPI_RESOURCE_TYPE_FIXED_IO: | |
226 | if (acpi_dev_resource_io(res, &r)) | |
227 | pnp_add_resource(dev, &r); | |
228 | break; | |
50eca3eb | 229 | case ACPI_RESOURCE_TYPE_DMA: |
9570a20e | 230 | dma = &res->data.dma; |
5acf9141 | 231 | if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) |
958a1fdd | 232 | flags = dma_flags(dev, dma->type, dma->bus_master, |
dc16f5f2 | 233 | dma->transfer); |
5acf9141 BH |
234 | else |
235 | flags = IORESOURCE_DISABLED; | |
236 | pnp_add_dma_resource(dev, dma->channels[0], flags); | |
1da177e4 | 237 | break; |
0af5853b | 238 | |
0af5853b LB |
239 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
240 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | |
241 | break; | |
242 | ||
0af5853b | 243 | case ACPI_RESOURCE_TYPE_VENDOR: |
40ab4f4c BH |
244 | vendor_typed = &res->data.vendor_typed; |
245 | pnpacpi_parse_allocated_vendor(dev, vendor_typed); | |
0af5853b LB |
246 | break; |
247 | ||
248 | case ACPI_RESOURCE_TYPE_END_TAG: | |
249 | break; | |
250 | ||
0af5853b | 251 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: |
1da177e4 | 252 | break; |
0af5853b | 253 | |
1da177e4 | 254 | default: |
af11cb2d BH |
255 | dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", |
256 | res->type); | |
1da177e4 LT |
257 | return AE_ERROR; |
258 | } | |
1c6e7d0a | 259 | |
1da177e4 LT |
260 | return AE_OK; |
261 | } | |
262 | ||
d152cf5d | 263 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) |
1da177e4 | 264 | { |
c4da6940 BH |
265 | struct acpi_device *acpi_dev = dev->data; |
266 | acpi_handle handle = acpi_dev->handle; | |
d152cf5d | 267 | acpi_status status; |
4ab55d8d | 268 | |
2f53432c | 269 | pnp_dbg(&dev->dev, "parse allocated resources\n"); |
72dcc883 | 270 | |
f4490002 | 271 | pnp_init_resources(dev); |
1da177e4 | 272 | |
d152cf5d BH |
273 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
274 | pnpacpi_allocated_resource, dev); | |
275 | ||
276 | if (ACPI_FAILURE(status)) { | |
277 | if (status != AE_NOT_FOUND) | |
278 | dev_err(&dev->dev, "can't evaluate _CRS: %d", status); | |
279 | return -EPERM; | |
280 | } | |
281 | return 0; | |
1da177e4 LT |
282 | } |
283 | ||
c1caf06c | 284 | static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, |
1f32ca31 | 285 | unsigned int option_flags, |
2bb9a6b3 | 286 | struct acpi_resource_dma *p) |
1da177e4 LT |
287 | { |
288 | int i; | |
18fd470a | 289 | unsigned char map = 0, flags; |
1da177e4 | 290 | |
9dd78466 | 291 | for (i = 0; i < p->channel_count; i++) |
c227536b | 292 | map |= 1 << p->channels[i]; |
1da177e4 | 293 | |
18fd470a | 294 | flags = dma_flags(dev, p->type, p->bus_master, p->transfer); |
1f32ca31 | 295 | pnp_register_dma_resource(dev, option_flags, map, flags); |
1da177e4 LT |
296 | } |
297 | ||
c1caf06c | 298 | static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, |
1f32ca31 | 299 | unsigned int option_flags, |
2bb9a6b3 | 300 | struct acpi_resource_irq *p) |
1da177e4 LT |
301 | { |
302 | int i; | |
c227536b | 303 | pnp_irq_mask_t map; |
18fd470a | 304 | unsigned char flags; |
1da177e4 | 305 | |
c227536b | 306 | bitmap_zero(map.bits, PNP_IRQ_NR); |
9dd78466 | 307 | for (i = 0; i < p->interrupt_count; i++) |
1da177e4 | 308 | if (p->interrupts[i]) |
c227536b | 309 | __set_bit(p->interrupts[i], map.bits); |
1da177e4 | 310 | |
046d9ce6 | 311 | flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); |
1f32ca31 | 312 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
1da177e4 LT |
313 | } |
314 | ||
c1caf06c | 315 | static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, |
1f32ca31 | 316 | unsigned int option_flags, |
2bb9a6b3 | 317 | struct acpi_resource_extended_irq *p) |
1da177e4 LT |
318 | { |
319 | int i; | |
c227536b | 320 | pnp_irq_mask_t map; |
18fd470a | 321 | unsigned char flags; |
1da177e4 | 322 | |
c227536b | 323 | bitmap_zero(map.bits, PNP_IRQ_NR); |
fe2cf598 BH |
324 | for (i = 0; i < p->interrupt_count; i++) { |
325 | if (p->interrupts[i]) { | |
326 | if (p->interrupts[i] < PNP_IRQ_NR) | |
327 | __set_bit(p->interrupts[i], map.bits); | |
328 | else | |
329 | dev_err(&dev->dev, "ignoring IRQ %d option " | |
330 | "(too large for %d entry bitmap)\n", | |
331 | p->interrupts[i], PNP_IRQ_NR); | |
332 | } | |
333 | } | |
1da177e4 | 334 | |
046d9ce6 | 335 | flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); |
1f32ca31 | 336 | pnp_register_irq_resource(dev, option_flags, &map, flags); |
1da177e4 LT |
337 | } |
338 | ||
c1caf06c | 339 | static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, |
1f32ca31 | 340 | unsigned int option_flags, |
2bb9a6b3 | 341 | struct acpi_resource_io *io) |
1da177e4 | 342 | { |
c227536b | 343 | unsigned char flags = 0; |
1da177e4 | 344 | |
c227536b | 345 | if (io->io_decode == ACPI_DECODE_16) |
18fd470a | 346 | flags = IORESOURCE_IO_16BIT_ADDR; |
1f32ca31 | 347 | pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, |
c227536b | 348 | io->alignment, io->address_length, flags); |
1da177e4 LT |
349 | } |
350 | ||
c1caf06c | 351 | static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, |
1f32ca31 | 352 | unsigned int option_flags, |
2bb9a6b3 | 353 | struct acpi_resource_fixed_io *io) |
1da177e4 | 354 | { |
1f32ca31 | 355 | pnp_register_port_resource(dev, option_flags, io->address, io->address, |
18fd470a | 356 | 0, io->address_length, IORESOURCE_IO_FIXED); |
1da177e4 LT |
357 | } |
358 | ||
c1caf06c | 359 | static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, |
1f32ca31 | 360 | unsigned int option_flags, |
2bb9a6b3 | 361 | struct acpi_resource_memory24 *p) |
1da177e4 | 362 | { |
c227536b | 363 | unsigned char flags = 0; |
1da177e4 | 364 | |
c227536b | 365 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
18fd470a | 366 | flags = IORESOURCE_MEM_WRITEABLE; |
1f32ca31 | 367 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
c227536b | 368 | p->alignment, p->address_length, flags); |
1da177e4 LT |
369 | } |
370 | ||
c1caf06c | 371 | static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, |
1f32ca31 | 372 | unsigned int option_flags, |
2bb9a6b3 | 373 | struct acpi_resource_memory32 *p) |
1da177e4 | 374 | { |
c227536b | 375 | unsigned char flags = 0; |
1da177e4 | 376 | |
c227536b | 377 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
18fd470a | 378 | flags = IORESOURCE_MEM_WRITEABLE; |
1f32ca31 | 379 | pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, |
c227536b | 380 | p->alignment, p->address_length, flags); |
1da177e4 LT |
381 | } |
382 | ||
c1caf06c | 383 | static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, |
1f32ca31 | 384 | unsigned int option_flags, |
2bb9a6b3 | 385 | struct acpi_resource_fixed_memory32 *p) |
1da177e4 | 386 | { |
c227536b | 387 | unsigned char flags = 0; |
1da177e4 | 388 | |
c227536b | 389 | if (p->write_protect == ACPI_READ_WRITE_MEMORY) |
18fd470a | 390 | flags = IORESOURCE_MEM_WRITEABLE; |
1f32ca31 | 391 | pnp_register_mem_resource(dev, option_flags, p->address, p->address, |
c227536b | 392 | 0, p->address_length, flags); |
1da177e4 LT |
393 | } |
394 | ||
c1caf06c | 395 | static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, |
1f32ca31 | 396 | unsigned int option_flags, |
2bb9a6b3 | 397 | struct acpi_resource *r) |
6f957eaf BH |
398 | { |
399 | struct acpi_resource_address64 addr, *p = &addr; | |
400 | acpi_status status; | |
c227536b | 401 | unsigned char flags = 0; |
6f957eaf BH |
402 | |
403 | status = acpi_resource_to_address64(r, p); | |
958a1fdd BH |
404 | if (ACPI_FAILURE(status)) { |
405 | dev_warn(&dev->dev, "can't convert resource type %d\n", | |
9dd78466 | 406 | r->type); |
6f957eaf BH |
407 | return; |
408 | } | |
409 | ||
6f957eaf | 410 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
c227536b | 411 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) |
18fd470a | 412 | flags = IORESOURCE_MEM_WRITEABLE; |
1f32ca31 BH |
413 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
414 | p->minimum, 0, p->address_length, | |
415 | flags); | |
c227536b | 416 | } else if (p->resource_type == ACPI_IO_RANGE) |
1f32ca31 BH |
417 | pnp_register_port_resource(dev, option_flags, p->minimum, |
418 | p->minimum, 0, p->address_length, | |
18fd470a | 419 | IORESOURCE_IO_FIXED); |
6f957eaf BH |
420 | } |
421 | ||
8cb24c8f BH |
422 | static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, |
423 | unsigned int option_flags, | |
424 | struct acpi_resource *r) | |
425 | { | |
426 | struct acpi_resource_extended_address64 *p = &r->data.ext_address64; | |
427 | unsigned char flags = 0; | |
428 | ||
8cb24c8f BH |
429 | if (p->resource_type == ACPI_MEMORY_RANGE) { |
430 | if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) | |
18fd470a | 431 | flags = IORESOURCE_MEM_WRITEABLE; |
8cb24c8f BH |
432 | pnp_register_mem_resource(dev, option_flags, p->minimum, |
433 | p->minimum, 0, p->address_length, | |
434 | flags); | |
435 | } else if (p->resource_type == ACPI_IO_RANGE) | |
436 | pnp_register_port_resource(dev, option_flags, p->minimum, | |
437 | p->minimum, 0, p->address_length, | |
18fd470a | 438 | IORESOURCE_IO_FIXED); |
8cb24c8f BH |
439 | } |
440 | ||
1da177e4 | 441 | struct acpipnp_parse_option_s { |
1da177e4 | 442 | struct pnp_dev *dev; |
1f32ca31 | 443 | unsigned int option_flags; |
1da177e4 LT |
444 | }; |
445 | ||
2bb9a6b3 TR |
446 | static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, |
447 | void *data) | |
1da177e4 | 448 | { |
e2a1a6f1 | 449 | int priority; |
4721a4cc | 450 | struct acpipnp_parse_option_s *parse_data = data; |
1da177e4 | 451 | struct pnp_dev *dev = parse_data->dev; |
1f32ca31 | 452 | unsigned int option_flags = parse_data->option_flags; |
1da177e4 | 453 | |
eca008c8 | 454 | switch (res->type) { |
9dd78466 | 455 | case ACPI_RESOURCE_TYPE_IRQ: |
1f32ca31 | 456 | pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); |
9dd78466 | 457 | break; |
0af5853b | 458 | |
9dd78466 | 459 | case ACPI_RESOURCE_TYPE_DMA: |
1f32ca31 | 460 | pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); |
9dd78466 | 461 | break; |
0af5853b | 462 | |
9dd78466 BH |
463 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
464 | switch (res->data.start_dpf.compatibility_priority) { | |
465 | case ACPI_GOOD_CONFIGURATION: | |
466 | priority = PNP_RES_PRIORITY_PREFERRED; | |
1da177e4 | 467 | break; |
0af5853b | 468 | |
9dd78466 BH |
469 | case ACPI_ACCEPTABLE_CONFIGURATION: |
470 | priority = PNP_RES_PRIORITY_ACCEPTABLE; | |
b008b8d7 | 471 | break; |
0af5853b | 472 | |
9dd78466 BH |
473 | case ACPI_SUB_OPTIMAL_CONFIGURATION: |
474 | priority = PNP_RES_PRIORITY_FUNCTIONAL; | |
0af5853b | 475 | break; |
9dd78466 BH |
476 | default: |
477 | priority = PNP_RES_PRIORITY_INVALID; | |
0af5853b | 478 | break; |
9dd78466 | 479 | } |
1f32ca31 | 480 | parse_data->option_flags = pnp_new_dependent_set(dev, priority); |
9dd78466 | 481 | break; |
0af5853b | 482 | |
9dd78466 | 483 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
1f32ca31 | 484 | parse_data->option_flags = 0; |
9dd78466 | 485 | break; |
0af5853b | 486 | |
9dd78466 | 487 | case ACPI_RESOURCE_TYPE_IO: |
1f32ca31 | 488 | pnpacpi_parse_port_option(dev, option_flags, &res->data.io); |
9dd78466 | 489 | break; |
0af5853b | 490 | |
9dd78466 | 491 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
1f32ca31 | 492 | pnpacpi_parse_fixed_port_option(dev, option_flags, |
c1caf06c | 493 | &res->data.fixed_io); |
9dd78466 | 494 | break; |
0af5853b | 495 | |
9dd78466 BH |
496 | case ACPI_RESOURCE_TYPE_VENDOR: |
497 | case ACPI_RESOURCE_TYPE_END_TAG: | |
498 | break; | |
0af5853b | 499 | |
9dd78466 | 500 | case ACPI_RESOURCE_TYPE_MEMORY24: |
1f32ca31 BH |
501 | pnpacpi_parse_mem24_option(dev, option_flags, |
502 | &res->data.memory24); | |
9dd78466 | 503 | break; |
0af5853b | 504 | |
9dd78466 | 505 | case ACPI_RESOURCE_TYPE_MEMORY32: |
1f32ca31 BH |
506 | pnpacpi_parse_mem32_option(dev, option_flags, |
507 | &res->data.memory32); | |
9dd78466 | 508 | break; |
0af5853b | 509 | |
9dd78466 | 510 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
1f32ca31 | 511 | pnpacpi_parse_fixed_mem32_option(dev, option_flags, |
9dd78466 BH |
512 | &res->data.fixed_memory32); |
513 | break; | |
0af5853b | 514 | |
9dd78466 BH |
515 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
516 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
517 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
1f32ca31 | 518 | pnpacpi_parse_address_option(dev, option_flags, res); |
9dd78466 | 519 | break; |
0af5853b | 520 | |
9dd78466 | 521 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
8cb24c8f | 522 | pnpacpi_parse_ext_address_option(dev, option_flags, res); |
9dd78466 BH |
523 | break; |
524 | ||
525 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: | |
1f32ca31 | 526 | pnpacpi_parse_ext_irq_option(dev, option_flags, |
c1caf06c | 527 | &res->data.extended_irq); |
9dd78466 BH |
528 | break; |
529 | ||
530 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | |
531 | break; | |
532 | ||
533 | default: | |
af11cb2d BH |
534 | dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", |
535 | res->type); | |
9dd78466 | 536 | return AE_ERROR; |
1da177e4 | 537 | } |
1c6e7d0a | 538 | |
1da177e4 LT |
539 | return AE_OK; |
540 | } | |
541 | ||
d152cf5d | 542 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) |
1da177e4 | 543 | { |
c4da6940 BH |
544 | struct acpi_device *acpi_dev = dev->data; |
545 | acpi_handle handle = acpi_dev->handle; | |
1da177e4 LT |
546 | acpi_status status; |
547 | struct acpipnp_parse_option_s parse_data; | |
548 | ||
2f53432c | 549 | pnp_dbg(&dev->dev, "parse resource options\n"); |
72dcc883 | 550 | |
1da177e4 | 551 | parse_data.dev = dev; |
1f32ca31 BH |
552 | parse_data.option_flags = 0; |
553 | ||
50eca3eb | 554 | status = acpi_walk_resources(handle, METHOD_NAME__PRS, |
9dd78466 | 555 | pnpacpi_option_resource, &parse_data); |
1da177e4 | 556 | |
d152cf5d BH |
557 | if (ACPI_FAILURE(status)) { |
558 | if (status != AE_NOT_FOUND) | |
559 | dev_err(&dev->dev, "can't evaluate _PRS: %d", status); | |
560 | return -EPERM; | |
561 | } | |
562 | return 0; | |
1da177e4 LT |
563 | } |
564 | ||
b5f2490b | 565 | static int pnpacpi_supported_resource(struct acpi_resource *res) |
1da177e4 | 566 | { |
eca008c8 | 567 | switch (res->type) { |
50eca3eb | 568 | case ACPI_RESOURCE_TYPE_IRQ: |
50eca3eb BM |
569 | case ACPI_RESOURCE_TYPE_DMA: |
570 | case ACPI_RESOURCE_TYPE_IO: | |
571 | case ACPI_RESOURCE_TYPE_FIXED_IO: | |
572 | case ACPI_RESOURCE_TYPE_MEMORY24: | |
573 | case ACPI_RESOURCE_TYPE_MEMORY32: | |
574 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | |
50eca3eb BM |
575 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
576 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
577 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
8cb24c8f | 578 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: |
0af5853b | 579 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
b5f2490b | 580 | return 1; |
1da177e4 | 581 | } |
b5f2490b BH |
582 | return 0; |
583 | } | |
584 | ||
585 | /* | |
586 | * Set resource | |
587 | */ | |
588 | static acpi_status pnpacpi_count_resources(struct acpi_resource *res, | |
9dd78466 | 589 | void *data) |
b5f2490b | 590 | { |
4721a4cc | 591 | int *res_cnt = data; |
b5f2490b BH |
592 | |
593 | if (pnpacpi_supported_resource(res)) | |
594 | (*res_cnt)++; | |
1da177e4 LT |
595 | return AE_OK; |
596 | } | |
597 | ||
1c6e7d0a | 598 | static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) |
1da177e4 | 599 | { |
4721a4cc | 600 | struct acpi_resource **resource = data; |
b5f2490b BH |
601 | |
602 | if (pnpacpi_supported_resource(res)) { | |
eca008c8 | 603 | (*resource)->type = res->type; |
b5f2490b | 604 | (*resource)->length = sizeof(struct acpi_resource); |
36d872a3 BH |
605 | if (res->type == ACPI_RESOURCE_TYPE_IRQ) |
606 | (*resource)->data.irq.descriptor_length = | |
607 | res->data.irq.descriptor_length; | |
1da177e4 | 608 | (*resource)++; |
1da177e4 LT |
609 | } |
610 | ||
611 | return AE_OK; | |
612 | } | |
613 | ||
cdef6254 | 614 | int pnpacpi_build_resource_template(struct pnp_dev *dev, |
9dd78466 | 615 | struct acpi_buffer *buffer) |
1da177e4 | 616 | { |
c4da6940 BH |
617 | struct acpi_device *acpi_dev = dev->data; |
618 | acpi_handle handle = acpi_dev->handle; | |
1da177e4 LT |
619 | struct acpi_resource *resource; |
620 | int res_cnt = 0; | |
621 | acpi_status status; | |
622 | ||
50eca3eb | 623 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
9dd78466 | 624 | pnpacpi_count_resources, &res_cnt); |
1da177e4 | 625 | if (ACPI_FAILURE(status)) { |
d152cf5d | 626 | dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); |
1da177e4 LT |
627 | return -EINVAL; |
628 | } | |
629 | if (!res_cnt) | |
630 | return -EINVAL; | |
631 | buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1; | |
cd861280 | 632 | buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); |
1da177e4 LT |
633 | if (!buffer->pointer) |
634 | return -ENOMEM; | |
72dcc883 | 635 | |
1da177e4 | 636 | resource = (struct acpi_resource *)buffer->pointer; |
50eca3eb | 637 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, |
9dd78466 | 638 | pnpacpi_type_resources, &resource); |
1da177e4 LT |
639 | if (ACPI_FAILURE(status)) { |
640 | kfree(buffer->pointer); | |
d152cf5d | 641 | dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); |
1da177e4 LT |
642 | return -EINVAL; |
643 | } | |
644 | /* resource will pointer the end resource now */ | |
50eca3eb | 645 | resource->type = ACPI_RESOURCE_TYPE_END_TAG; |
f084dbb9 | 646 | resource->length = sizeof(struct acpi_resource); |
1da177e4 LT |
647 | |
648 | return 0; | |
649 | } | |
650 | ||
72dcc883 BH |
651 | static void pnpacpi_encode_irq(struct pnp_dev *dev, |
652 | struct acpi_resource *resource, | |
9dd78466 | 653 | struct resource *p) |
1da177e4 | 654 | { |
9570a20e | 655 | struct acpi_resource_irq *irq = &resource->data.irq; |
a993273b | 656 | int triggering, polarity, shareable; |
1c6e7d0a | 657 | |
aee3ad81 BH |
658 | if (!pnp_resource_enabled(p)) { |
659 | irq->interrupt_count = 0; | |
2f53432c | 660 | pnp_dbg(&dev->dev, " encode irq (%s)\n", |
aee3ad81 BH |
661 | p ? "disabled" : "missing"); |
662 | return; | |
663 | } | |
664 | ||
a993273b | 665 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
9570a20e BH |
666 | irq->triggering = triggering; |
667 | irq->polarity = polarity; | |
a993273b | 668 | irq->sharable = shareable; |
9570a20e BH |
669 | irq->interrupt_count = 1; |
670 | irq->interrupts[0] = p->start; | |
72dcc883 | 671 | |
2f53432c | 672 | pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", |
36d872a3 | 673 | (int) p->start, |
72dcc883 BH |
674 | triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", |
675 | polarity == ACPI_ACTIVE_LOW ? "low" : "high", | |
36d872a3 BH |
676 | irq->sharable == ACPI_SHARED ? "shared" : "exclusive", |
677 | irq->descriptor_length); | |
1da177e4 LT |
678 | } |
679 | ||
72dcc883 BH |
680 | static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, |
681 | struct acpi_resource *resource, | |
9dd78466 | 682 | struct resource *p) |
1da177e4 | 683 | { |
9570a20e | 684 | struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; |
a993273b | 685 | int triggering, polarity, shareable; |
1c6e7d0a | 686 | |
aee3ad81 BH |
687 | if (!pnp_resource_enabled(p)) { |
688 | extended_irq->interrupt_count = 0; | |
2f53432c | 689 | pnp_dbg(&dev->dev, " encode extended irq (%s)\n", |
aee3ad81 BH |
690 | p ? "disabled" : "missing"); |
691 | return; | |
692 | } | |
693 | ||
a993273b | 694 | decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); |
9570a20e BH |
695 | extended_irq->producer_consumer = ACPI_CONSUMER; |
696 | extended_irq->triggering = triggering; | |
697 | extended_irq->polarity = polarity; | |
a993273b | 698 | extended_irq->sharable = shareable; |
9570a20e BH |
699 | extended_irq->interrupt_count = 1; |
700 | extended_irq->interrupts[0] = p->start; | |
72dcc883 | 701 | |
2f53432c | 702 | pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, |
72dcc883 BH |
703 | triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", |
704 | polarity == ACPI_ACTIVE_LOW ? "low" : "high", | |
705 | extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); | |
1da177e4 LT |
706 | } |
707 | ||
72dcc883 BH |
708 | static void pnpacpi_encode_dma(struct pnp_dev *dev, |
709 | struct acpi_resource *resource, | |
9dd78466 | 710 | struct resource *p) |
1da177e4 | 711 | { |
9570a20e BH |
712 | struct acpi_resource_dma *dma = &resource->data.dma; |
713 | ||
aee3ad81 BH |
714 | if (!pnp_resource_enabled(p)) { |
715 | dma->channel_count = 0; | |
2f53432c | 716 | pnp_dbg(&dev->dev, " encode dma (%s)\n", |
aee3ad81 BH |
717 | p ? "disabled" : "missing"); |
718 | return; | |
719 | } | |
720 | ||
1da177e4 | 721 | /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ |
ccc4c7bb | 722 | switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { |
9dd78466 | 723 | case IORESOURCE_DMA_TYPEA: |
9570a20e | 724 | dma->type = ACPI_TYPE_A; |
9dd78466 BH |
725 | break; |
726 | case IORESOURCE_DMA_TYPEB: | |
9570a20e | 727 | dma->type = ACPI_TYPE_B; |
9dd78466 BH |
728 | break; |
729 | case IORESOURCE_DMA_TYPEF: | |
9570a20e | 730 | dma->type = ACPI_TYPE_F; |
9dd78466 BH |
731 | break; |
732 | default: | |
9570a20e | 733 | dma->type = ACPI_COMPATIBILITY; |
ccc4c7bb VP |
734 | } |
735 | ||
736 | switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { | |
9dd78466 | 737 | case IORESOURCE_DMA_8BIT: |
9570a20e | 738 | dma->transfer = ACPI_TRANSFER_8; |
9dd78466 BH |
739 | break; |
740 | case IORESOURCE_DMA_8AND16BIT: | |
9570a20e | 741 | dma->transfer = ACPI_TRANSFER_8_16; |
9dd78466 BH |
742 | break; |
743 | default: | |
9570a20e | 744 | dma->transfer = ACPI_TRANSFER_16; |
ccc4c7bb VP |
745 | } |
746 | ||
9570a20e BH |
747 | dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); |
748 | dma->channel_count = 1; | |
749 | dma->channels[0] = p->start; | |
72dcc883 | 750 | |
2f53432c | 751 | pnp_dbg(&dev->dev, " encode dma %d " |
72dcc883 BH |
752 | "type %#x transfer %#x master %d\n", |
753 | (int) p->start, dma->type, dma->transfer, dma->bus_master); | |
1da177e4 LT |
754 | } |
755 | ||
72dcc883 BH |
756 | static void pnpacpi_encode_io(struct pnp_dev *dev, |
757 | struct acpi_resource *resource, | |
9dd78466 | 758 | struct resource *p) |
1da177e4 | 759 | { |
9570a20e BH |
760 | struct acpi_resource_io *io = &resource->data.io; |
761 | ||
aee3ad81 BH |
762 | if (pnp_resource_enabled(p)) { |
763 | /* Note: pnp_assign_port copies pnp_port->flags into p->flags */ | |
08c9f262 | 764 | io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ? |
aee3ad81 BH |
765 | ACPI_DECODE_16 : ACPI_DECODE_10; |
766 | io->minimum = p->start; | |
767 | io->maximum = p->end; | |
768 | io->alignment = 0; /* Correct? */ | |
28f65c11 | 769 | io->address_length = resource_size(p); |
aee3ad81 BH |
770 | } else { |
771 | io->minimum = 0; | |
772 | io->address_length = 0; | |
773 | } | |
72dcc883 | 774 | |
2f53432c | 775 | pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, |
aee3ad81 | 776 | io->minimum + io->address_length - 1, io->io_decode); |
1da177e4 LT |
777 | } |
778 | ||
72dcc883 BH |
779 | static void pnpacpi_encode_fixed_io(struct pnp_dev *dev, |
780 | struct acpi_resource *resource, | |
9dd78466 | 781 | struct resource *p) |
1da177e4 | 782 | { |
9570a20e BH |
783 | struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; |
784 | ||
aee3ad81 BH |
785 | if (pnp_resource_enabled(p)) { |
786 | fixed_io->address = p->start; | |
28f65c11 | 787 | fixed_io->address_length = resource_size(p); |
aee3ad81 BH |
788 | } else { |
789 | fixed_io->address = 0; | |
790 | fixed_io->address_length = 0; | |
791 | } | |
72dcc883 | 792 | |
2f53432c | 793 | pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, |
aee3ad81 | 794 | fixed_io->address + fixed_io->address_length - 1); |
1da177e4 LT |
795 | } |
796 | ||
72dcc883 BH |
797 | static void pnpacpi_encode_mem24(struct pnp_dev *dev, |
798 | struct acpi_resource *resource, | |
9dd78466 | 799 | struct resource *p) |
1da177e4 | 800 | { |
9570a20e BH |
801 | struct acpi_resource_memory24 *memory24 = &resource->data.memory24; |
802 | ||
aee3ad81 BH |
803 | if (pnp_resource_enabled(p)) { |
804 | /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */ | |
805 | memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? | |
806 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
807 | memory24->minimum = p->start; | |
808 | memory24->maximum = p->end; | |
809 | memory24->alignment = 0; | |
28f65c11 | 810 | memory24->address_length = resource_size(p); |
aee3ad81 BH |
811 | } else { |
812 | memory24->minimum = 0; | |
813 | memory24->address_length = 0; | |
814 | } | |
815 | ||
2f53432c | 816 | pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
817 | memory24->minimum, |
818 | memory24->minimum + memory24->address_length - 1, | |
72dcc883 | 819 | memory24->write_protect); |
1da177e4 LT |
820 | } |
821 | ||
72dcc883 BH |
822 | static void pnpacpi_encode_mem32(struct pnp_dev *dev, |
823 | struct acpi_resource *resource, | |
9dd78466 | 824 | struct resource *p) |
1da177e4 | 825 | { |
9570a20e BH |
826 | struct acpi_resource_memory32 *memory32 = &resource->data.memory32; |
827 | ||
aee3ad81 BH |
828 | if (pnp_resource_enabled(p)) { |
829 | memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? | |
830 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
831 | memory32->minimum = p->start; | |
832 | memory32->maximum = p->end; | |
833 | memory32->alignment = 0; | |
28f65c11 | 834 | memory32->address_length = resource_size(p); |
aee3ad81 BH |
835 | } else { |
836 | memory32->minimum = 0; | |
837 | memory32->alignment = 0; | |
838 | } | |
72dcc883 | 839 | |
2f53432c | 840 | pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
841 | memory32->minimum, |
842 | memory32->minimum + memory32->address_length - 1, | |
72dcc883 | 843 | memory32->write_protect); |
1da177e4 LT |
844 | } |
845 | ||
72dcc883 BH |
846 | static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, |
847 | struct acpi_resource *resource, | |
9dd78466 | 848 | struct resource *p) |
1da177e4 | 849 | { |
9570a20e BH |
850 | struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; |
851 | ||
aee3ad81 BH |
852 | if (pnp_resource_enabled(p)) { |
853 | fixed_memory32->write_protect = | |
854 | p->flags & IORESOURCE_MEM_WRITEABLE ? | |
855 | ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; | |
856 | fixed_memory32->address = p->start; | |
28f65c11 | 857 | fixed_memory32->address_length = resource_size(p); |
aee3ad81 BH |
858 | } else { |
859 | fixed_memory32->address = 0; | |
860 | fixed_memory32->address_length = 0; | |
861 | } | |
72dcc883 | 862 | |
2f53432c | 863 | pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", |
aee3ad81 BH |
864 | fixed_memory32->address, |
865 | fixed_memory32->address + fixed_memory32->address_length - 1, | |
72dcc883 | 866 | fixed_memory32->write_protect); |
1da177e4 LT |
867 | } |
868 | ||
4ab55d8d | 869 | int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) |
1da177e4 LT |
870 | { |
871 | int i = 0; | |
872 | /* pnpacpi_build_resource_template allocates extra mem */ | |
9dd78466 | 873 | int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1; |
4721a4cc | 874 | struct acpi_resource *resource = buffer->pointer; |
1da177e4 LT |
875 | int port = 0, irq = 0, dma = 0, mem = 0; |
876 | ||
2f53432c | 877 | pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt); |
1da177e4 | 878 | while (i < res_cnt) { |
9dd78466 | 879 | switch (resource->type) { |
50eca3eb | 880 | case ACPI_RESOURCE_TYPE_IRQ: |
72dcc883 | 881 | pnpacpi_encode_irq(dev, resource, |
7e2cf31f | 882 | pnp_get_resource(dev, IORESOURCE_IRQ, irq)); |
1da177e4 LT |
883 | irq++; |
884 | break; | |
885 | ||
50eca3eb | 886 | case ACPI_RESOURCE_TYPE_DMA: |
72dcc883 | 887 | pnpacpi_encode_dma(dev, resource, |
7e2cf31f | 888 | pnp_get_resource(dev, IORESOURCE_DMA, dma)); |
1c6e7d0a | 889 | dma++; |
1da177e4 | 890 | break; |
50eca3eb | 891 | case ACPI_RESOURCE_TYPE_IO: |
72dcc883 | 892 | pnpacpi_encode_io(dev, resource, |
7e2cf31f | 893 | pnp_get_resource(dev, IORESOURCE_IO, port)); |
1c6e7d0a | 894 | port++; |
1da177e4 | 895 | break; |
50eca3eb | 896 | case ACPI_RESOURCE_TYPE_FIXED_IO: |
72dcc883 | 897 | pnpacpi_encode_fixed_io(dev, resource, |
7e2cf31f | 898 | pnp_get_resource(dev, IORESOURCE_IO, port)); |
1c6e7d0a | 899 | port++; |
1da177e4 | 900 | break; |
50eca3eb | 901 | case ACPI_RESOURCE_TYPE_MEMORY24: |
72dcc883 | 902 | pnpacpi_encode_mem24(dev, resource, |
7e2cf31f | 903 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 904 | mem++; |
1da177e4 | 905 | break; |
50eca3eb | 906 | case ACPI_RESOURCE_TYPE_MEMORY32: |
72dcc883 | 907 | pnpacpi_encode_mem32(dev, resource, |
7e2cf31f | 908 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 909 | mem++; |
1da177e4 | 910 | break; |
50eca3eb | 911 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
72dcc883 | 912 | pnpacpi_encode_fixed_mem32(dev, resource, |
7e2cf31f | 913 | pnp_get_resource(dev, IORESOURCE_MEM, mem)); |
1c6e7d0a | 914 | mem++; |
1da177e4 | 915 | break; |
0af5853b | 916 | case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: |
72dcc883 | 917 | pnpacpi_encode_ext_irq(dev, resource, |
7e2cf31f | 918 | pnp_get_resource(dev, IORESOURCE_IRQ, irq)); |
0af5853b LB |
919 | irq++; |
920 | break; | |
921 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | |
922 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | |
923 | case ACPI_RESOURCE_TYPE_VENDOR: | |
924 | case ACPI_RESOURCE_TYPE_END_TAG: | |
925 | case ACPI_RESOURCE_TYPE_ADDRESS16: | |
926 | case ACPI_RESOURCE_TYPE_ADDRESS32: | |
927 | case ACPI_RESOURCE_TYPE_ADDRESS64: | |
928 | case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: | |
929 | case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: | |
9dd78466 | 930 | default: /* other type */ |
af11cb2d BH |
931 | dev_warn(&dev->dev, "can't encode unknown resource " |
932 | "type %d\n", resource->type); | |
1da177e4 LT |
933 | return -EINVAL; |
934 | } | |
1c6e7d0a BH |
935 | resource++; |
936 | i++; | |
1da177e4 LT |
937 | } |
938 | return 0; | |
939 | } |