]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/pnp/pnpacpi/rsparser.c
PNPACPI: simplify irq_flags()
[mirror_ubuntu-hirsute-kernel.git] / drivers / pnp / pnpacpi / rsparser.c
CommitLineData
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>
50eca3eb 6 *
1da177e4
LT
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/kernel.h>
22#include <linux/acpi.h>
23#include <linux/pci.h>
24#include "pnpacpi.h"
25
26#ifdef CONFIG_IA64
27#define valid_IRQ(i) (1)
28#else
29#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
30#endif
31
32/*
33 * Allocated Resources
34 */
50eca3eb 35static int irq_flags(int triggering, int polarity)
1da177e4 36{
50eca3eb 37 if (triggering == ACPI_LEVEL_SENSITIVE) {
1c6e7d0a 38 if (polarity == ACPI_ACTIVE_LOW)
4cec086b 39 return IORESOURCE_IRQ_LOWLEVEL;
1da177e4 40 else
4cec086b 41 return IORESOURCE_IRQ_HIGHLEVEL;
9dd78466 42 } else {
1c6e7d0a 43 if (polarity == ACPI_ACTIVE_LOW)
4cec086b 44 return IORESOURCE_IRQ_LOWEDGE;
1da177e4 45 else
4cec086b 46 return IORESOURCE_IRQ_HIGHEDGE;
1da177e4 47 }
1da177e4
LT
48}
49
50eca3eb 50static void decode_irq_flags(int flag, int *triggering, int *polarity)
1da177e4
LT
51{
52 switch (flag) {
53 case IORESOURCE_IRQ_LOWLEVEL:
50eca3eb
BM
54 *triggering = ACPI_LEVEL_SENSITIVE;
55 *polarity = ACPI_ACTIVE_LOW;
1da177e4 56 break;
1c6e7d0a 57 case IORESOURCE_IRQ_HIGHLEVEL:
50eca3eb
BM
58 *triggering = ACPI_LEVEL_SENSITIVE;
59 *polarity = ACPI_ACTIVE_HIGH;
1da177e4
LT
60 break;
61 case IORESOURCE_IRQ_LOWEDGE:
50eca3eb
BM
62 *triggering = ACPI_EDGE_SENSITIVE;
63 *polarity = ACPI_ACTIVE_LOW;
1da177e4
LT
64 break;
65 case IORESOURCE_IRQ_HIGHEDGE:
50eca3eb
BM
66 *triggering = ACPI_EDGE_SENSITIVE;
67 *polarity = ACPI_ACTIVE_HIGH;
1da177e4
LT
68 break;
69 }
70}
71
07d4e9af
BH
72static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
73 u32 gsi, int triggering,
74 int polarity, int shareable)
1da177e4
LT
75{
76 int i = 0;
dbed12da
BH
77 int irq;
78
79 if (!valid_IRQ(gsi))
80 return;
81
1da177e4 82 while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
9dd78466 83 i < PNP_MAX_IRQ)
1da177e4 84 i++;
dbed12da
BH
85 if (i >= PNP_MAX_IRQ)
86 return;
87
9dd78466 88 res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
362ea087 89 res->irq_resource[i].flags |= irq_flags(triggering, polarity);
50eca3eb 90 irq = acpi_register_gsi(gsi, triggering, polarity);
dbed12da
BH
91 if (irq < 0) {
92 res->irq_resource[i].flags |= IORESOURCE_DISABLED;
93 return;
1da177e4 94 }
dbed12da 95
c32928c5
BH
96 if (shareable)
97 res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
98
dbed12da
BH
99 res->irq_resource[i].start = irq;
100 res->irq_resource[i].end = irq;
101 pcibios_penalize_isa_irq(irq, 1);
1da177e4
LT
102}
103
362ea087
MK
104static int dma_flags(int type, int bus_master, int transfer)
105{
106 int flags = 0;
107
108 if (bus_master)
109 flags |= IORESOURCE_DMA_MASTER;
110 switch (type) {
111 case ACPI_COMPATIBILITY:
112 flags |= IORESOURCE_DMA_COMPATIBLE;
113 break;
114 case ACPI_TYPE_A:
115 flags |= IORESOURCE_DMA_TYPEA;
116 break;
117 case ACPI_TYPE_B:
118 flags |= IORESOURCE_DMA_TYPEB;
119 break;
120 case ACPI_TYPE_F:
121 flags |= IORESOURCE_DMA_TYPEF;
122 break;
123 default:
124 /* Set a default value ? */
125 flags |= IORESOURCE_DMA_COMPATIBLE;
126 pnp_err("Invalid DMA type");
127 }
128 switch (transfer) {
129 case ACPI_TRANSFER_8:
130 flags |= IORESOURCE_DMA_8BIT;
131 break;
132 case ACPI_TRANSFER_8_16:
133 flags |= IORESOURCE_DMA_8AND16BIT;
134 break;
135 case ACPI_TRANSFER_16:
136 flags |= IORESOURCE_DMA_16BIT;
137 break;
138 default:
139 /* Set a default value ? */
140 flags |= IORESOURCE_DMA_8AND16BIT;
141 pnp_err("Invalid DMA transfer type");
142 }
143
144 return flags;
145}
146
07d4e9af
BH
147static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
148 u32 dma, int type,
149 int bus_master, int transfer)
1da177e4
LT
150{
151 int i = 0;
07d4e9af 152
0dec63ba 153 while (i < PNP_MAX_DMA &&
9dd78466 154 !(res->dma_resource[i].flags & IORESOURCE_UNSET))
1da177e4
LT
155 i++;
156 if (i < PNP_MAX_DMA) {
9dd78466
BH
157 res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
158 res->dma_resource[i].flags |=
159 dma_flags(type, bus_master, transfer);
1da177e4
LT
160 if (dma == -1) {
161 res->dma_resource[i].flags |= IORESOURCE_DISABLED;
162 return;
163 }
dbed12da
BH
164 res->dma_resource[i].start = dma;
165 res->dma_resource[i].end = dma;
1da177e4
LT
166 }
167}
168
07d4e9af
BH
169static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
170 u64 io, u64 len, int io_decode)
1da177e4
LT
171{
172 int i = 0;
07d4e9af 173
1da177e4 174 while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
9dd78466 175 i < PNP_MAX_PORT)
1da177e4
LT
176 i++;
177 if (i < PNP_MAX_PORT) {
9dd78466 178 res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
362ea087
MK
179 if (io_decode == ACPI_DECODE_16)
180 res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
9dd78466 181 if (len <= 0 || (io + len - 1) >= 0x10003) {
1da177e4
LT
182 res->port_resource[i].flags |= IORESOURCE_DISABLED;
183 return;
184 }
dbed12da
BH
185 res->port_resource[i].start = io;
186 res->port_resource[i].end = io + len - 1;
1da177e4
LT
187 }
188}
189
07d4e9af
BH
190static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
191 u64 mem, u64 len,
192 int write_protect)
1da177e4
LT
193{
194 int i = 0;
07d4e9af 195
1da177e4 196 while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
9dd78466 197 (i < PNP_MAX_MEM))
1da177e4
LT
198 i++;
199 if (i < PNP_MAX_MEM) {
9dd78466 200 res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
1da177e4
LT
201 if (len <= 0) {
202 res->mem_resource[i].flags |= IORESOURCE_DISABLED;
203 return;
204 }
9dd78466 205 if (write_protect == ACPI_READ_WRITE_MEMORY)
362ea087
MK
206 res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
207
dbed12da
BH
208 res->mem_resource[i].start = mem;
209 res->mem_resource[i].end = mem + len - 1;
1da177e4
LT
210 }
211}
212
07d4e9af
BH
213static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
214 struct acpi_resource *res)
1acfb7f2
BH
215{
216 struct acpi_resource_address64 addr, *p = &addr;
217 acpi_status status;
218
219 status = acpi_resource_to_address64(res, p);
220 if (!ACPI_SUCCESS(status)) {
221 pnp_warn("PnPACPI: failed to convert resource type %d",
9dd78466 222 res->type);
1acfb7f2
BH
223 return;
224 }
225
2b8de5f5
MC
226 if (p->producer_consumer == ACPI_PRODUCER)
227 return;
228
1acfb7f2
BH
229 if (p->resource_type == ACPI_MEMORY_RANGE)
230 pnpacpi_parse_allocated_memresource(res_table,
07d4e9af
BH
231 p->minimum, p->address_length,
232 p->info.mem.write_protect);
1acfb7f2
BH
233 else if (p->resource_type == ACPI_IO_RANGE)
234 pnpacpi_parse_allocated_ioresource(res_table,
07d4e9af
BH
235 p->minimum, p->address_length,
236 p->granularity == 0xfff ? ACPI_DECODE_10 :
237 ACPI_DECODE_16);
1acfb7f2 238}
1da177e4
LT
239
240static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
9dd78466 241 void *data)
1da177e4 242{
9dd78466
BH
243 struct pnp_resource_table *res_table =
244 (struct pnp_resource_table *)data;
dbed12da 245 int i;
1da177e4 246
eca008c8 247 switch (res->type) {
50eca3eb 248 case ACPI_RESOURCE_TYPE_IRQ:
dbed12da
BH
249 /*
250 * Per spec, only one interrupt per descriptor is allowed in
251 * _CRS, but some firmware violates this, so parse them all.
252 */
50eca3eb 253 for (i = 0; i < res->data.irq.interrupt_count; i++) {
dbed12da 254 pnpacpi_parse_allocated_irqresource(res_table,
07d4e9af
BH
255 res->data.irq.interrupts[i],
256 res->data.irq.triggering,
257 res->data.irq.polarity,
258 res->data.irq.sharable);
1da177e4
LT
259 }
260 break;
261
50eca3eb
BM
262 case ACPI_RESOURCE_TYPE_DMA:
263 if (res->data.dma.channel_count > 0)
264 pnpacpi_parse_allocated_dmaresource(res_table,
07d4e9af
BH
265 res->data.dma.channels[0],
266 res->data.dma.type,
267 res->data.dma.bus_master,
268 res->data.dma.transfer);
1da177e4 269 break;
0af5853b 270
50eca3eb
BM
271 case ACPI_RESOURCE_TYPE_IO:
272 pnpacpi_parse_allocated_ioresource(res_table,
07d4e9af
BH
273 res->data.io.minimum,
274 res->data.io.address_length,
275 res->data.io.io_decode);
1da177e4 276 break;
0af5853b
LB
277
278 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
279 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
280 break;
281
50eca3eb
BM
282 case ACPI_RESOURCE_TYPE_FIXED_IO:
283 pnpacpi_parse_allocated_ioresource(res_table,
07d4e9af
BH
284 res->data.fixed_io.address,
285 res->data.fixed_io.address_length,
286 ACPI_DECODE_10);
1da177e4 287 break;
0af5853b
LB
288
289 case ACPI_RESOURCE_TYPE_VENDOR:
290 break;
291
292 case ACPI_RESOURCE_TYPE_END_TAG:
293 break;
294
50eca3eb
BM
295 case ACPI_RESOURCE_TYPE_MEMORY24:
296 pnpacpi_parse_allocated_memresource(res_table,
07d4e9af
BH
297 res->data.memory24.minimum,
298 res->data.memory24.address_length,
299 res->data.memory24.write_protect);
1da177e4 300 break;
50eca3eb
BM
301 case ACPI_RESOURCE_TYPE_MEMORY32:
302 pnpacpi_parse_allocated_memresource(res_table,
07d4e9af
BH
303 res->data.memory32.minimum,
304 res->data.memory32.address_length,
305 res->data.memory32.write_protect);
1da177e4 306 break;
50eca3eb
BM
307 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
308 pnpacpi_parse_allocated_memresource(res_table,
07d4e9af
BH
309 res->data.fixed_memory32.address,
310 res->data.fixed_memory32.address_length,
311 res->data.fixed_memory32.write_protect);
1da177e4 312 break;
50eca3eb 313 case ACPI_RESOURCE_TYPE_ADDRESS16:
50eca3eb 314 case ACPI_RESOURCE_TYPE_ADDRESS32:
50eca3eb 315 case ACPI_RESOURCE_TYPE_ADDRESS64:
1acfb7f2 316 pnpacpi_parse_allocated_address_space(res_table, res);
1da177e4 317 break;
0af5853b
LB
318
319 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
2b8de5f5
MC
320 if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER)
321 return AE_OK;
0af5853b
LB
322 break;
323
324 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
2b8de5f5
MC
325 if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER)
326 return AE_OK;
327
0af5853b
LB
328 for (i = 0; i < res->data.extended_irq.interrupt_count; i++) {
329 pnpacpi_parse_allocated_irqresource(res_table,
07d4e9af
BH
330 res->data.extended_irq.interrupts[i],
331 res->data.extended_irq.triggering,
332 res->data.extended_irq.polarity,
333 res->data.extended_irq.sharable);
0af5853b
LB
334 }
335 break;
336
337 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
1da177e4 338 break;
0af5853b 339
1da177e4 340 default:
eca008c8 341 pnp_warn("PnPACPI: unknown resource type %d", res->type);
1da177e4
LT
342 return AE_ERROR;
343 }
1c6e7d0a 344
1da177e4
LT
345 return AE_OK;
346}
347
9dd78466
BH
348acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
349 struct pnp_resource_table * res)
1da177e4
LT
350{
351 /* Blank the resource table values */
352 pnp_init_resource_table(res);
353
9dd78466
BH
354 return acpi_walk_resources(handle, METHOD_NAME__CRS,
355 pnpacpi_allocated_resource, res);
1da177e4
LT
356}
357
9dd78466
BH
358static void pnpacpi_parse_dma_option(struct pnp_option *option,
359 struct acpi_resource_dma *p)
1da177e4
LT
360{
361 int i;
9dd78466 362 struct pnp_dma *dma;
1da177e4 363
50eca3eb 364 if (p->channel_count == 0)
1da177e4 365 return;
cd861280 366 dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
1da177e4
LT
367 if (!dma)
368 return;
369
9dd78466 370 for (i = 0; i < p->channel_count; i++)
1da177e4 371 dma->map |= 1 << p->channels[i];
362ea087
MK
372
373 dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
1da177e4 374
1c6e7d0a 375 pnp_register_dma_resource(option, dma);
1da177e4
LT
376}
377
1da177e4 378static void pnpacpi_parse_irq_option(struct pnp_option *option,
9dd78466 379 struct acpi_resource_irq *p)
1da177e4
LT
380{
381 int i;
1c6e7d0a
BH
382 struct pnp_irq *irq;
383
50eca3eb 384 if (p->interrupt_count == 0)
1da177e4 385 return;
cd861280 386 irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
1da177e4
LT
387 if (!irq)
388 return;
389
9dd78466 390 for (i = 0; i < p->interrupt_count; i++)
1da177e4
LT
391 if (p->interrupts[i])
392 __set_bit(p->interrupts[i], irq->map);
50eca3eb 393 irq->flags = irq_flags(p->triggering, p->polarity);
1da177e4
LT
394
395 pnp_register_irq_resource(option, irq);
1da177e4
LT
396}
397
398static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
9dd78466 399 struct acpi_resource_extended_irq *p)
1da177e4
LT
400{
401 int i;
1c6e7d0a 402 struct pnp_irq *irq;
1da177e4 403
50eca3eb 404 if (p->interrupt_count == 0)
1da177e4 405 return;
cd861280 406 irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
1da177e4
LT
407 if (!irq)
408 return;
409
9dd78466 410 for (i = 0; i < p->interrupt_count; i++)
1da177e4
LT
411 if (p->interrupts[i])
412 __set_bit(p->interrupts[i], irq->map);
50eca3eb 413 irq->flags = irq_flags(p->triggering, p->polarity);
1da177e4
LT
414
415 pnp_register_irq_resource(option, irq);
1da177e4
LT
416}
417
07d4e9af
BH
418static void pnpacpi_parse_port_option(struct pnp_option *option,
419 struct acpi_resource_io *io)
1da177e4 420{
1c6e7d0a 421 struct pnp_port *port;
1da177e4 422
50eca3eb 423 if (io->address_length == 0)
1da177e4 424 return;
cd861280 425 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
1da177e4
LT
426 if (!port)
427 return;
50eca3eb
BM
428 port->min = io->minimum;
429 port->max = io->maximum;
1da177e4 430 port->align = io->alignment;
50eca3eb
BM
431 port->size = io->address_length;
432 port->flags = ACPI_DECODE_16 == io->io_decode ?
9dd78466 433 PNP_PORT_FLAG_16BITADDR : 0;
1c6e7d0a 434 pnp_register_port_resource(option, port);
1da177e4
LT
435}
436
07d4e9af
BH
437static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
438 struct acpi_resource_fixed_io *io)
1da177e4 439{
1c6e7d0a 440 struct pnp_port *port;
1da177e4 441
50eca3eb 442 if (io->address_length == 0)
1da177e4 443 return;
cd861280 444 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
1da177e4
LT
445 if (!port)
446 return;
50eca3eb
BM
447 port->min = port->max = io->address;
448 port->size = io->address_length;
1da177e4
LT
449 port->align = 0;
450 port->flags = PNP_PORT_FLAG_FIXED;
1c6e7d0a 451 pnp_register_port_resource(option, port);
1da177e4
LT
452}
453
07d4e9af
BH
454static void pnpacpi_parse_mem24_option(struct pnp_option *option,
455 struct acpi_resource_memory24 *p)
1da177e4 456{
1c6e7d0a 457 struct pnp_mem *mem;
1da177e4 458
50eca3eb 459 if (p->address_length == 0)
1da177e4 460 return;
cd861280 461 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
462 if (!mem)
463 return;
50eca3eb
BM
464 mem->min = p->minimum;
465 mem->max = p->maximum;
1da177e4 466 mem->align = p->alignment;
50eca3eb 467 mem->size = p->address_length;
1da177e4 468
0897831b 469 mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
9dd78466 470 IORESOURCE_MEM_WRITEABLE : 0;
1da177e4 471
1c6e7d0a 472 pnp_register_mem_resource(option, mem);
1da177e4
LT
473}
474
07d4e9af
BH
475static void pnpacpi_parse_mem32_option(struct pnp_option *option,
476 struct acpi_resource_memory32 *p)
1da177e4 477{
1c6e7d0a 478 struct pnp_mem *mem;
1da177e4 479
50eca3eb 480 if (p->address_length == 0)
1da177e4 481 return;
cd861280 482 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
483 if (!mem)
484 return;
50eca3eb
BM
485 mem->min = p->minimum;
486 mem->max = p->maximum;
1da177e4 487 mem->align = p->alignment;
50eca3eb 488 mem->size = p->address_length;
1da177e4 489
0897831b 490 mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
9dd78466 491 IORESOURCE_MEM_WRITEABLE : 0;
1da177e4 492
1c6e7d0a 493 pnp_register_mem_resource(option, mem);
1da177e4
LT
494}
495
07d4e9af
BH
496static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
497 struct acpi_resource_fixed_memory32 *p)
1da177e4 498{
1c6e7d0a 499 struct pnp_mem *mem;
1da177e4 500
50eca3eb 501 if (p->address_length == 0)
1da177e4 502 return;
cd861280 503 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
1da177e4
LT
504 if (!mem)
505 return;
50eca3eb
BM
506 mem->min = mem->max = p->address;
507 mem->size = p->address_length;
1da177e4
LT
508 mem->align = 0;
509
0897831b 510 mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
9dd78466 511 IORESOURCE_MEM_WRITEABLE : 0;
1da177e4 512
1c6e7d0a 513 pnp_register_mem_resource(option, mem);
1da177e4
LT
514}
515
07d4e9af
BH
516static void pnpacpi_parse_address_option(struct pnp_option *option,
517 struct acpi_resource *r)
6f957eaf
BH
518{
519 struct acpi_resource_address64 addr, *p = &addr;
520 acpi_status status;
1c6e7d0a
BH
521 struct pnp_mem *mem;
522 struct pnp_port *port;
6f957eaf
BH
523
524 status = acpi_resource_to_address64(r, p);
525 if (!ACPI_SUCCESS(status)) {
9dd78466
BH
526 pnp_warn("PnPACPI: failed to convert resource type %d",
527 r->type);
6f957eaf
BH
528 return;
529 }
530
531 if (p->address_length == 0)
532 return;
533
534 if (p->resource_type == ACPI_MEMORY_RANGE) {
cd861280 535 mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
6f957eaf
BH
536 if (!mem)
537 return;
ed03f430 538 mem->min = mem->max = p->minimum;
6f957eaf
BH
539 mem->size = p->address_length;
540 mem->align = 0;
ed03f430 541 mem->flags = (p->info.mem.write_protect ==
9dd78466
BH
542 ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
543 : 0;
1c6e7d0a 544 pnp_register_mem_resource(option, mem);
6f957eaf 545 } else if (p->resource_type == ACPI_IO_RANGE) {
cd861280 546 port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
6f957eaf
BH
547 if (!port)
548 return;
ed03f430 549 port->min = port->max = p->minimum;
6f957eaf
BH
550 port->size = p->address_length;
551 port->align = 0;
552 port->flags = PNP_PORT_FLAG_FIXED;
1c6e7d0a 553 pnp_register_port_resource(option, port);
6f957eaf
BH
554 }
555}
556
1da177e4
LT
557struct acpipnp_parse_option_s {
558 struct pnp_option *option;
b008b8d7 559 struct pnp_option *option_independent;
1da177e4
LT
560 struct pnp_dev *dev;
561};
562
50eca3eb 563static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
9dd78466 564 void *data)
1da177e4
LT
565{
566 int priority = 0;
9dd78466
BH
567 struct acpipnp_parse_option_s *parse_data =
568 (struct acpipnp_parse_option_s *)data;
1da177e4
LT
569 struct pnp_dev *dev = parse_data->dev;
570 struct pnp_option *option = parse_data->option;
571
eca008c8 572 switch (res->type) {
9dd78466
BH
573 case ACPI_RESOURCE_TYPE_IRQ:
574 pnpacpi_parse_irq_option(option, &res->data.irq);
575 break;
0af5853b 576
9dd78466
BH
577 case ACPI_RESOURCE_TYPE_DMA:
578 pnpacpi_parse_dma_option(option, &res->data.dma);
579 break;
0af5853b 580
9dd78466
BH
581 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
582 switch (res->data.start_dpf.compatibility_priority) {
583 case ACPI_GOOD_CONFIGURATION:
584 priority = PNP_RES_PRIORITY_PREFERRED;
1da177e4 585 break;
0af5853b 586
9dd78466
BH
587 case ACPI_ACCEPTABLE_CONFIGURATION:
588 priority = PNP_RES_PRIORITY_ACCEPTABLE;
b008b8d7 589 break;
0af5853b 590
9dd78466
BH
591 case ACPI_SUB_OPTIMAL_CONFIGURATION:
592 priority = PNP_RES_PRIORITY_FUNCTIONAL;
0af5853b 593 break;
9dd78466
BH
594 default:
595 priority = PNP_RES_PRIORITY_INVALID;
0af5853b 596 break;
9dd78466 597 }
07d4e9af 598 /* TBD: Consider performance/robustness bits */
9dd78466
BH
599 option = pnp_register_dependent_option(dev, priority);
600 if (!option)
601 return AE_ERROR;
602 parse_data->option = option;
603 break;
0af5853b 604
9dd78466
BH
605 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
606 /*only one EndDependentFn is allowed */
607 if (!parse_data->option_independent) {
608 pnp_warn("PnPACPI: more than one EndDependentFn");
609 return AE_ERROR;
610 }
611 parse_data->option = parse_data->option_independent;
612 parse_data->option_independent = NULL;
613 break;
0af5853b 614
9dd78466
BH
615 case ACPI_RESOURCE_TYPE_IO:
616 pnpacpi_parse_port_option(option, &res->data.io);
617 break;
0af5853b 618
9dd78466
BH
619 case ACPI_RESOURCE_TYPE_FIXED_IO:
620 pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io);
621 break;
0af5853b 622
9dd78466
BH
623 case ACPI_RESOURCE_TYPE_VENDOR:
624 case ACPI_RESOURCE_TYPE_END_TAG:
625 break;
0af5853b 626
9dd78466
BH
627 case ACPI_RESOURCE_TYPE_MEMORY24:
628 pnpacpi_parse_mem24_option(option, &res->data.memory24);
629 break;
0af5853b 630
9dd78466
BH
631 case ACPI_RESOURCE_TYPE_MEMORY32:
632 pnpacpi_parse_mem32_option(option, &res->data.memory32);
633 break;
0af5853b 634
9dd78466
BH
635 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
636 pnpacpi_parse_fixed_mem32_option(option,
637 &res->data.fixed_memory32);
638 break;
0af5853b 639
9dd78466
BH
640 case ACPI_RESOURCE_TYPE_ADDRESS16:
641 case ACPI_RESOURCE_TYPE_ADDRESS32:
642 case ACPI_RESOURCE_TYPE_ADDRESS64:
643 pnpacpi_parse_address_option(option, res);
644 break;
0af5853b 645
9dd78466
BH
646 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
647 break;
648
649 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
650 pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq);
651 break;
652
653 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
654 break;
655
656 default:
657 pnp_warn("PnPACPI: unknown resource type %d", res->type);
658 return AE_ERROR;
1da177e4 659 }
1c6e7d0a 660
1da177e4
LT
661 return AE_OK;
662}
663
50eca3eb 664acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
9dd78466 665 struct pnp_dev * dev)
1da177e4
LT
666{
667 acpi_status status;
668 struct acpipnp_parse_option_s parse_data;
669
670 parse_data.option = pnp_register_independent_option(dev);
671 if (!parse_data.option)
672 return AE_ERROR;
b008b8d7 673 parse_data.option_independent = parse_data.option;
1da177e4 674 parse_data.dev = dev;
50eca3eb 675 status = acpi_walk_resources(handle, METHOD_NAME__PRS,
9dd78466 676 pnpacpi_option_resource, &parse_data);
1da177e4
LT
677
678 return status;
679}
680
b5f2490b 681static int pnpacpi_supported_resource(struct acpi_resource *res)
1da177e4 682{
eca008c8 683 switch (res->type) {
50eca3eb 684 case ACPI_RESOURCE_TYPE_IRQ:
50eca3eb
BM
685 case ACPI_RESOURCE_TYPE_DMA:
686 case ACPI_RESOURCE_TYPE_IO:
687 case ACPI_RESOURCE_TYPE_FIXED_IO:
688 case ACPI_RESOURCE_TYPE_MEMORY24:
689 case ACPI_RESOURCE_TYPE_MEMORY32:
690 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
50eca3eb
BM
691 case ACPI_RESOURCE_TYPE_ADDRESS16:
692 case ACPI_RESOURCE_TYPE_ADDRESS32:
693 case ACPI_RESOURCE_TYPE_ADDRESS64:
0af5853b 694 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
b5f2490b 695 return 1;
1da177e4 696 }
b5f2490b
BH
697 return 0;
698}
699
700/*
701 * Set resource
702 */
703static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
9dd78466 704 void *data)
b5f2490b
BH
705{
706 int *res_cnt = (int *)data;
707
708 if (pnpacpi_supported_resource(res))
709 (*res_cnt)++;
1da177e4
LT
710 return AE_OK;
711}
712
1c6e7d0a 713static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
1da177e4 714{
1c6e7d0a 715 struct acpi_resource **resource = (struct acpi_resource **)data;
b5f2490b
BH
716
717 if (pnpacpi_supported_resource(res)) {
eca008c8 718 (*resource)->type = res->type;
b5f2490b 719 (*resource)->length = sizeof(struct acpi_resource);
1da177e4 720 (*resource)++;
1da177e4
LT
721 }
722
723 return AE_OK;
724}
725
50eca3eb 726int pnpacpi_build_resource_template(acpi_handle handle,
9dd78466 727 struct acpi_buffer *buffer)
1da177e4
LT
728{
729 struct acpi_resource *resource;
730 int res_cnt = 0;
731 acpi_status status;
732
50eca3eb 733 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
9dd78466 734 pnpacpi_count_resources, &res_cnt);
1da177e4
LT
735 if (ACPI_FAILURE(status)) {
736 pnp_err("Evaluate _CRS failed");
737 return -EINVAL;
738 }
739 if (!res_cnt)
740 return -EINVAL;
741 buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
cd861280 742 buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
1da177e4
LT
743 if (!buffer->pointer)
744 return -ENOMEM;
745 pnp_dbg("Res cnt %d", res_cnt);
746 resource = (struct acpi_resource *)buffer->pointer;
50eca3eb 747 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
9dd78466 748 pnpacpi_type_resources, &resource);
1da177e4
LT
749 if (ACPI_FAILURE(status)) {
750 kfree(buffer->pointer);
751 pnp_err("Evaluate _CRS failed");
752 return -EINVAL;
753 }
754 /* resource will pointer the end resource now */
50eca3eb 755 resource->type = ACPI_RESOURCE_TYPE_END_TAG;
1da177e4
LT
756
757 return 0;
758}
759
50eca3eb 760static void pnpacpi_encode_irq(struct acpi_resource *resource,
9dd78466 761 struct resource *p)
1da177e4 762{
50eca3eb 763 int triggering, polarity;
1c6e7d0a
BH
764
765 decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
50eca3eb
BM
766 resource->data.irq.triggering = triggering;
767 resource->data.irq.polarity = polarity;
768 if (triggering == ACPI_EDGE_SENSITIVE)
769 resource->data.irq.sharable = ACPI_EXCLUSIVE;
1da177e4 770 else
50eca3eb
BM
771 resource->data.irq.sharable = ACPI_SHARED;
772 resource->data.irq.interrupt_count = 1;
1da177e4
LT
773 resource->data.irq.interrupts[0] = p->start;
774}
775
776static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
9dd78466 777 struct resource *p)
1da177e4 778{
50eca3eb 779 int triggering, polarity;
1c6e7d0a
BH
780
781 decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
1da177e4 782 resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
50eca3eb
BM
783 resource->data.extended_irq.triggering = triggering;
784 resource->data.extended_irq.polarity = polarity;
785 if (triggering == ACPI_EDGE_SENSITIVE)
786 resource->data.irq.sharable = ACPI_EXCLUSIVE;
1da177e4 787 else
50eca3eb
BM
788 resource->data.irq.sharable = ACPI_SHARED;
789 resource->data.extended_irq.interrupt_count = 1;
1da177e4
LT
790 resource->data.extended_irq.interrupts[0] = p->start;
791}
792
793static void pnpacpi_encode_dma(struct acpi_resource *resource,
9dd78466 794 struct resource *p)
1da177e4 795{
1da177e4 796 /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
ccc4c7bb 797 switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
9dd78466
BH
798 case IORESOURCE_DMA_TYPEA:
799 resource->data.dma.type = ACPI_TYPE_A;
800 break;
801 case IORESOURCE_DMA_TYPEB:
802 resource->data.dma.type = ACPI_TYPE_B;
803 break;
804 case IORESOURCE_DMA_TYPEF:
805 resource->data.dma.type = ACPI_TYPE_F;
806 break;
807 default:
808 resource->data.dma.type = ACPI_COMPATIBILITY;
ccc4c7bb
VP
809 }
810
811 switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
9dd78466
BH
812 case IORESOURCE_DMA_8BIT:
813 resource->data.dma.transfer = ACPI_TRANSFER_8;
814 break;
815 case IORESOURCE_DMA_8AND16BIT:
816 resource->data.dma.transfer = ACPI_TRANSFER_8_16;
817 break;
818 default:
819 resource->data.dma.transfer = ACPI_TRANSFER_16;
ccc4c7bb
VP
820 }
821
822 resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
50eca3eb 823 resource->data.dma.channel_count = 1;
1da177e4
LT
824 resource->data.dma.channels[0] = p->start;
825}
826
827static void pnpacpi_encode_io(struct acpi_resource *resource,
9dd78466 828 struct resource *p)
1da177e4 829{
1da177e4 830 /* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
9dd78466
BH
831 resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
832 ACPI_DECODE_16 : ACPI_DECODE_10;
50eca3eb
BM
833 resource->data.io.minimum = p->start;
834 resource->data.io.maximum = p->end;
9dd78466 835 resource->data.io.alignment = 0; /* Correct? */
50eca3eb 836 resource->data.io.address_length = p->end - p->start + 1;
1da177e4
LT
837}
838
839static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
9dd78466 840 struct resource *p)
1da177e4 841{
50eca3eb
BM
842 resource->data.fixed_io.address = p->start;
843 resource->data.fixed_io.address_length = p->end - p->start + 1;
1da177e4
LT
844}
845
846static void pnpacpi_encode_mem24(struct acpi_resource *resource,
9dd78466 847 struct resource *p)
1da177e4 848{
1da177e4 849 /* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
0897831b 850 resource->data.memory24.write_protect =
9dd78466
BH
851 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
852 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
50eca3eb
BM
853 resource->data.memory24.minimum = p->start;
854 resource->data.memory24.maximum = p->end;
1da177e4 855 resource->data.memory24.alignment = 0;
50eca3eb 856 resource->data.memory24.address_length = p->end - p->start + 1;
1da177e4
LT
857}
858
859static void pnpacpi_encode_mem32(struct acpi_resource *resource,
9dd78466 860 struct resource *p)
1da177e4 861{
0897831b 862 resource->data.memory32.write_protect =
9dd78466
BH
863 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
864 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
50eca3eb
BM
865 resource->data.memory32.minimum = p->start;
866 resource->data.memory32.maximum = p->end;
1da177e4 867 resource->data.memory32.alignment = 0;
50eca3eb 868 resource->data.memory32.address_length = p->end - p->start + 1;
1da177e4
LT
869}
870
871static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
9dd78466 872 struct resource *p)
1da177e4 873{
0897831b 874 resource->data.fixed_memory32.write_protect =
9dd78466
BH
875 (p->flags & IORESOURCE_MEM_WRITEABLE) ?
876 ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
50eca3eb
BM
877 resource->data.fixed_memory32.address = p->start;
878 resource->data.fixed_memory32.address_length = p->end - p->start + 1;
1da177e4
LT
879}
880
50eca3eb 881int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
9dd78466 882 struct acpi_buffer *buffer)
1da177e4
LT
883{
884 int i = 0;
885 /* pnpacpi_build_resource_template allocates extra mem */
9dd78466
BH
886 int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
887 struct acpi_resource *resource =
888 (struct acpi_resource *)buffer->pointer;
1da177e4
LT
889 int port = 0, irq = 0, dma = 0, mem = 0;
890
891 pnp_dbg("res cnt %d", res_cnt);
892 while (i < res_cnt) {
9dd78466 893 switch (resource->type) {
50eca3eb 894 case ACPI_RESOURCE_TYPE_IRQ:
1da177e4 895 pnp_dbg("Encode irq");
50eca3eb 896 pnpacpi_encode_irq(resource,
9dd78466 897 &res_table->irq_resource[irq]);
1da177e4
LT
898 irq++;
899 break;
900
50eca3eb 901 case ACPI_RESOURCE_TYPE_DMA:
1da177e4 902 pnp_dbg("Encode dma");
50eca3eb 903 pnpacpi_encode_dma(resource,
9dd78466 904 &res_table->dma_resource[dma]);
1c6e7d0a 905 dma++;
1da177e4 906 break;
50eca3eb 907 case ACPI_RESOURCE_TYPE_IO:
1da177e4 908 pnp_dbg("Encode io");
50eca3eb 909 pnpacpi_encode_io(resource,
9dd78466 910 &res_table->port_resource[port]);
1c6e7d0a 911 port++;
1da177e4 912 break;
50eca3eb 913 case ACPI_RESOURCE_TYPE_FIXED_IO:
1da177e4
LT
914 pnp_dbg("Encode fixed io");
915 pnpacpi_encode_fixed_io(resource,
9dd78466
BH
916 &res_table->
917 port_resource[port]);
1c6e7d0a 918 port++;
1da177e4 919 break;
50eca3eb 920 case ACPI_RESOURCE_TYPE_MEMORY24:
1da177e4
LT
921 pnp_dbg("Encode mem24");
922 pnpacpi_encode_mem24(resource,
9dd78466 923 &res_table->mem_resource[mem]);
1c6e7d0a 924 mem++;
1da177e4 925 break;
50eca3eb 926 case ACPI_RESOURCE_TYPE_MEMORY32:
1da177e4
LT
927 pnp_dbg("Encode mem32");
928 pnpacpi_encode_mem32(resource,
9dd78466 929 &res_table->mem_resource[mem]);
1c6e7d0a 930 mem++;
1da177e4 931 break;
50eca3eb 932 case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1da177e4
LT
933 pnp_dbg("Encode fixed mem32");
934 pnpacpi_encode_fixed_mem32(resource,
9dd78466
BH
935 &res_table->
936 mem_resource[mem]);
1c6e7d0a 937 mem++;
1da177e4 938 break;
0af5853b
LB
939 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
940 pnp_dbg("Encode ext irq");
941 pnpacpi_encode_ext_irq(resource,
9dd78466 942 &res_table->irq_resource[irq]);
0af5853b
LB
943 irq++;
944 break;
945 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
946 case ACPI_RESOURCE_TYPE_END_DEPENDENT:
947 case ACPI_RESOURCE_TYPE_VENDOR:
948 case ACPI_RESOURCE_TYPE_END_TAG:
949 case ACPI_RESOURCE_TYPE_ADDRESS16:
950 case ACPI_RESOURCE_TYPE_ADDRESS32:
951 case ACPI_RESOURCE_TYPE_ADDRESS64:
952 case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
953 case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
9dd78466 954 default: /* other type */
eca008c8 955 pnp_warn("unknown resource type %d", resource->type);
1da177e4
LT
956 return -EINVAL;
957 }
1c6e7d0a
BH
958 resource++;
959 i++;
1da177e4
LT
960 }
961 return 0;
962}