rsparser.c 32.0 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 27
#include <linux/pnp.h>
#include "../base.h"
L
Linus Torvalds 已提交
28 29 30 31 32 33 34 35 36 37 38
#include "pnpacpi.h"

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

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

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

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

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

B
Bjorn Helgaas 已提交
61
static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
62
			     int *polarity, int *shareable)
L
Linus Torvalds 已提交
63
{
B
Bjorn Helgaas 已提交
64 65
	switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
			 IORESOURCE_IRQ_LOWEDGE  | IORESOURCE_IRQ_HIGHEDGE)) {
L
Linus Torvalds 已提交
66
	case IORESOURCE_IRQ_LOWLEVEL:
B
Bob Moore 已提交
67 68
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
69
		break;
B
Bjorn Helgaas 已提交
70
	case IORESOURCE_IRQ_HIGHLEVEL:
B
Bob Moore 已提交
71 72
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
73 74
		break;
	case IORESOURCE_IRQ_LOWEDGE:
B
Bob Moore 已提交
75 76
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
77 78
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
B
Bob Moore 已提交
79 80
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
81
		break;
B
Bjorn Helgaas 已提交
82 83 84 85 86 87
	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 已提交
88
	}
89 90 91 92 93

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

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

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

108 109 110 111 112 113 114 115 116 117
	/*
	 * 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) {
118
			dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
119 120 121 122 123 124
				gsi, t ? "edge":"level", p ? "low":"high");
			triggering = t;
			polarity = p;
		}
	}

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

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

135 136
static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
		     int transfer)
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
{
	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;
158
		dev_err(&dev->dev, "invalid DMA type %d\n", type);
159 160 161 162 163 164 165 166 167 168 169 170 171 172
	}
	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;
173
		dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
174 175 176 177 178
	}

	return flags;
}

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

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

	pnp_add_io_resource(dev, start, end, flags);
L
Linus Torvalds 已提交
194 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
/*
 * 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);
	}
}

251
static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
252
						u64 start, u64 len,
B
Bjorn Helgaas 已提交
253
						int write_protect, int window)
L
Linus Torvalds 已提交
254
{
255 256 257 258 259 260 261
	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 已提交
262 263
	if (window)
		flags |= IORESOURCE_WINDOW;
264 265

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

B
Bjorn Helgaas 已提交
268 269 270 271 272 273 274 275
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);
}

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

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

B
Bjorn Helgaas 已提交
290
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
291

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

306 307 308 309
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 已提交
310
	int window;
311

B
Bjorn Helgaas 已提交
312
	window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
313 314 315 316

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

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

343
	switch (res->type) {
B
Bob Moore 已提交
344
	case ACPI_RESOURCE_TYPE_IRQ:
345 346 347 348
		/*
		 * Per spec, only one interrupt per descriptor is allowed in
		 * _CRS, but some firmware violates this, so parse them all.
		 */
349
		irq = &res->data.irq;
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
		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 已提交
372 373 374
		}
		break;

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

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

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

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

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

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

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

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

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

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
		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;
			}
470 471 472 473
		}
		break;

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

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

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

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

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

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

495 496 497 498 499 500 501 502 503
	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 已提交
504 505
}

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

B
Bob Moore 已提交
513
	if (p->channel_count == 0)
L
Linus Torvalds 已提交
514 515
		return;

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

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

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

B
Bob Moore 已提交
531
	if (p->interrupt_count == 0)
L
Linus Torvalds 已提交
532 533
		return;

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

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

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

B
Bob Moore 已提交
551
	if (p->interrupt_count == 0)
L
Linus Torvalds 已提交
552 553
		return;

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

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

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

B
Bob Moore 已提交
576
	if (io->address_length == 0)
L
Linus Torvalds 已提交
577
		return;
578 579 580

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

585
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
586
					unsigned int option_flags,
587
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
588
{
B
Bob Moore 已提交
589
	if (io->address_length == 0)
L
Linus Torvalds 已提交
590
		return;
591

592 593
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
594 595
}

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

B
Bob Moore 已提交
602
	if (p->address_length == 0)
L
Linus Torvalds 已提交
603 604
		return;

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

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

B
Bob Moore 已提交
617
	if (p->address_length == 0)
L
Linus Torvalds 已提交
618 619
		return;

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

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

B
Bob Moore 已提交
632
	if (p->address_length == 0)
L
Linus Torvalds 已提交
633 634
		return;

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

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

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

	if (p->address_length == 0)
		return;

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

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
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)
		return;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
			flags = IORESOURCE_MEM_WRITEABLE;
		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,
					   IORESOURCE_IO_FIXED);
}

L
Linus Torvalds 已提交
693 694
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
695
	unsigned int option_flags;
L
Linus Torvalds 已提交
696 697
};

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

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

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

B
Bjorn Helgaas 已提交
715 716 717 718
	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 已提交
719
			break;
720

B
Bjorn Helgaas 已提交
721 722
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
723
			break;
724

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

B
Bjorn Helgaas 已提交
735
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
736
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
737
		break;
738

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

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

B
Bjorn Helgaas 已提交
748 749 750
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
751

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

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

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

B
Bjorn Helgaas 已提交
767 768 769
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
770
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
771
		break;
772

B
Bjorn Helgaas 已提交
773
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
774
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
775 776 777
		break;

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

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

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

L
Linus Torvalds 已提交
791 792 793
	return AE_OK;
}

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

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

L
Linus Torvalds 已提交
803
	parse_data.dev = dev;
804 805
	parse_data.option_flags = 0;

B
Bob Moore 已提交
806
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
807
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
808

809 810 811 812 813 814
	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 已提交
815 816
}

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

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

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
847 848 849
	return AE_OK;
}

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

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

	return AE_OK;
}

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

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

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

	return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

998 999 1000
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
1001

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

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

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

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

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

1036 1037 1038 1039 1040 1041 1042
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
		fixed_io->address_length = p->end - p->start + 1;
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
1043

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

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

1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	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;
		memory24->address_length = p->end - p->start + 1;
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

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

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

1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
	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;
		memory32->address_length = p->end - p->start + 1;
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
1090

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

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

1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
	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;
		fixed_memory32->address_length = p->end - p->start + 1;
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
1113

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

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

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

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