rsparser.c 25.9 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
#include "pnpacpi.h"

B
Bjorn Helgaas 已提交
31
static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering,
32
			     int *polarity, int *shareable)
L
Linus Torvalds 已提交
33
{
B
Bjorn Helgaas 已提交
34 35
	switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL |
			 IORESOURCE_IRQ_LOWEDGE  | IORESOURCE_IRQ_HIGHEDGE)) {
L
Linus Torvalds 已提交
36
	case IORESOURCE_IRQ_LOWLEVEL:
B
Bob Moore 已提交
37 38
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
39
		break;
B
Bjorn Helgaas 已提交
40
	case IORESOURCE_IRQ_HIGHLEVEL:
B
Bob Moore 已提交
41 42
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
43 44
		break;
	case IORESOURCE_IRQ_LOWEDGE:
B
Bob Moore 已提交
45 46
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
L
Linus Torvalds 已提交
47 48
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
B
Bob Moore 已提交
49 50
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
L
Linus Torvalds 已提交
51
		break;
B
Bjorn Helgaas 已提交
52 53 54 55 56 57
	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 已提交
58
	}
59 60 61 62 63

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

66 67
static int dma_flags(struct pnp_dev *dev, int type, int bus_master,
		     int transfer)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
	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;
89
		dev_err(&dev->dev, "invalid DMA type %d\n", type);
90 91 92 93 94 95 96 97 98 99 100 101 102 103
	}
	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;
104
		dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer);
105 106 107 108 109
	}

	return flags;
}

110 111 112
/*
 * Allocated Resources
 */
B
Bjorn Helgaas 已提交
113

114 115 116 117
static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r)
{
	if (!(r->flags & IORESOURCE_DISABLED))
		pcibios_penalize_isa_irq(r->start, 1);
118

119
	pnp_add_resource(dev, r);
L
Linus Torvalds 已提交
120 121
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
/*
 * 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);
	}
}

L
Linus Torvalds 已提交
177
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
178
					      void *data)
L
Linus Torvalds 已提交
179
{
180
	struct pnp_dev *dev = data;
181
	struct acpi_resource_dma *dma;
182
	struct acpi_resource_vendor_typed *vendor_typed;
183 184
	struct resource_win win = {{0}, 0};
	struct resource *r = &win.res;
185
	int i, flags;
L
Linus Torvalds 已提交
186

187 188 189
	if (acpi_dev_resource_address_space(res, &win)
	    || acpi_dev_resource_ext_address_space(res, &win)) {
		pnp_add_resource(dev, &win.res);
190 191 192
		return AE_OK;
	}

193 194 195 196 197
	r->flags = 0;
	if (acpi_dev_resource_interrupt(res, 0, r)) {
		pnpacpi_add_irqresource(dev, r);
		for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
			pnpacpi_add_irqresource(dev, r);
198

199
		if (i > 1) {
200 201 202 203 204
			/*
			 * 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.
			 */
205
			if (pnp_can_write(dev)) {
206 207 208 209 210
				dev_warn(&dev->dev, "multiple interrupts in "
					 "_CRS descriptor; configuration can't "
					 "be changed\n");
				dev->capabilities &= ~PNP_WRITE;
			}
L
Linus Torvalds 已提交
211
		}
212
		return AE_OK;
213
	} else if (r->flags & IORESOURCE_DISABLED) {
214 215 216
		pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
		return AE_OK;
	}
L
Linus Torvalds 已提交
217

218
	switch (res->type) {
219 220 221
	case ACPI_RESOURCE_TYPE_MEMORY24:
	case ACPI_RESOURCE_TYPE_MEMORY32:
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
222 223
		if (acpi_dev_resource_memory(res, r))
			pnp_add_resource(dev, r);
224 225 226
		break;
	case ACPI_RESOURCE_TYPE_IO:
	case ACPI_RESOURCE_TYPE_FIXED_IO:
227 228
		if (acpi_dev_resource_io(res, r))
			pnp_add_resource(dev, r);
229
		break;
B
Bob Moore 已提交
230
	case ACPI_RESOURCE_TYPE_DMA:
231
		dma = &res->data.dma;
232
		if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
233
			flags = dma_flags(dev, dma->type, dma->bus_master,
234
					  dma->transfer);
235 236 237
		else
			flags = IORESOURCE_DISABLED;
		pnp_add_dma_resource(dev, dma->channels[0], flags);
L
Linus Torvalds 已提交
238
		break;
239 240 241 242 243 244

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

	case ACPI_RESOURCE_TYPE_VENDOR:
245 246
		vendor_typed = &res->data.vendor_typed;
		pnpacpi_parse_allocated_vendor(dev, vendor_typed);
247 248 249 250 251 252
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
L
Linus Torvalds 已提交
253
		break;
254

L
Linus Torvalds 已提交
255
	default:
256 257
		dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
			 res->type);
L
Linus Torvalds 已提交
258 259
		return AE_ERROR;
	}
B
Bjorn Helgaas 已提交
260

L
Linus Torvalds 已提交
261 262 263
	return AE_OK;
}

264
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
L
Linus Torvalds 已提交
265
{
266 267
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
268
	acpi_status status;
269

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

272
	pnp_init_resources(dev);
L
Linus Torvalds 已提交
273

274 275 276 277 278 279 280 281 282
	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 已提交
283 284
}

285
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
286
					    unsigned int option_flags,
287
					    struct acpi_resource_dma *p)
L
Linus Torvalds 已提交
288 289
{
	int i;
290
	unsigned char map = 0, flags;
L
Linus Torvalds 已提交
291

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

295
	flags = dma_flags(dev, p->type, p->bus_master, p->transfer);
296
	pnp_register_dma_resource(dev, option_flags, map, flags);
L
Linus Torvalds 已提交
297 298
}

299
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
300
					    unsigned int option_flags,
301
					    struct acpi_resource_irq *p)
L
Linus Torvalds 已提交
302 303
{
	int i;
304
	pnp_irq_mask_t map;
305
	unsigned char flags;
L
Linus Torvalds 已提交
306

307
	bitmap_zero(map.bits, PNP_IRQ_NR);
B
Bjorn Helgaas 已提交
308
	for (i = 0; i < p->interrupt_count; i++)
L
Linus Torvalds 已提交
309
		if (p->interrupts[i])
310
			__set_bit(p->interrupts[i], map.bits);
L
Linus Torvalds 已提交
311

312
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
313
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
314 315
}

316
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
317
					unsigned int option_flags,
318
					struct acpi_resource_extended_irq *p)
L
Linus Torvalds 已提交
319 320
{
	int i;
321
	pnp_irq_mask_t map;
322
	unsigned char flags;
L
Linus Torvalds 已提交
323

324
	bitmap_zero(map.bits, PNP_IRQ_NR);
325 326 327 328 329 330 331 332 333 334
	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 已提交
335

336
	flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable);
337
	pnp_register_irq_resource(dev, option_flags, &map, flags);
L
Linus Torvalds 已提交
338 339
}

340
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
341
					     unsigned int option_flags,
342
					     struct acpi_resource_io *io)
L
Linus Torvalds 已提交
343
{
344
	unsigned char flags = 0;
L
Linus Torvalds 已提交
345

346
	if (io->io_decode == ACPI_DECODE_16)
347
		flags = IORESOURCE_IO_16BIT_ADDR;
348
	pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
349
				   io->alignment, io->address_length, flags);
L
Linus Torvalds 已提交
350 351
}

352
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
353
					unsigned int option_flags,
354
					struct acpi_resource_fixed_io *io)
L
Linus Torvalds 已提交
355
{
356
	pnp_register_port_resource(dev, option_flags, io->address, io->address,
357
				   0, io->address_length, IORESOURCE_IO_FIXED);
L
Linus Torvalds 已提交
358 359
}

360
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
361
					      unsigned int option_flags,
362
					      struct acpi_resource_memory24 *p)
L
Linus Torvalds 已提交
363
{
364
	unsigned char flags = 0;
L
Linus Torvalds 已提交
365

366
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
367
		flags = IORESOURCE_MEM_WRITEABLE;
368
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
369
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
370 371
}

372
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
373
					      unsigned int option_flags,
374
					      struct acpi_resource_memory32 *p)
L
Linus Torvalds 已提交
375
{
376
	unsigned char flags = 0;
L
Linus Torvalds 已提交
377

378
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
379
		flags = IORESOURCE_MEM_WRITEABLE;
380
	pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
381
				  p->alignment, p->address_length, flags);
L
Linus Torvalds 已提交
382 383
}

384
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
385
					unsigned int option_flags,
386
					struct acpi_resource_fixed_memory32 *p)
L
Linus Torvalds 已提交
387
{
388
	unsigned char flags = 0;
L
Linus Torvalds 已提交
389

390
	if (p->write_protect == ACPI_READ_WRITE_MEMORY)
391
		flags = IORESOURCE_MEM_WRITEABLE;
392
	pnp_register_mem_resource(dev, option_flags, p->address, p->address,
393
				  0, p->address_length, flags);
L
Linus Torvalds 已提交
394 395
}

396
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
397
						unsigned int option_flags,
398
						struct acpi_resource *r)
399 400 401
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
402
	unsigned char flags = 0;
403 404

	status = acpi_resource_to_address64(r, p);
405 406
	if (ACPI_FAILURE(status)) {
		dev_warn(&dev->dev, "can't convert resource type %d\n",
B
Bjorn Helgaas 已提交
407
			 r->type);
408 409 410 411
		return;
	}

	if (p->resource_type == ACPI_MEMORY_RANGE) {
412
		if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
413
			flags = IORESOURCE_MEM_WRITEABLE;
414 415
		pnp_register_mem_resource(dev, option_flags, p->address.minimum,
					  p->address.minimum, 0, p->address.address_length,
416
					  flags);
417
	} else if (p->resource_type == ACPI_IO_RANGE)
418 419
		pnp_register_port_resource(dev, option_flags, p->address.minimum,
					   p->address.minimum, 0, p->address.address_length,
420
					   IORESOURCE_IO_FIXED);
421 422
}

423 424 425 426 427 428 429 430 431
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)
432
			flags = IORESOURCE_MEM_WRITEABLE;
433 434
		pnp_register_mem_resource(dev, option_flags, p->address.minimum,
					  p->address.minimum, 0, p->address.address_length,
435 436
					  flags);
	} else if (p->resource_type == ACPI_IO_RANGE)
437 438
		pnp_register_port_resource(dev, option_flags, p->address.minimum,
					   p->address.minimum, 0, p->address.address_length,
439
					   IORESOURCE_IO_FIXED);
440 441
}

L
Linus Torvalds 已提交
442 443
struct acpipnp_parse_option_s {
	struct pnp_dev *dev;
444
	unsigned int option_flags;
L
Linus Torvalds 已提交
445 446
};

447 448
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
						  void *data)
L
Linus Torvalds 已提交
449
{
450
	int priority;
451
	struct acpipnp_parse_option_s *parse_data = data;
L
Linus Torvalds 已提交
452
	struct pnp_dev *dev = parse_data->dev;
453
	unsigned int option_flags = parse_data->option_flags;
L
Linus Torvalds 已提交
454

455
	switch (res->type) {
B
Bjorn Helgaas 已提交
456
	case ACPI_RESOURCE_TYPE_IRQ:
457
		pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
B
Bjorn Helgaas 已提交
458
		break;
459

B
Bjorn Helgaas 已提交
460
	case ACPI_RESOURCE_TYPE_DMA:
461
		pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
B
Bjorn Helgaas 已提交
462
		break;
463

B
Bjorn Helgaas 已提交
464 465 466 467
	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 已提交
468
			break;
469

B
Bjorn Helgaas 已提交
470 471
		case ACPI_ACCEPTABLE_CONFIGURATION:
			priority = PNP_RES_PRIORITY_ACCEPTABLE;
M
Matthieu Castet 已提交
472
			break;
473

B
Bjorn Helgaas 已提交
474 475
		case ACPI_SUB_OPTIMAL_CONFIGURATION:
			priority = PNP_RES_PRIORITY_FUNCTIONAL;
476
			break;
B
Bjorn Helgaas 已提交
477 478
		default:
			priority = PNP_RES_PRIORITY_INVALID;
479
			break;
B
Bjorn Helgaas 已提交
480
		}
481
		parse_data->option_flags = pnp_new_dependent_set(dev, priority);
B
Bjorn Helgaas 已提交
482
		break;
483

B
Bjorn Helgaas 已提交
484
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
485
		parse_data->option_flags = 0;
B
Bjorn Helgaas 已提交
486
		break;
487

B
Bjorn Helgaas 已提交
488
	case ACPI_RESOURCE_TYPE_IO:
489
		pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
B
Bjorn Helgaas 已提交
490
		break;
491

B
Bjorn Helgaas 已提交
492
	case ACPI_RESOURCE_TYPE_FIXED_IO:
493
		pnpacpi_parse_fixed_port_option(dev, option_flags,
494
					        &res->data.fixed_io);
B
Bjorn Helgaas 已提交
495
		break;
496

B
Bjorn Helgaas 已提交
497 498 499
	case ACPI_RESOURCE_TYPE_VENDOR:
	case ACPI_RESOURCE_TYPE_END_TAG:
		break;
500

B
Bjorn Helgaas 已提交
501
	case ACPI_RESOURCE_TYPE_MEMORY24:
502 503
		pnpacpi_parse_mem24_option(dev, option_flags,
					   &res->data.memory24);
B
Bjorn Helgaas 已提交
504
		break;
505

B
Bjorn Helgaas 已提交
506
	case ACPI_RESOURCE_TYPE_MEMORY32:
507 508
		pnpacpi_parse_mem32_option(dev, option_flags,
					   &res->data.memory32);
B
Bjorn Helgaas 已提交
509
		break;
510

B
Bjorn Helgaas 已提交
511
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
512
		pnpacpi_parse_fixed_mem32_option(dev, option_flags,
B
Bjorn Helgaas 已提交
513 514
						 &res->data.fixed_memory32);
		break;
515

B
Bjorn Helgaas 已提交
516 517 518
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
519
		pnpacpi_parse_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
520
		break;
521

B
Bjorn Helgaas 已提交
522
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
523
		pnpacpi_parse_ext_address_option(dev, option_flags, res);
B
Bjorn Helgaas 已提交
524 525 526
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
527
		pnpacpi_parse_ext_irq_option(dev, option_flags,
528
					     &res->data.extended_irq);
B
Bjorn Helgaas 已提交
529 530 531 532 533 534
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
535 536
		dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
			 res->type);
B
Bjorn Helgaas 已提交
537
		return AE_ERROR;
L
Linus Torvalds 已提交
538
	}
B
Bjorn Helgaas 已提交
539

L
Linus Torvalds 已提交
540 541 542
	return AE_OK;
}

543
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
L
Linus Torvalds 已提交
544
{
545 546
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
547 548 549
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

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

L
Linus Torvalds 已提交
552
	parse_data.dev = dev;
553 554
	parse_data.option_flags = 0;

B
Bob Moore 已提交
555
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
B
Bjorn Helgaas 已提交
556
				     pnpacpi_option_resource, &parse_data);
L
Linus Torvalds 已提交
557

558 559 560 561 562 563
	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 已提交
564 565
}

566
static int pnpacpi_supported_resource(struct acpi_resource *res)
L
Linus Torvalds 已提交
567
{
568
	switch (res->type) {
B
Bob Moore 已提交
569 570 571 572 573 574 575 576 577 578
	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:
579
	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
580
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
581
		return 1;
L
Linus Torvalds 已提交
582
	}
583 584 585 586 587 588 589
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
B
Bjorn Helgaas 已提交
590
					   void *data)
591
{
592
	int *res_cnt = data;
593 594 595

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
L
Linus Torvalds 已提交
596 597 598
	return AE_OK;
}

B
Bjorn Helgaas 已提交
599
static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
L
Linus Torvalds 已提交
600
{
601
	struct acpi_resource **resource = data;
602 603

	if (pnpacpi_supported_resource(res)) {
604
		(*resource)->type = res->type;
605
		(*resource)->length = sizeof(struct acpi_resource);
606 607 608
		if (res->type == ACPI_RESOURCE_TYPE_IRQ)
			(*resource)->data.irq.descriptor_length =
					res->data.irq.descriptor_length;
L
Linus Torvalds 已提交
609 610 611 612 613 614
		(*resource)++;
	}

	return AE_OK;
}

615
int pnpacpi_build_resource_template(struct pnp_dev *dev,
B
Bjorn Helgaas 已提交
616
				    struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
617
{
618 619
	struct acpi_device *acpi_dev = dev->data;
	acpi_handle handle = acpi_dev->handle;
L
Linus Torvalds 已提交
620 621 622 623
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

B
Bob Moore 已提交
624
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
625
				     pnpacpi_count_resources, &res_cnt);
L
Linus Torvalds 已提交
626
	if (ACPI_FAILURE(status)) {
627
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
628 629 630 631 632
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
633
	buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
L
Linus Torvalds 已提交
634 635
	if (!buffer->pointer)
		return -ENOMEM;
636

L
Linus Torvalds 已提交
637
	resource = (struct acpi_resource *)buffer->pointer;
B
Bob Moore 已提交
638
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
B
Bjorn Helgaas 已提交
639
				     pnpacpi_type_resources, &resource);
L
Linus Torvalds 已提交
640 641
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
642
		dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
L
Linus Torvalds 已提交
643 644 645
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
B
Bob Moore 已提交
646
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;
647
	resource->length = sizeof(struct acpi_resource);
L
Linus Torvalds 已提交
648 649 650 651

	return 0;
}

652 653
static void pnpacpi_encode_irq(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
654
			       struct resource *p)
L
Linus Torvalds 已提交
655
{
656
	struct acpi_resource_irq *irq = &resource->data.irq;
657
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
658

659 660
	if (!pnp_resource_enabled(p)) {
		irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
661
		pnp_dbg(&dev->dev, "  encode irq (%s)\n",
662 663 664 665
			p ? "disabled" : "missing");
		return;
	}

666
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
667 668
	irq->triggering = triggering;
	irq->polarity = polarity;
669
	irq->sharable = shareable;
670 671
	irq->interrupt_count = 1;
	irq->interrupts[0] = p->start;
672

B
Bjorn Helgaas 已提交
673
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s (%d-byte descriptor)\n",
674
		(int) p->start,
675 676
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
677 678
		irq->sharable == ACPI_SHARED ? "shared" : "exclusive",
		irq->descriptor_length);
L
Linus Torvalds 已提交
679 680
}

681 682
static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
				   struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
683
				   struct resource *p)
L
Linus Torvalds 已提交
684
{
685
	struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
686
	int triggering, polarity, shareable;
B
Bjorn Helgaas 已提交
687

688 689
	if (!pnp_resource_enabled(p)) {
		extended_irq->interrupt_count = 0;
B
Bjorn Helgaas 已提交
690
		pnp_dbg(&dev->dev, "  encode extended irq (%s)\n",
691 692 693 694
			p ? "disabled" : "missing");
		return;
	}

695
	decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable);
696 697 698
	extended_irq->producer_consumer = ACPI_CONSUMER;
	extended_irq->triggering = triggering;
	extended_irq->polarity = polarity;
699
	extended_irq->sharable = shareable;
700 701
	extended_irq->interrupt_count = 1;
	extended_irq->interrupts[0] = p->start;
702

B
Bjorn Helgaas 已提交
703
	pnp_dbg(&dev->dev, "  encode irq %d %s %s %s\n", (int) p->start,
704 705 706
		triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
		polarity == ACPI_ACTIVE_LOW ? "low" : "high",
		extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
L
Linus Torvalds 已提交
707 708
}

709 710
static void pnpacpi_encode_dma(struct pnp_dev *dev,
			       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
711
			       struct resource *p)
L
Linus Torvalds 已提交
712
{
713 714
	struct acpi_resource_dma *dma = &resource->data.dma;

715 716
	if (!pnp_resource_enabled(p)) {
		dma->channel_count = 0;
B
Bjorn Helgaas 已提交
717
		pnp_dbg(&dev->dev, "  encode dma (%s)\n",
718 719 720 721
			p ? "disabled" : "missing");
		return;
	}

L
Linus Torvalds 已提交
722
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
723
	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
B
Bjorn Helgaas 已提交
724
	case IORESOURCE_DMA_TYPEA:
725
		dma->type = ACPI_TYPE_A;
B
Bjorn Helgaas 已提交
726 727
		break;
	case IORESOURCE_DMA_TYPEB:
728
		dma->type = ACPI_TYPE_B;
B
Bjorn Helgaas 已提交
729 730
		break;
	case IORESOURCE_DMA_TYPEF:
731
		dma->type = ACPI_TYPE_F;
B
Bjorn Helgaas 已提交
732 733
		break;
	default:
734
		dma->type = ACPI_COMPATIBILITY;
735 736 737
	}

	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
B
Bjorn Helgaas 已提交
738
	case IORESOURCE_DMA_8BIT:
739
		dma->transfer = ACPI_TRANSFER_8;
B
Bjorn Helgaas 已提交
740 741
		break;
	case IORESOURCE_DMA_8AND16BIT:
742
		dma->transfer = ACPI_TRANSFER_8_16;
B
Bjorn Helgaas 已提交
743 744
		break;
	default:
745
		dma->transfer = ACPI_TRANSFER_16;
746 747
	}

748 749 750
	dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
	dma->channel_count = 1;
	dma->channels[0] = p->start;
751

B
Bjorn Helgaas 已提交
752
	pnp_dbg(&dev->dev, "  encode dma %d "
753 754
		"type %#x transfer %#x master %d\n",
		(int) p->start, dma->type, dma->transfer, dma->bus_master);
L
Linus Torvalds 已提交
755 756
}

757 758
static void pnpacpi_encode_io(struct pnp_dev *dev,
			      struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
759
			      struct resource *p)
L
Linus Torvalds 已提交
760
{
761 762
	struct acpi_resource_io *io = &resource->data.io;

763 764
	if (pnp_resource_enabled(p)) {
		/* Note: pnp_assign_port copies pnp_port->flags into p->flags */
765
		io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ?
766 767 768 769
		    ACPI_DECODE_16 : ACPI_DECODE_10;
		io->minimum = p->start;
		io->maximum = p->end;
		io->alignment = 0;	/* Correct? */
770
		io->address_length = resource_size(p);
771 772 773 774
	} else {
		io->minimum = 0;
		io->address_length = 0;
	}
775

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

780 781
static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
				    struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
782
				    struct resource *p)
L
Linus Torvalds 已提交
783
{
784 785
	struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;

786 787
	if (pnp_resource_enabled(p)) {
		fixed_io->address = p->start;
788
		fixed_io->address_length = resource_size(p);
789 790 791 792
	} else {
		fixed_io->address = 0;
		fixed_io->address_length = 0;
	}
793

B
Bjorn Helgaas 已提交
794
	pnp_dbg(&dev->dev, "  encode fixed_io %#x-%#x\n", fixed_io->address,
795
		fixed_io->address + fixed_io->address_length - 1);
L
Linus Torvalds 已提交
796 797
}

798 799
static void pnpacpi_encode_mem24(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
800
				 struct resource *p)
L
Linus Torvalds 已提交
801
{
802 803
	struct acpi_resource_memory24 *memory24 = &resource->data.memory24;

804 805 806 807 808 809 810
	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;
811
		memory24->address_length = resource_size(p);
812 813 814 815 816
	} else {
		memory24->minimum = 0;
		memory24->address_length = 0;
	}

B
Bjorn Helgaas 已提交
817
	pnp_dbg(&dev->dev, "  encode mem24 %#x-%#x write_protect %#x\n",
818 819
		memory24->minimum,
		memory24->minimum + memory24->address_length - 1,
820
		memory24->write_protect);
L
Linus Torvalds 已提交
821 822
}

823 824
static void pnpacpi_encode_mem32(struct pnp_dev *dev,
				 struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
825
				 struct resource *p)
L
Linus Torvalds 已提交
826
{
827 828
	struct acpi_resource_memory32 *memory32 = &resource->data.memory32;

829 830 831 832 833 834
	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;
835
		memory32->address_length = resource_size(p);
836 837 838 839
	} else {
		memory32->minimum = 0;
		memory32->alignment = 0;
	}
840

B
Bjorn Helgaas 已提交
841
	pnp_dbg(&dev->dev, "  encode mem32 %#x-%#x write_protect %#x\n",
842 843
		memory32->minimum,
		memory32->minimum + memory32->address_length - 1,
844
		memory32->write_protect);
L
Linus Torvalds 已提交
845 846
}

847 848
static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
				       struct acpi_resource *resource,
B
Bjorn Helgaas 已提交
849
				       struct resource *p)
L
Linus Torvalds 已提交
850
{
851 852
	struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;

853 854 855 856 857
	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;
858
		fixed_memory32->address_length = resource_size(p);
859 860 861 862
	} else {
		fixed_memory32->address = 0;
		fixed_memory32->address_length = 0;
	}
863

B
Bjorn Helgaas 已提交
864
	pnp_dbg(&dev->dev, "  encode fixed_mem32 %#x-%#x write_protect %#x\n",
865 866
		fixed_memory32->address,
		fixed_memory32->address + fixed_memory32->address_length - 1,
867
		fixed_memory32->write_protect);
L
Linus Torvalds 已提交
868 869
}

870
int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
L
Linus Torvalds 已提交
871 872 873
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
B
Bjorn Helgaas 已提交
874
	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
875
	struct acpi_resource *resource = buffer->pointer;
L
Linus Torvalds 已提交
876 877
	int port = 0, irq = 0, dma = 0, mem = 0;

B
Bjorn Helgaas 已提交
878
	pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt);
L
Linus Torvalds 已提交
879
	while (i < res_cnt) {
B
Bjorn Helgaas 已提交
880
		switch (resource->type) {
B
Bob Moore 已提交
881
		case ACPI_RESOURCE_TYPE_IRQ:
882
			pnpacpi_encode_irq(dev, resource,
883
			       pnp_get_resource(dev, IORESOURCE_IRQ, irq));
L
Linus Torvalds 已提交
884 885 886
			irq++;
			break;

B
Bob Moore 已提交
887
		case ACPI_RESOURCE_TYPE_DMA:
888
			pnpacpi_encode_dma(dev, resource,
889
				pnp_get_resource(dev, IORESOURCE_DMA, dma));
B
Bjorn Helgaas 已提交
890
			dma++;
L
Linus Torvalds 已提交
891
			break;
B
Bob Moore 已提交
892
		case ACPI_RESOURCE_TYPE_IO:
893
			pnpacpi_encode_io(dev, resource,
894
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
895
			port++;
L
Linus Torvalds 已提交
896
			break;
B
Bob Moore 已提交
897
		case ACPI_RESOURCE_TYPE_FIXED_IO:
898
			pnpacpi_encode_fixed_io(dev, resource,
899
				pnp_get_resource(dev, IORESOURCE_IO, port));
B
Bjorn Helgaas 已提交
900
			port++;
L
Linus Torvalds 已提交
901
			break;
B
Bob Moore 已提交
902
		case ACPI_RESOURCE_TYPE_MEMORY24:
903
			pnpacpi_encode_mem24(dev, resource,
904
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
905
			mem++;
L
Linus Torvalds 已提交
906
			break;
B
Bob Moore 已提交
907
		case ACPI_RESOURCE_TYPE_MEMORY32:
908
			pnpacpi_encode_mem32(dev, resource,
909
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
910
			mem++;
L
Linus Torvalds 已提交
911
			break;
B
Bob Moore 已提交
912
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
913
			pnpacpi_encode_fixed_mem32(dev, resource,
914
				pnp_get_resource(dev, IORESOURCE_MEM, mem));
B
Bjorn Helgaas 已提交
915
			mem++;
L
Linus Torvalds 已提交
916
			break;
917
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
918
			pnpacpi_encode_ext_irq(dev, resource,
919
				pnp_get_resource(dev, IORESOURCE_IRQ, irq));
920 921 922 923 924 925 926 927 928 929 930
			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 已提交
931
		default:	/* other type */
932 933
			dev_warn(&dev->dev, "can't encode unknown resource "
				 "type %d\n", resource->type);
L
Linus Torvalds 已提交
934 935
			return -EINVAL;
		}
B
Bjorn Helgaas 已提交
936 937
		resource++;
		i++;
L
Linus Torvalds 已提交
938 939 940
	}
	return 0;
}