rsparser.c 31.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * pnpacpi -- PnP ACPI driver
 *
 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
6 7
 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
B
Bob Moore 已提交
8
 *
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
26
#include <linux/pnp.h>
27
#include <linux/slab.h>
28
#include "../base.h"
L
Linus Torvalds 已提交
29 30 31 32 33 34 35 36 37 38 39
#include "pnpacpi.h"

#ifdef CONFIG_IA64
#define valid_IRQ(i) (1)
#else
#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
#endif

/*
 * Allocated Resources
 */
40
static int irq_flags(int triggering, int polarity, int shareable)
L
Linus Torvalds 已提交
41
{
42 43
	int flags;

B
Bob Moore 已提交
44
	if (triggering == ACPI_LEVEL_SENSITIVE) {
B
Bjorn Helgaas 已提交
45
		if (polarity == ACPI_ACTIVE_LOW)
46
			flags = IORESOURCE_IRQ_LOWLEVEL;
L
Linus Torvalds 已提交
47
		else
48
			flags = IORESOURCE_IRQ_HIGHLEVEL;
B
Bjorn Helgaas 已提交
49
	} else {
B
Bjorn Helgaas 已提交
50
		if (polarity == ACPI_ACTIVE_LOW)
51
			flags = IORESOURCE_IRQ_LOWEDGE;
L
Linus Torvalds 已提交
52
		else
53
			flags = IORESOURCE_IRQ_HIGHEDGE;
L
Linus Torvalds 已提交
54
	}
55

56
	if (shareable == ACPI_SHARED)
57 58 59
		flags |= IORESOURCE_IRQ_SHAREABLE;

	return flags;
L
Linus Torvalds 已提交
60 61
}

B
Bjorn Helgaas 已提交
62
static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
63
			     int *polarity, int *shareable)
L
Linus Torvalds 已提交
64
{
B
Bjorn Helgaas 已提交
65 66
	switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
			 IORESOURCE_IRQ_LOWEDGE  | IORESOURCE_IRQ_HIGHEDGE)) {
L
Linus Torvalds 已提交
67
	case IORESOURCE_IRQ_LOWLEVEL:
B
Bob Moore 已提交
68 69
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
70
		break;
B
Bjorn Helgaas 已提交
71
	case IORESOURCE_IRQ_HIGHLEVEL:
B
Bob Moore 已提交
72 73
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
74 75
		break;
	case IORESOURCE_IRQ_LOWEDGE:
B
Bob Moore 已提交
76 77
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
78 79
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
B
Bob Moore 已提交
80 81
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
82
		break;
B
Bjorn Helgaas 已提交
83 84 85 86 87 88
	default:
		dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n",
			flags);
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
		break;
L
Linus Torvalds 已提交
89
	}
90 91 92 93 94

	if (flags & IORESOURCE_IRQ_SHAREABLE)
		*shareable = ACPI_SHARED;
	else
		*shareable = ACPI_EXCLUSIVE;
L
Linus Torvalds 已提交
95 96
}

97
static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
98 99
						u32 gsi, int triggering,
						int polarity, int shareable)
L
Linus Torvalds 已提交
100
{
101
	int irq, flags;
102
	int p, t;
103

104 105
	if (!valid_IRQ(gsi)) {
		pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED);
106
		return;
107
	}
108

109 110 111 112 113 114 115 116 117 118
	/*
	 * in IO-APIC mode, use overrided attribute. Two reasons:
	 * 1. BIOS bug in DSDT
	 * 2. BIOS uses IO-APIC mode Interrupt Source Override
	 */
	if (!acpi_get_override_irq(gsi, &t, &p)) {
		t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
		p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;

		if (triggering != t || polarity != p) {
119
			dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
120 121 122 123 124 125
				gsi, t ? "edge":"level", p ? "low":"high");
			triggering = t;
			polarity = p;
		}
	}

126
	flags = irq_flags(triggering, polarity, shareable);
127
	irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
128 129 130 131
	if (irq >= 0)
		pcibios_penalize_isa_irq(irq, 1);
	else
		flags |= IORESOURCE_DISABLED;
132

133
	pnp_add_irq_resource(dev, irq, flags);
L
Linus Torvalds 已提交
134 135
}

136 137
static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
		     int transfer)
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
	int flags = 0;

	if (bus_master)
		flags |= IORESOURCE_DMA_MASTER;
	switch (type) {
	case ACPI_COMPATIBILITY:
		flags |= IORESOURCE_DMA_COMPATIBLE;
		break;
	case ACPI_TYPE_A:
		flags |= IORESOURCE_DMA_TYPEA;
		break;
	case ACPI_TYPE_B:
		flags |= IORESOURCE_DMA_TYPEB;
		break;
	case ACPI_TYPE_F:
		flags |= IORESOURCE_DMA_TYPEF;
		break;
	default:
		/* Set a default value ? */
		flags |= IORESOURCE_DMA_COMPATIBLE;
159
		dev_err(&dev->dev, "invalid DMA type %d\n", type);
160 161 162 163 164 165 166 167 168 169 170 171 172 173
	}
	switch (transfer) {
	case ACPI_TRANSFER_8:
		flags |= IORESOURCE_DMA_8BIT;
		break;
	case ACPI_TRANSFER_8_16:
		flags |= IORESOURCE_DMA_8AND16BIT;
		break;
	case ACPI_TRANSFER_16:
		flags |= IORESOURCE_DMA_16BIT;
		break;
	default:
		/* Set a default value ? */
		flags |= IORESOURCE_DMA_8AND16BIT;
174
		dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
175 176 177 178 179
	}

	return flags;
}

180
static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
B
Bjorn Helgaas 已提交
181 182
					       u64 len, int io_decode,
					       int window)
L
Linus Torvalds 已提交
183
{
184 185
	int flags = 0;
	u64 end = start + len - 1;
B
Bjorn Helgaas 已提交
186

187
	if (io_decode == ACPI_DECODE_16)
188
		flags |= IORESOURCE_IO_16BIT_ADDR;
189 190
	if (len == 0 || end >= 0x10003)
		flags |= IORESOURCE_DISABLED;
B
Bjorn Helgaas 已提交
191 192
	if (window)
		flags |= IORESOURCE_WINDOW;
193 194

	pnp_add_io_resource(dev, start, end, flags);
L
Linus Torvalds 已提交
195 196
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
/*
 * Device CSRs that do not appear in PCI config space should be described
 * via ACPI.  This would normally be done with Address Space Descriptors
 * marked as "consumer-only," but old versions of Windows and Linux ignore
 * the producer/consumer flag, so HP invented a vendor-defined resource to
 * describe the location and size of CSR space.
 */
static struct acpi_vendor_uuid hp_ccsr_uuid = {
	.subtype = 2,
	.data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a,
	    0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad },
};

static int vendor_resource_matches(struct pnp_dev *dev,
				   struct acpi_resource_vendor_typed *vendor,
				   struct acpi_vendor_uuid *match,
				   int expected_len)
{
	int uuid_len = sizeof(vendor->uuid);
	u8 uuid_subtype = vendor->uuid_subtype;
	u8 *uuid = vendor->uuid;
	int actual_len;

	/* byte_length includes uuid_subtype and uuid */
	actual_len = vendor->byte_length - uuid_len - 1;

	if (uuid_subtype == match->subtype &&
	    uuid_len == sizeof(match->data) &&
	    memcmp(uuid, match->data, uuid_len) == 0) {
		if (expected_len && expected_len != actual_len) {
			dev_err(&dev->dev, "wrong vendor descriptor size; "
				"expected %d, found %d bytes\n",
				expected_len, actual_len);
			return 0;
		}

		return 1;
	}

	return 0;
}

static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev,
				    struct acpi_resource_vendor_typed *vendor)
{
	if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 16)) {
		u64 start, length;

		memcpy(&start, vendor->byte_data, sizeof(start));
		memcpy(&length, vendor->byte_data + 8, sizeof(length));

		pnp_add_mem_resource(dev, start, start + length - 1, 0);
	}
}

252
static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
253
						u64 start, u64 len,
B
Bjorn Helgaas 已提交
254
						int write_protect, int window)
L
Linus Torvalds 已提交
255
{
256 257 258 259 260 261 262
	int flags = 0;
	u64 end = start + len - 1;

	if (len == 0)
		flags |= IORESOURCE_DISABLED;
	if (write_protect == ACPI_READ_WRITE_MEMORY)
		flags |= IORESOURCE_MEM_WRITEABLE;
B
Bjorn Helgaas 已提交
263 264
	if (window)
		flags |= IORESOURCE_WINDOW;
265 266

	pnp_add_mem_resource(dev, start, end, flags);
L
Linus Torvalds 已提交
267 268
}

B
Bjorn Helgaas 已提交
269 270 271 272 273 274 275 276
static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
						u64 start, u64 len)
{
	u64 end = start + len - 1;

	pnp_add_bus_resource(dev, start, end);
}

277
static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
278
						  struct acpi_resource *res)
279 280 281
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
B
Bjorn Helgaas 已提交
282
	int window;
283
	u64 len;
284 285 286

	status = acpi_resource_to_address64(res, p);
	if (!ACPI_SUCCESS(status)) {
287
		dev_warn(&dev->dev, "failed to convert resource type %d\n",
B
Bjorn Helgaas 已提交
288
			 res->type);
289 290 291
		return;
	}

292 293
	/* Windows apparently computes length rather than using _LEN */
	len = p->maximum - p->minimum + 1;
B
Bjorn Helgaas 已提交
294
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
295

296
	if (p->resource_type == ACPI_MEMORY_RANGE)
297
		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
298
			p->info.mem.write_protect, window);
299
	else if (p->resource_type == ACPI_IO_RANGE)
300
		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
301
			p->granularity == 0xfff ? ACPI_DECODE_10 :
B
Bjorn Helgaas 已提交
302
				ACPI_DECODE_16, window);
B
Bjorn Helgaas 已提交
303
	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
304
		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
305
}
L
Linus Torvalds 已提交
306

307 308 309 310
static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
						      struct acpi_resource *res)
{
	struct acpi_resource_extended_address64 *p = &res->data.ext_address64;
B
Bjorn Helgaas 已提交
311
	int window;
312
	u64 len;
313

314 315
	/* Windows apparently computes length rather than using _LEN */
	len = p->maximum - p->minimum + 1;
B
Bjorn Helgaas 已提交
316
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
317 318

	if (p->resource_type == ACPI_MEMORY_RANGE)
319
		pnpacpi_parse_allocated_memresource(dev, p->minimum, len,
B
Bjorn Helgaas 已提交
320
			p->info.mem.write_protect, window);
321
	else if (p->resource_type == ACPI_IO_RANGE)
322
		pnpacpi_parse_allocated_ioresource(dev, p->minimum, len,
323
			p->granularity == 0xfff ? ACPI_DECODE_10 :
B
Bjorn Helgaas 已提交
324
				ACPI_DECODE_16, window);
B
Bjorn Helgaas 已提交
325
	else if (p->resource_type == ACPI_BUS_NUMBER_RANGE)
326
		pnpacpi_parse_allocated_busresource(dev, p->minimum, len);
327 328
}

L
Linus Torvalds 已提交
329
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
330
					      void *data)
L
Linus Torvalds 已提交
331
{
332
	struct pnp_dev *dev = data;
333 334 335 336
	struct acpi_resource_irq *irq;
	struct acpi_resource_dma *dma;
	struct acpi_resource_io *io;
	struct acpi_resource_fixed_io *fixed_io;
337
	struct acpi_resource_vendor_typed *vendor_typed;
338 339 340 341
	struct acpi_resource_memory24 *memory24;
	struct acpi_resource_memory32 *memory32;
	struct acpi_resource_fixed_memory32 *fixed_memory32;
	struct acpi_resource_extended_irq *extended_irq;
342
	int i, flags;
L
Linus Torvalds 已提交
343

344
	switch (res->type) {
B
Bob Moore 已提交
345
	case ACPI_RESOURCE_TYPE_IRQ:
346 347 348 349
		/*
		 * Per spec, only one interrupt per descriptor is allowed in
		 * _CRS, but some firmware violates this, so parse them all.
		 */
350
		irq = &res->data.irq;
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
		if (irq->interrupt_count == 0)
			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		else {
			for (i = 0; i < irq->interrupt_count; i++) {
				pnpacpi_parse_allocated_irqresource(dev,
					irq->interrupts[i],
					irq->triggering,
					irq->polarity,
				    irq->sharable);
			}

			/*
			 * The IRQ encoder puts a single interrupt in each
			 * descriptor, so if a _CRS descriptor has more than
			 * one interrupt, we won't be able to re-encode it.
			 */
			if (pnp_can_write(dev) && irq->interrupt_count > 1) {
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
L
Linus Torvalds 已提交
373 374 375
		}
		break;

B
Bob Moore 已提交
376
	case ACPI_RESOURCE_TYPE_DMA:
377
		dma = &res->data.dma;
378
		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
379
			flags = dma_flags(dev, dma->type, dma->bus_master,
380
					  dma->transfer);
381 382 383
		else
			flags = IORESOURCE_DISABLED;
		pnp_add_dma_resource(dev, dma->channels[0], flags);
L
Linus Torvalds 已提交
384
		break;
385

B
Bob Moore 已提交
386
	case ACPI_RESOURCE_TYPE_IO:
387
		io = &res->data.io;
388
		pnpacpi_parse_allocated_ioresource(dev,
389 390
			io->minimum,
			io->address_length,
B
Bjorn Helgaas 已提交
391
			io->io_decode, 0);
L
Linus Torvalds 已提交
392
		break;
393 394 395 396 397

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

B
Bob Moore 已提交
398
	case ACPI_RESOURCE_TYPE_FIXED_IO:
399
		fixed_io = &res->data.fixed_io;
400
		pnpacpi_parse_allocated_ioresource(dev,
401 402
			fixed_io->address,
			fixed_io->address_length,
B
Bjorn Helgaas 已提交
403
			ACPI_DECODE_10, 0);
L
Linus Torvalds 已提交
404
		break;
405 406

	case ACPI_RESOURCE_TYPE_VENDOR:
407 408
		vendor_typed = &res->data.vendor_typed;
		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
409 410 411 412 413
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

B
Bob Moore 已提交
414
	case ACPI_RESOURCE_TYPE_MEMORY24:
415
		memory24 = &res->data.memory24;
416
		pnpacpi_parse_allocated_memresource(dev,
417 418
			memory24->minimum,
			memory24->address_length,
B
Bjorn Helgaas 已提交
419
			memory24->write_protect, 0);
L
Linus Torvalds 已提交
420
		break;
B
Bob Moore 已提交
421
	case ACPI_RESOURCE_TYPE_MEMORY32:
422
		memory32 = &res->data.memory32;
423
		pnpacpi_parse_allocated_memresource(dev,
424 425
			memory32->minimum,
			memory32->address_length,
B
Bjorn Helgaas 已提交
426
			memory32->write_protect, 0);
L
Linus Torvalds 已提交
427
		break;
B
Bob Moore 已提交
428
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
429
		fixed_memory32 = &res->data.fixed_memory32;
430
		pnpacpi_parse_allocated_memresource(dev,
431 432
			fixed_memory32->address,
			fixed_memory32->address_length,
B
Bjorn Helgaas 已提交
433
			fixed_memory32->write_protect, 0);
L
Linus Torvalds 已提交
434
		break;
B
Bob Moore 已提交
435 436 437
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
438
		pnpacpi_parse_allocated_address_space(dev, res);
L
Linus Torvalds 已提交
439
		break;
440 441

	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
442
		pnpacpi_parse_allocated_ext_address_space(dev, res);
443 444 445
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
446
		extended_irq = &res->data.extended_irq;
447

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
		if (extended_irq->interrupt_count == 0)
			pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		else {
			for (i = 0; i < extended_irq->interrupt_count; i++) {
				pnpacpi_parse_allocated_irqresource(dev,
					extended_irq->interrupts[i],
					extended_irq->triggering,
					extended_irq->polarity,
					extended_irq->sharable);
			}

			/*
			 * The IRQ encoder puts a single interrupt in each
			 * descriptor, so if a _CRS descriptor has more than
			 * one interrupt, we won't be able to re-encode it.
			 */
			if (pnp_can_write(dev) &&
			    extended_irq->interrupt_count > 1) {
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
471 472 473 474
		}
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
L
Linus Torvalds 已提交
475
		break;
476

L
Linus Torvalds 已提交
477
	default:
478 479
		dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
			 res->type);
L
Linus Torvalds 已提交
480 481
		return AE_ERROR;
	}
B
Bjorn Helgaas 已提交
482

L
Linus Torvalds 已提交
483 484 485
	return AE_OK;
}

486
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
L
Linus Torvalds 已提交
487
{
488 489
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
490
	acpi_status status;
491

B
Bjorn Helgaas 已提交
492
	pnp_dbg(&dev->dev, "parse allocated resources\n");
493

494
	pnp_init_resources(dev);
L
Linus Torvalds 已提交
495

496 497 498 499 500 501 502 503 504
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
				     pnpacpi_allocated_resource, dev);

	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND)
			dev_err(&dev->dev, "can't evaluate _CRS: %d", status);
		return -EPERM;
	}
	return 0;
L
Linus Torvalds 已提交
505 506
}

507
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
508
					    unsigned int option_flags,
509
					    struct acpi_resource_dma *p)
L
Linus Torvalds 已提交
510 511
{
	int i;
512
	unsigned char map = 0, flags;
L
Linus Torvalds 已提交
513

B
Bjorn Helgaas 已提交
514
	for (i = 0; i < p->channel_count; i++)
515
		map |= 1 << p->channels[i];
L
Linus Torvalds 已提交
516

517
	flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
518
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
519 520
}

521
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
522
					    unsigned int option_flags,
523
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
524 525
{
	int i;
526
	pnp_irq_mask_t map;
527
	unsigned char flags;
L
Linus Torvalds 已提交
528

529
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
530
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
531
		if (p->interrupts[i])
532
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
533

534
	flags = irq_flags(p->triggering, p->polarity, p->sharable);
535
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
536 537
}

538
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
539
					unsigned int option_flags,
540
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
541 542
{
	int i;
543
	pnp_irq_mask_t map;
544
	unsigned char flags;
L
Linus Torvalds 已提交
545

546
	bitmap_zero(map.bits, PNP_IRQ_NR);
547 548 549 550 551 552 553 554 555 556
	for (i = 0; i < p->interrupt_count; i++) {
		if (p->interrupts[i]) {
			if (p->interrupts[i] < PNP_IRQ_NR)
				__set_bit(p->interrupts[i], map.bits);
			else
				dev_err(&dev->dev, "ignoring IRQ %d option "
					"(too large for %d entry bitmap)\n",
					p->interrupts[i], PNP_IRQ_NR);
		}
	}
L
Linus Torvalds 已提交
557

558
	flags = irq_flags(p->triggering, p->polarity, p->sharable);
559
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
560 561
}

562
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
563
					     unsigned int option_flags,
564
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
565
{
566
	unsigned char flags = 0;
L
Linus Torvalds 已提交
567

568
	if (io->io_decode == ACPI_DECODE_16)
569
		flags = IORESOURCE_IO_16BIT_ADDR;
570
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
571
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
572 573
}

574
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
575
					unsigned int option_flags,
576
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
577
{
578
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
579
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
580 581
}

582
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
583
					      unsigned int option_flags,
584
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
585
{
586
	unsigned char flags = 0;
L
Linus Torvalds 已提交
587

588
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
589
		flags = IORESOURCE_MEM_WRITEABLE;
590
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
591
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
592 593
}

594
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
595
					      unsigned int option_flags,
596
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
597
{
598
	unsigned char flags = 0;
L
Linus Torvalds 已提交
599

600
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
601
		flags = IORESOURCE_MEM_WRITEABLE;
602
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
603
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
604 605
}

606
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
607
					unsigned int option_flags,
608
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
609
{
610
	unsigned char flags = 0;
L
Linus Torvalds 已提交
611

612
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
613
		flags = IORESOURCE_MEM_WRITEABLE;
614
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
615
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
616 617
}

618
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
619
						unsigned int option_flags,
620
						struct acpi_resource *r)
621 622 623
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
624
	unsigned char flags = 0;
625 626

	status = acpi_resource_to_address64(r, p);
627 628
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
629
			 r->type);
630 631 632 633
		return;
	}

	if (p->resource_type == ACPI_MEMORY_RANGE) {
634
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
635
			flags = IORESOURCE_MEM_WRITEABLE;
636 637 638
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
639
	} else if (p->resource_type == ACPI_IO_RANGE)
640 641
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
642
					   IORESOURCE_IO_FIXED);
643 644
}

645 646 647 648 649 650 651 652 653
static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev,
						    unsigned int option_flags,
						    struct acpi_resource *r)
{
	struct acpi_resource_extended_address64 *p = &r->data.ext_address64;
	unsigned char flags = 0;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
654
			flags = IORESOURCE_MEM_WRITEABLE;
655 656 657 658 659 660
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
	} else if (p->resource_type == ACPI_IO_RANGE)
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
661
					   IORESOURCE_IO_FIXED);
662 663
}

L
Linus Torvalds 已提交
664 665
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
666
	unsigned int option_flags;
L
Linus Torvalds 已提交
667 668
};

669 670
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
671
{
672
	int priority;
673
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
674
	struct pnp_dev *dev = parse_data->dev;
675
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
676

677
	switch (res->type) {
B
Bjorn Helgaas 已提交
678
	case ACPI_RESOURCE_TYPE_IRQ:
679
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
680
		break;
681

B
Bjorn Helgaas 已提交
682
	case ACPI_RESOURCE_TYPE_DMA:
683
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
684
		break;
685

B
Bjorn Helgaas 已提交
686 687 688 689
	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
		switch (res->data.start_dpf.compatibility_priority) {
		case ACPI_GOOD_CONFIGURATION:
			priority = PNP_RES_PRIORITY_PREFERRED;
L
Linus Torvalds 已提交
690
			break;
691

B
Bjorn Helgaas 已提交
692 693
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
694
			break;
695

B
Bjorn Helgaas 已提交
696 697
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
698
			break;
B
Bjorn Helgaas 已提交
699 700
		default:
			priority = PNP_RES_PRIORITY_INVALID;
701
			break;
B
Bjorn Helgaas 已提交
702
		}
703
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
704
		break;
705

B
Bjorn Helgaas 已提交
706
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
707
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
708
		break;
709

B
Bjorn Helgaas 已提交
710
	case ACPI_RESOURCE_TYPE_IO:
711
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
712
		break;
713

B
Bjorn Helgaas 已提交
714
	case ACPI_RESOURCE_TYPE_FIXED_IO:
715
		pnpacpi_parse_fixed_port_option(dev, option_flags,
716
					        &res->data.fixed_io);
B
Bjorn Helgaas 已提交
717
		break;
718

B
Bjorn Helgaas 已提交
719 720 721
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
722

B
Bjorn Helgaas 已提交
723
	case ACPI_RESOURCE_TYPE_MEMORY24:
724 725
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
726
		break;
727

B
Bjorn Helgaas 已提交
728
	case ACPI_RESOURCE_TYPE_MEMORY32:
729 730
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
731
		break;
732

B
Bjorn Helgaas 已提交
733
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
734
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
735 736
						 &res->data.fixed_memory32);
		break;
737

B
Bjorn Helgaas 已提交
738 739 740
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
741
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
742
		break;
743

B
Bjorn Helgaas 已提交
744
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
745
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
746 747 748
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
749
		pnpacpi_parse_ext_irq_option(dev, option_flags,
750
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
751 752 753 754 755 756
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
757 758
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
759
		return AE_ERROR;
L
Linus Torvalds 已提交
760
	}
B
Bjorn Helgaas 已提交
761

L
Linus Torvalds 已提交
762 763 764
	return AE_OK;
}

765
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
766
{
767 768
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
769 770 771
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

B
Bjorn Helgaas 已提交
772
	pnp_dbg(&dev->dev, "parse resource options\n");
773

L
Linus Torvalds 已提交
774
	parse_data.dev = dev;
775 776
	parse_data.option_flags = 0;

B
Bob Moore 已提交
777
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
778
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
779

780 781 782 783 784 785
	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND)
			dev_err(&dev->dev, "can't evaluate _PRS: %d", status);
		return -EPERM;
	}
	return 0;
L
Linus Torvalds 已提交
786 787
}

788
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
789
{
790
	switch (res->type) {
B
Bob Moore 已提交
791 792 793 794 795 796 797 798 799 800
	case ACPI_RESOURCE_TYPE_IRQ:
	case ACPI_RESOURCE_TYPE_DMA:
	case ACPI_RESOURCE_TYPE_IO:
	case ACPI_RESOURCE_TYPE_FIXED_IO:
	case ACPI_RESOURCE_TYPE_MEMORY24:
	case ACPI_RESOURCE_TYPE_MEMORY32:
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
801
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
802
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
803
		return 1;
L
Linus Torvalds 已提交
804
	}
805 806 807 808 809 810 811
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
812
					   void *data)
813
{
814
	int *res_cnt = data;
815 816 817

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
818 819 820
	return AE_OK;
}

B
Bjorn Helgaas 已提交
821
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
822
{
823
	struct acpi_resource **resource = data;
824 825

	if (pnpacpi_supported_resource(res)) {
826
		(*resource)->type = res->type;
827
		(*resource)->length = sizeof(struct acpi_resource);
828 829 830
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
831 832 833 834 835 836
		(*resource)++;
	}

	return AE_OK;
}

837
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
838
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
839
{
840 841
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
842 843 844 845
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
846
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
847
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
848
	if (ACPI_FAILURE(status)) {
849
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
850 851 852 853 854
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
855
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
856 857
	if (!buffer->pointer)
		return -ENOMEM;
858

L
Linus Torvalds 已提交
859
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
860
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
861
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
862 863
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
864
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
865 866 867
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
868
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
L
Linus Torvalds 已提交
869 870 871 872

	return 0;
}

873 874
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
875
			       struct resource *p)
L
Linus Torvalds 已提交
876
{
877
	struct acpi_resource_irq *irq = &resource->data.irq;
878
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
879

880 881
	if (!pnp_resource_enabled(p)) {
		irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
882
		pnp_dbg(&dev->dev, "  encode irq (%s)\n",
883 884 885 886
			p ? "disabled" : "missing");
		return;
	}

887
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
888 889
	irq->triggering = triggering;
	irq->polarity = polarity;
890
	irq->sharable = shareable;
891 892
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
893

B
Bjorn Helgaas 已提交
894
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s (%d-byte descriptor)\n",
895
		(int) p->start,
896 897
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
898 899
		irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
		irq->descriptor_length);
L
Linus Torvalds 已提交
900 901
}

902 903
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
904
				   struct resource *p)
L
Linus Torvalds 已提交
905
{
906
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
907
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
908

909 910
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
911
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
912 913 914 915
			p ? "disabled" : "missing");
		return;
	}

916
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
917 918 919
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
920
	extended_irq->sharable = shareable;
921 922
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
923

B
Bjorn Helgaas 已提交
924
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
925 926 927
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
928 929
}

930 931
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
932
			       struct resource *p)
L
Linus Torvalds 已提交
933
{
934 935
	struct acpi_resource_dma *dma = &resource->data.dma;

936 937
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
938
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
939 940 941 942
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
943
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
944
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
945
	case IORESOURCE_DMA_TYPEA:
946
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
947 948
		break;
	case IORESOURCE_DMA_TYPEB:
949
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
950 951
		break;
	case IORESOURCE_DMA_TYPEF:
952
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
953 954
		break;
	default:
955
		dma->type = ACPI_COMPATIBILITY;
956 957 958
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
959
	case IORESOURCE_DMA_8BIT:
960
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
961 962
		break;
	case IORESOURCE_DMA_8AND16BIT:
963
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
964 965
		break;
	default:
966
		dma->transfer = ACPI_TRANSFER_16;
967 968
	}

969 970 971
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
972

B
Bjorn Helgaas 已提交
973
	pnp_dbg(&dev->dev, "  encode dma %d "
974 975
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
976 977
}

978 979
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
980
			      struct resource *p)
L
Linus Torvalds 已提交
981
{
982 983
	struct acpi_resource_io *io = &resource->data.io;

984 985
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
986
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
987 988 989 990
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
991
		io->address_length = resource_size(p);
992 993 994 995
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
996

B
Bjorn Helgaas 已提交
997
	pnp_dbg(&dev->dev, "  encode io %#x-%#x decode %#x\n", io->minimum,
998
		io->minimum + io->address_length - 1, io->io_decode);
L
Linus Torvalds 已提交
999 1000
}

1001 1002
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1003
				    struct resource *p)
L
Linus Torvalds 已提交
1004
{
1005 1006
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

1007 1008
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
1009
		fixed_io->address_length = resource_size(p);
1010 1011 1012 1013
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
1014

B
Bjorn Helgaas 已提交
1015
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
1016
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
1017 1018
}

1019 1020
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1021
				 struct resource *p)
L
Linus Torvalds 已提交
1022
{
1023 1024
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

1025 1026 1027 1028 1029 1030 1031
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */
		memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		memory24->minimum = p->start;
		memory24->maximum = p->end;
		memory24->alignment = 0;
1032
		memory24->address_length = resource_size(p);
1033 1034 1035 1036 1037
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
1038
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
1039 1040
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
1041
		memory24->write_protect);
L
Linus Torvalds 已提交
1042 1043
}

1044 1045
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1046
				 struct resource *p)
L
Linus Torvalds 已提交
1047
{
1048 1049
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

1050 1051 1052 1053 1054 1055
	if (pnp_resource_enabled(p)) {
		memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		memory32->minimum = p->start;
		memory32->maximum = p->end;
		memory32->alignment = 0;
1056
		memory32->address_length = resource_size(p);
1057 1058 1059 1060
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
1061

B
Bjorn Helgaas 已提交
1062
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
1063 1064
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
1065
		memory32->write_protect);
L
Linus Torvalds 已提交
1066 1067
}

1068 1069
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1070
				       struct resource *p)
L
Linus Torvalds 已提交
1071
{
1072 1073
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

1074 1075 1076 1077 1078
	if (pnp_resource_enabled(p)) {
		fixed_memory32->write_protect =
		    p->flags & IORESOURCE_MEM_WRITEABLE ?
		    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
		fixed_memory32->address = p->start;
1079
		fixed_memory32->address_length = resource_size(p);
1080 1081 1082 1083
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
1084

B
Bjorn Helgaas 已提交
1085
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
1086 1087
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
1088
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
1089 1090
}

1091
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
1092 1093 1094
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
1095
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
1096
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
1097 1098
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
1099
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
1100
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
1101
		switch (resource->type) {
B
Bob Moore 已提交
1102
		case ACPI_RESOURCE_TYPE_IRQ:
1103
			pnpacpi_encode_irq(dev, resource,
1104
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
1105 1106 1107
			irq++;
			break;

B
Bob Moore 已提交
1108
		case ACPI_RESOURCE_TYPE_DMA:
1109
			pnpacpi_encode_dma(dev, resource,
1110
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
1111
			dma++;
L
Linus Torvalds 已提交
1112
			break;
B
Bob Moore 已提交
1113
		case ACPI_RESOURCE_TYPE_IO:
1114
			pnpacpi_encode_io(dev, resource,
1115
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1116
			port++;
L
Linus Torvalds 已提交
1117
			break;
B
Bob Moore 已提交
1118
		case ACPI_RESOURCE_TYPE_FIXED_IO:
1119
			pnpacpi_encode_fixed_io(dev, resource,
1120
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1121
			port++;
L
Linus Torvalds 已提交
1122
			break;
B
Bob Moore 已提交
1123
		case ACPI_RESOURCE_TYPE_MEMORY24:
1124
			pnpacpi_encode_mem24(dev, resource,
1125
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1126
			mem++;
L
Linus Torvalds 已提交
1127
			break;
B
Bob Moore 已提交
1128
		case ACPI_RESOURCE_TYPE_MEMORY32:
1129
			pnpacpi_encode_mem32(dev, resource,
1130
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1131
			mem++;
L
Linus Torvalds 已提交
1132
			break;
B
Bob Moore 已提交
1133
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1134
			pnpacpi_encode_fixed_mem32(dev, resource,
1135
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1136
			mem++;
L
Linus Torvalds 已提交
1137
			break;
1138
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1139
			pnpacpi_encode_ext_irq(dev, resource,
1140
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
			irq++;
			break;
		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		case ACPI_RESOURCE_TYPE_VENDOR:
		case ACPI_RESOURCE_TYPE_END_TAG:
		case ACPI_RESOURCE_TYPE_ADDRESS16:
		case ACPI_RESOURCE_TYPE_ADDRESS32:
		case ACPI_RESOURCE_TYPE_ADDRESS64:
		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
B
Bjorn Helgaas 已提交
1152
		default:	/* other type */
1153 1154
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
1155 1156
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
1157 1158
		resource++;
		i++;
L
Linus Torvalds 已提交
1159 1160 1161
	}
	return 0;
}