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