rsparser.c 32.4 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 = 0;
L
Linus Torvalds 已提交
513

B
Bob Moore 已提交
514
	if (p->channel_count == 0)
515
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
516

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

520
	flags |= dma_flags(dev, p->type, p->bus_master, p->transfer);
521
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
522 523
}

524
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
525
					    unsigned int option_flags,
526
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
527 528
{
	int i;
529
	pnp_irq_mask_t map;
530
	unsigned char flags = 0;
B
Bjorn Helgaas 已提交
531

B
Bob Moore 已提交
532
	if (p->interrupt_count == 0)
533
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
534

535
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
536
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
537
		if (p->interrupts[i])
538
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
539

540
	flags |= irq_flags(p->triggering, p->polarity, p->sharable);
541
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
542 543
}

544
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
545
					unsigned int option_flags,
546
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
547 548
{
	int i;
549
	pnp_irq_mask_t map;
550
	unsigned char flags = 0;
L
Linus Torvalds 已提交
551

B
Bob Moore 已提交
552
	if (p->interrupt_count == 0)
553
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
554

555
	bitmap_zero(map.bits, PNP_IRQ_NR);
556 557 558 559 560 561 562 563 564 565
	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 已提交
566

567
	flags |= irq_flags(p->triggering, p->polarity, p->sharable);
568
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
569 570
}

571
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
572
					     unsigned int option_flags,
573
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
574
{
575
	unsigned char flags = 0;
L
Linus Torvalds 已提交
576

B
Bob Moore 已提交
577
	if (io->address_length == 0)
578
		flags |= IORESOURCE_DISABLED;
579 580

	if (io->io_decode == ACPI_DECODE_16)
581
		flags |= IORESOURCE_IO_16BIT_ADDR;
582
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
583
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
584 585
}

586
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
587
					unsigned int option_flags,
588
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
589
{
590 591
	unsigned char flags = 0;

B
Bob Moore 已提交
592
	if (io->address_length == 0)
593
		flags |= IORESOURCE_DISABLED;
594

595
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
596
				   0, io->address_length, flags | IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
597 598
}

599
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
600
					      unsigned int option_flags,
601
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
602
{
603
	unsigned char flags = 0;
L
Linus Torvalds 已提交
604

B
Bob Moore 已提交
605
	if (p->address_length == 0)
606
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
607

608
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
609
		flags |= IORESOURCE_MEM_WRITEABLE;
610
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
611
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
612 613
}

614
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
615
					      unsigned int option_flags,
616
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
617
{
618
	unsigned char flags = 0;
L
Linus Torvalds 已提交
619

B
Bob Moore 已提交
620
	if (p->address_length == 0)
621
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
622

623
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
624
		flags |= IORESOURCE_MEM_WRITEABLE;
625
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
626
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
627 628
}

629
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
630
					unsigned int option_flags,
631
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
632
{
633
	unsigned char flags = 0;
L
Linus Torvalds 已提交
634

B
Bob Moore 已提交
635
	if (p->address_length == 0)
636
		flags |= IORESOURCE_DISABLED;
L
Linus Torvalds 已提交
637

638
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
639
		flags |= IORESOURCE_MEM_WRITEABLE;
640
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
641
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
642 643
}

644
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
645
						unsigned int option_flags,
646
						struct acpi_resource *r)
647 648 649
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
650
	unsigned char flags = 0;
651 652

	status = acpi_resource_to_address64(r, p);
653 654
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
655
			 r->type);
656 657 658 659
		return;
	}

	if (p->address_length == 0)
660
		flags |= IORESOURCE_DISABLED;
661 662

	if (p->resource_type == ACPI_MEMORY_RANGE) {
663
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
664
			flags |= IORESOURCE_MEM_WRITEABLE;
665 666 667
		pnp_register_mem_resource(dev, option_flags, p->minimum,
					  p->minimum, 0, p->address_length,
					  flags);
668
	} else if (p->resource_type == ACPI_IO_RANGE)
669 670
		pnp_register_port_resource(dev, option_flags, p->minimum,
					   p->minimum, 0, p->address_length,
671
					   flags | IORESOURCE_IO_FIXED);
672 673
}

674 675 676 677 678 679 680 681
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->address_length == 0)
682
		flags |= IORESOURCE_DISABLED;
683 684 685

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
686
			flags |= IORESOURCE_MEM_WRITEABLE;
687 688 689 690 691 692
		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,
693
					   flags | IORESOURCE_IO_FIXED);
694 695
}

L
Linus Torvalds 已提交
696 697
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
698
	unsigned int option_flags;
L
Linus Torvalds 已提交
699 700
};

701 702
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
703
{
704
	int priority;
705
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
706
	struct pnp_dev *dev = parse_data->dev;
707
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
708

709
	switch (res->type) {
B
Bjorn Helgaas 已提交
710
	case ACPI_RESOURCE_TYPE_IRQ:
711
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
712
		break;
713

B
Bjorn Helgaas 已提交
714
	case ACPI_RESOURCE_TYPE_DMA:
715
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
716
		break;
717

B
Bjorn Helgaas 已提交
718 719 720 721
	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 已提交
722
			break;
723

B
Bjorn Helgaas 已提交
724 725
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
726
			break;
727

B
Bjorn Helgaas 已提交
728 729
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
730
			break;
B
Bjorn Helgaas 已提交
731 732
		default:
			priority = PNP_RES_PRIORITY_INVALID;
733
			break;
B
Bjorn Helgaas 已提交
734
		}
735
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
736
		break;
737

B
Bjorn Helgaas 已提交
738
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
739
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
740
		break;
741

B
Bjorn Helgaas 已提交
742
	case ACPI_RESOURCE_TYPE_IO:
743
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
744
		break;
745

B
Bjorn Helgaas 已提交
746
	case ACPI_RESOURCE_TYPE_FIXED_IO:
747
		pnpacpi_parse_fixed_port_option(dev, option_flags,
748
					        &res->data.fixed_io);
B
Bjorn Helgaas 已提交
749
		break;
750

B
Bjorn Helgaas 已提交
751 752 753
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
754

B
Bjorn Helgaas 已提交
755
	case ACPI_RESOURCE_TYPE_MEMORY24:
756 757
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
758
		break;
759

B
Bjorn Helgaas 已提交
760
	case ACPI_RESOURCE_TYPE_MEMORY32:
761 762
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
763
		break;
764

B
Bjorn Helgaas 已提交
765
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
766
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
767 768
						 &res->data.fixed_memory32);
		break;
769

B
Bjorn Helgaas 已提交
770 771 772
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
773
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
774
		break;
775

B
Bjorn Helgaas 已提交
776
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
777
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
778 779 780
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
781
		pnpacpi_parse_ext_irq_option(dev, option_flags,
782
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
783 784 785 786 787 788
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
789 790
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
791
		return AE_ERROR;
L
Linus Torvalds 已提交
792
	}
B
Bjorn Helgaas 已提交
793

L
Linus Torvalds 已提交
794 795 796
	return AE_OK;
}

797
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
798
{
799 800
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
801 802 803
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

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

L
Linus Torvalds 已提交
806
	parse_data.dev = dev;
807 808
	parse_data.option_flags = 0;

B
Bob Moore 已提交
809
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
810
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
811

812 813 814 815 816 817
	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 已提交
818 819
}

820
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
821
{
822
	switch (res->type) {
B
Bob Moore 已提交
823 824 825 826 827 828 829 830 831 832
	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:
833
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
834
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
835
		return 1;
L
Linus Torvalds 已提交
836
	}
837 838 839 840 841 842 843
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
844
					   void *data)
845
{
846
	int *res_cnt = data;
847 848 849

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
850 851 852
	return AE_OK;
}

B
Bjorn Helgaas 已提交
853
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
854
{
855
	struct acpi_resource **resource = data;
856 857

	if (pnpacpi_supported_resource(res)) {
858
		(*resource)->type = res->type;
859
		(*resource)->length = sizeof(struct acpi_resource);
860 861 862
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
863 864 865 866 867 868
		(*resource)++;
	}

	return AE_OK;
}

869
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
870
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
871
{
872 873
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
874 875 876 877
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
878
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
879
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
880
	if (ACPI_FAILURE(status)) {
881
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
882 883 884 885 886
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
887
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
888 889
	if (!buffer->pointer)
		return -ENOMEM;
890

L
Linus Torvalds 已提交
891
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
892
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
893
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
894 895
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
896
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
897 898 899
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
900
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
L
Linus Torvalds 已提交
901 902 903 904

	return 0;
}

905 906
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
907
			       struct resource *p)
L
Linus Torvalds 已提交
908
{
909
	struct acpi_resource_irq *irq = &resource->data.irq;
910
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
911

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

919
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
920 921
	irq->triggering = triggering;
	irq->polarity = polarity;
922
	irq->sharable = shareable;
923 924
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
925

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

934 935
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
936
				   struct resource *p)
L
Linus Torvalds 已提交
937
{
938
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
939
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
940

941 942
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
943
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
944 945 946 947
			p ? "disabled" : "missing");
		return;
	}

948
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
949 950 951
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
952
	extended_irq->sharable = shareable;
953 954
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
955

B
Bjorn Helgaas 已提交
956
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
957 958 959
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
960 961
}

962 963
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
964
			       struct resource *p)
L
Linus Torvalds 已提交
965
{
966 967
	struct acpi_resource_dma *dma = &resource->data.dma;

968 969
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
970
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
971 972 973 974
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
975
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
976
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
977
	case IORESOURCE_DMA_TYPEA:
978
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
979 980
		break;
	case IORESOURCE_DMA_TYPEB:
981
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
982 983
		break;
	case IORESOURCE_DMA_TYPEF:
984
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
985 986
		break;
	default:
987
		dma->type = ACPI_COMPATIBILITY;
988 989 990
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
991
	case IORESOURCE_DMA_8BIT:
992
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
993 994
		break;
	case IORESOURCE_DMA_8AND16BIT:
995
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
996 997
		break;
	default:
998
		dma->transfer = ACPI_TRANSFER_16;
999 1000
	}

1001 1002 1003
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
1004

B
Bjorn Helgaas 已提交
1005
	pnp_dbg(&dev->dev, "  encode dma %d "
1006 1007
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
1008 1009
}

1010 1011
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1012
			      struct resource *p)
L
Linus Torvalds 已提交
1013
{
1014 1015
	struct acpi_resource_io *io = &resource->data.io;

1016 1017
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
1018
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
1019 1020 1021 1022
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
1023
		io->address_length = resource_size(p);
1024 1025 1026 1027
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
1028

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

1033 1034
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1035
				    struct resource *p)
L
Linus Torvalds 已提交
1036
{
1037 1038
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

1039 1040
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
1041
		fixed_io->address_length = resource_size(p);
1042 1043 1044 1045
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
1046

B
Bjorn Helgaas 已提交
1047
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
1048
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
1049 1050
}

1051 1052
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1053
				 struct resource *p)
L
Linus Torvalds 已提交
1054
{
1055 1056
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

1057 1058 1059 1060 1061 1062 1063
	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;
1064
		memory24->address_length = resource_size(p);
1065 1066 1067 1068 1069
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
1070
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
1071 1072
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
1073
		memory24->write_protect);
L
Linus Torvalds 已提交
1074 1075
}

1076 1077
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1078
				 struct resource *p)
L
Linus Torvalds 已提交
1079
{
1080 1081
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

1082 1083 1084 1085 1086 1087
	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;
1088
		memory32->address_length = resource_size(p);
1089 1090 1091 1092
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
1093

B
Bjorn Helgaas 已提交
1094
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
1095 1096
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
1097
		memory32->write_protect);
L
Linus Torvalds 已提交
1098 1099
}

1100 1101
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
1102
				       struct resource *p)
L
Linus Torvalds 已提交
1103
{
1104 1105
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

1106 1107 1108 1109 1110
	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;
1111
		fixed_memory32->address_length = resource_size(p);
1112 1113 1114 1115
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
1116

B
Bjorn Helgaas 已提交
1117
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
1118 1119
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
1120
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
1121 1122
}

1123
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
1124 1125 1126
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
1127
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
1128
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
1129 1130
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
1131
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
1132
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
1133
		switch (resource->type) {
B
Bob Moore 已提交
1134
		case ACPI_RESOURCE_TYPE_IRQ:
1135
			pnpacpi_encode_irq(dev, resource,
1136
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
1137 1138 1139
			irq++;
			break;

B
Bob Moore 已提交
1140
		case ACPI_RESOURCE_TYPE_DMA:
1141
			pnpacpi_encode_dma(dev, resource,
1142
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
1143
			dma++;
L
Linus Torvalds 已提交
1144
			break;
B
Bob Moore 已提交
1145
		case ACPI_RESOURCE_TYPE_IO:
1146
			pnpacpi_encode_io(dev, resource,
1147
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1148
			port++;
L
Linus Torvalds 已提交
1149
			break;
B
Bob Moore 已提交
1150
		case ACPI_RESOURCE_TYPE_FIXED_IO:
1151
			pnpacpi_encode_fixed_io(dev, resource,
1152
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
1153
			port++;
L
Linus Torvalds 已提交
1154
			break;
B
Bob Moore 已提交
1155
		case ACPI_RESOURCE_TYPE_MEMORY24:
1156
			pnpacpi_encode_mem24(dev, resource,
1157
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1158
			mem++;
L
Linus Torvalds 已提交
1159
			break;
B
Bob Moore 已提交
1160
		case ACPI_RESOURCE_TYPE_MEMORY32:
1161
			pnpacpi_encode_mem32(dev, resource,
1162
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1163
			mem++;
L
Linus Torvalds 已提交
1164
			break;
B
Bob Moore 已提交
1165
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
1166
			pnpacpi_encode_fixed_mem32(dev, resource,
1167
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
1168
			mem++;
L
Linus Torvalds 已提交
1169
			break;
1170
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1171
			pnpacpi_encode_ext_irq(dev, resource,
1172
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
			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 已提交
1184
		default:	/* other type */
1185 1186
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
1187 1188
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
1189 1190
		resource++;
		i++;
L
Linus Torvalds 已提交
1191 1192 1193
	}
	return 0;
}