Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f32ca31 authored by Bjorn Helgaas's avatar Bjorn Helgaas Committed by Andi Kleen
Browse files

PNP: convert resource options to single linked list



ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of
a device, i.e., the possibilities an OS bus driver has when it assigns
I/O port, MMIO, and other resources to the device.

PNP used to maintain this "possible resource setting" information in
one independent option structure and a list of dependent option
structures for each device.  Each of these option structures had lists
of I/O, memory, IRQ, and DMA resources, for example:

  dev
    independent options
      ind-io0  -> ind-io1  ...
      ind-mem0 -> ind-mem1 ...
      ...
    dependent option set 0
      dep0-io0  -> dep0-io1  ...
      dep0-mem0 -> dep0-mem1 ...
      ...
    dependent option set 1
      dep1-io0  -> dep1-io1  ...
      dep1-mem0 -> dep1-mem1 ...
      ...
    ...

This data structure was designed for ISAPNP, where the OS configures
device resource settings by writing directly to configuration
registers.  The OS can write the registers in arbitrary order much
like it writes PCI BARs.

However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces
that perform device configuration, and it is important to pass the
desired settings to those interfaces in the correct order.  The OS
learns the correct order by using firmware interfaces that return the
"current resource settings" and "possible resource settings," but the
option structures above doesn't store the ordering information.

This patch replaces the independent and dependent lists with a single
list of options.  For example, a device might have possible resource
settings like this:

  dev
    options
      ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ...

All the possible settings are in the same list, in the order they
come from the firmware "possible resource settings" list.  Each entry
is tagged with an independent/dependent flag.  Dependent entries also
have a "set number" and an optional priority value.  All dependent
entries must be assigned from the same set.  For example, the OS can
use all the entries from dependent set 0, or all the entries from
dependent set 1, but it cannot mix entries from set 0 with entries
from set 1.

Prior to this patch PNP didn't keep track of the order of this list,
and it assigned all independent options first, then all dependent
ones.  Using the example above, that resulted in a "desired
configuration" list like this:

  ind->io0 -> ind->io1 -> depN-io0 ...

instead of the list the firmware expects, which looks like this:

  ind->io0 -> depN-io0 -> ind-io1 ...

Signed-off-by: default avatarBjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Acked-by: default avatarRene Herman <rene.herman@gmail.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent bbe413b4
Loading
Loading
Loading
Loading
+70 −23
Original line number Diff line number Diff line
/*
 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
 */

extern spinlock_t pnp_lock;
void *pnp_alloc(long size);

@@ -25,8 +30,6 @@ struct pnp_port {
	resource_size_t align;	/* align boundary */
	resource_size_t size;	/* size of range */
	unsigned char flags;	/* port flags */
	unsigned char pad;	/* pad */
	struct pnp_port *next;	/* next port */
};

#define PNP_IRQ_NR 256
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t;
struct pnp_irq {
	pnp_irq_mask_t map;	/* bitmap for IRQ lines */
	unsigned char flags;	/* IRQ flags */
	unsigned char pad;	/* pad */
	struct pnp_irq *next;	/* next IRQ */
};

struct pnp_dma {
	unsigned char map;	/* bitmask for DMA channels */
	unsigned char flags;	/* DMA flags */
	struct pnp_dma *next;	/* next port */
};

struct pnp_mem {
@@ -51,44 +51,91 @@ struct pnp_mem {
	resource_size_t align;	/* align boundary */
	resource_size_t size;	/* size of range */
	unsigned char flags;	/* memory flags */
	unsigned char pad;	/* pad */
	struct pnp_mem *next;	/* next memory resource */
};

#define PNP_OPTION_DEPENDENT		0x80000000
#define PNP_OPTION_SET_MASK		0xffff
#define PNP_OPTION_SET_SHIFT		12
#define PNP_OPTION_PRIORITY_MASK	0xfff
#define PNP_OPTION_PRIORITY_SHIFT	0

#define PNP_RES_PRIORITY_PREFERRED	0
#define PNP_RES_PRIORITY_ACCEPTABLE	1
#define PNP_RES_PRIORITY_FUNCTIONAL	2
#define PNP_RES_PRIORITY_INVALID	65535
#define PNP_RES_PRIORITY_INVALID	PNP_OPTION_PRIORITY_MASK

struct pnp_option {
	unsigned short priority;	/* priority */
	struct pnp_port *port;		/* first port */
	struct pnp_irq *irq;		/* first IRQ */
	struct pnp_dma *dma;		/* first DMA */
	struct pnp_mem *mem;		/* first memory resource */
	struct pnp_option *next;	/* used to chain dependent resources */
	struct list_head list;
	unsigned int flags;	/* independent/dependent, set, priority */

	unsigned long type;	/* IORESOURCE_{IO,MEM,IRQ,DMA} */
	union {
		struct pnp_port port;
		struct pnp_irq irq;
		struct pnp_dma dma;
		struct pnp_mem mem;
	} u;
};

struct pnp_option *pnp_build_option(int priority);
struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
						 int priority);
int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
			      pnp_irq_mask_t *map, unsigned char flags);
int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
			      unsigned char map, unsigned char flags);
int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
			       resource_size_t min, resource_size_t max,
			       resource_size_t align, resource_size_t size,
			       unsigned char flags);
int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
			      resource_size_t min, resource_size_t max,
			      resource_size_t align, resource_size_t size,
			      unsigned char flags);

static inline int pnp_option_is_dependent(struct pnp_option *option)
{
	return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0;
}

static inline unsigned int pnp_option_set(struct pnp_option *option)
{
	return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK;
}

static inline unsigned int pnp_option_priority(struct pnp_option *option)
{
	return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) &
	    PNP_OPTION_PRIORITY_MASK;
}

static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev,
						 int priority)
{
	unsigned int flags;

	if (priority > PNP_RES_PRIORITY_FUNCTIONAL) {
		dev_warn(&dev->dev, "invalid dependent option priority %d "
			 "clipped to %d", priority,
			 PNP_RES_PRIORITY_INVALID);
		priority = PNP_RES_PRIORITY_INVALID;
	}

	flags = PNP_OPTION_DEPENDENT |
	    ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) <<
		PNP_OPTION_SET_SHIFT) |
	    ((priority & PNP_OPTION_PRIORITY_MASK) <<
		PNP_OPTION_PRIORITY_SHIFT);

	dev->num_dependent_sets++;

	return flags;
}

char *pnp_option_priority_name(struct pnp_option *option);
void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option);

void pnp_init_resources(struct pnp_dev *dev);

void pnp_fixup_device(struct pnp_dev *dev);
void pnp_free_option(struct pnp_option *option);
void pnp_free_options(struct pnp_dev *dev);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);

+2 −2
Original line number Diff line number Diff line
@@ -118,10 +118,9 @@ static void pnp_release_device(struct device *dmdev)
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);

	pnp_free_option(dev->independent);
	pnp_free_option(dev->dependent);
	pnp_free_ids(dev);
	pnp_free_resources(dev);
	pnp_free_options(dev);
	kfree(dev);
}

@@ -135,6 +134,7 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid
		return NULL;

	INIT_LIST_HEAD(&dev->resources);
	INIT_LIST_HEAD(&dev->options);
	dev->protocol = protocol;
	dev->number = id;
	dev->dma_mask = DMA_24BIT_MASK;
+35 −40
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
 *
 * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
 * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
 */

#include <linux/pnp.h>
@@ -184,39 +186,22 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
}

static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
			     struct pnp_option *option, int dep)
			     struct pnp_option *option)
{
	char *s;
	struct pnp_port *port;
	struct pnp_irq *irq;
	struct pnp_dma *dma;
	struct pnp_mem *mem;

	if (dep) {
		switch (option->priority) {
		case PNP_RES_PRIORITY_PREFERRED:
			s = "preferred";
	switch (option->type) {
	case IORESOURCE_IO:
		pnp_print_port(buffer, space, &option->u.port);
		break;
		case PNP_RES_PRIORITY_ACCEPTABLE:
			s = "acceptable";
	case IORESOURCE_MEM:
		pnp_print_mem(buffer, space, &option->u.mem);
		break;
		case PNP_RES_PRIORITY_FUNCTIONAL:
			s = "functional";
	case IORESOURCE_IRQ:
		pnp_print_irq(buffer, space, &option->u.irq);
		break;
	case IORESOURCE_DMA:
		pnp_print_dma(buffer, space, &option->u.dma);
		break;
		default:
			s = "invalid";
		}
		pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
	}

	for (port = option->port; port; port = port->next)
		pnp_print_port(buffer, space, port);
	for (irq = option->irq; irq; irq = irq->next)
		pnp_print_irq(buffer, space, irq);
	for (dma = option->dma; dma; dma = dma->next)
		pnp_print_dma(buffer, space, dma);
	for (mem = option->mem; mem; mem = mem->next)
		pnp_print_mem(buffer, space, mem);
}

static ssize_t pnp_show_options(struct device *dmdev,
@@ -224,9 +209,9 @@ static ssize_t pnp_show_options(struct device *dmdev,
{
	struct pnp_dev *dev = to_pnp_dev(dmdev);
	pnp_info_buffer_t *buffer;
	struct pnp_option *independent = dev->independent;
	struct pnp_option *dependent = dev->dependent;
	int ret, dep = 1;
	struct pnp_option *option;
	int ret, dep = 0, set = 0;
	char *indent;

	buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
	if (!buffer)
@@ -235,14 +220,24 @@ static ssize_t pnp_show_options(struct device *dmdev,
	buffer->len = PAGE_SIZE;
	buffer->buffer = buf;
	buffer->curr = buffer->buffer;
	if (independent)
		pnp_print_option(buffer, "", independent, 0);

	while (dependent) {
		pnp_print_option(buffer, "   ", dependent, dep);
		dependent = dependent->next;
		dep++;
	list_for_each_entry(option, &dev->options, list) {
		if (pnp_option_is_dependent(option)) {
			indent = "  ";
			if (!dep || pnp_option_set(option) != set) {
				set = pnp_option_set(option);
				dep = 1;
				pnp_printf(buffer, "Dependent: %02i - "
					   "Priority %s\n", set,
					   pnp_option_priority_name(option));
			}
		} else {
			dep = 0;
			indent = "";
		}
		pnp_print_option(buffer, indent, option);
	}

	ret = (buffer->curr - buf);
	kfree(buffer);
	return ret;
+31 −41
Original line number Diff line number Diff line
@@ -429,7 +429,7 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
 *  Add IRQ resource to resources list.
 */
static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
					     struct pnp_option *option,
					     unsigned int option_flags,
					     int size)
{
	unsigned char tmp[3];
@@ -446,27 +446,27 @@ static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
	if (size > 2)
		flags = tmp[2];

	pnp_register_irq_resource(dev, option, &map, flags);
	pnp_register_irq_resource(dev, option_flags, &map, flags);
}

/*
 *  Add DMA resource to resources list.
 */
static void __init isapnp_parse_dma_resource(struct pnp_dev *dev,
					     struct pnp_option *option,
					     unsigned int option_flags,
					     int size)
{
	unsigned char tmp[2];

	isapnp_peek(tmp, size);
	pnp_register_dma_resource(dev, option, tmp[0], tmp[1]);
	pnp_register_dma_resource(dev, option_flags, tmp[0], tmp[1]);
}

/*
 *  Add port resource to resources list.
 */
static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
					      struct pnp_option *option,
					      unsigned int option_flags,
					      int size)
{
	unsigned char tmp[7];
@@ -479,14 +479,15 @@ static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
	align = tmp[5];
	len = tmp[6];
	flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0;
	pnp_register_port_resource(dev, option, min, max, align, len, flags);
	pnp_register_port_resource(dev, option_flags,
				   min, max, align, len, flags);
}

/*
 *  Add fixed port resource to resources list.
 */
static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
						    struct pnp_option *option,
						    unsigned int option_flags,
						    int size)
{
	unsigned char tmp[3];
@@ -495,7 +496,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
	isapnp_peek(tmp, size);
	base = (tmp[1] << 8) | tmp[0];
	len = tmp[2];
	pnp_register_port_resource(dev, option, base, base, 0, len,
	pnp_register_port_resource(dev, option_flags, base, base, 0, len,
				   IORESOURCE_IO_FIXED);
}

@@ -503,7 +504,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
 *  Add memory resource to resources list.
 */
static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
					     struct pnp_option *option,
					     unsigned int option_flags,
					     int size)
{
	unsigned char tmp[9];
@@ -516,14 +517,15 @@ static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
	align = (tmp[6] << 8) | tmp[5];
	len = ((tmp[8] << 8) | tmp[7]) << 8;
	flags = tmp[0];
	pnp_register_mem_resource(dev, option, min, max, align, len, flags);
	pnp_register_mem_resource(dev, option_flags,
				  min, max, align, len, flags);
}

/*
 *  Add 32-bit memory resource to resources list.
 */
static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
					       struct pnp_option *option,
					       unsigned int option_flags,
					       int size)
{
	unsigned char tmp[17];
@@ -536,14 +538,15 @@ static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
	align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
	len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
	flags = tmp[0];
	pnp_register_mem_resource(dev, option, min, max, align, len, flags);
	pnp_register_mem_resource(dev, option_flags,
				  min, max, align, len, flags);
}

/*
 *  Add 32-bit fixed memory resource to resources list.
 */
static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
						     struct pnp_option *option,
						     unsigned int option_flags,
						     int size)
{
	unsigned char tmp[9];
@@ -554,7 +557,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
	base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
	len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
	flags = tmp[0];
	pnp_register_mem_resource(dev, option, base, base, 0, len, flags);
	pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
}

/*
@@ -584,18 +587,14 @@ static int __init isapnp_create_device(struct pnp_card *card,
{
	int number = 0, skip = 0, priority, compat = 0;
	unsigned char type, tmp[17];
	struct pnp_option *option, *option_independent;
	unsigned int option_flags;
	struct pnp_dev *dev;
	u32 eisa_id;
	char id[8];

	if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
		return 1;
	option_independent = option = pnp_register_independent_option(dev);
	if (!option) {
		kfree(dev);
		return 1;
	}
	option_flags = 0;
	pnp_add_card_device(card, dev);

	while (1) {
@@ -612,12 +611,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
					return 1;
				size = 0;
				skip = 0;
				option = pnp_register_independent_option(dev);
				option_independent = option;
				if (!option) {
					kfree(dev);
					return 1;
				}
				option_flags = 0;
				pnp_add_card_device(card, dev);
			} else {
				skip = 1;
@@ -638,13 +632,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
		case _STAG_IRQ:
			if (size < 2 || size > 3)
				goto __skip;
			isapnp_parse_irq_resource(dev, option, size);
			isapnp_parse_irq_resource(dev, option_flags, size);
			size = 0;
			break;
		case _STAG_DMA:
			if (size != 2)
				goto __skip;
			isapnp_parse_dma_resource(dev, option, size);
			isapnp_parse_dma_resource(dev, option_flags, size);
			size = 0;
			break;
		case _STAG_STARTDEP:
@@ -656,29 +650,24 @@ static int __init isapnp_create_device(struct pnp_card *card,
				priority = tmp[0];
				size = 0;
			}
			option = pnp_register_dependent_option(dev, priority);
			if (!option)
				return 1;
			option_flags = pnp_new_dependent_set(dev, priority);
			break;
		case _STAG_ENDDEP:
			if (size != 0)
				goto __skip;
			if (option_independent == option)
				dev_warn(&dev->dev, "missing "
					 "_STAG_STARTDEP tag\n");
			option = option_independent;
			dev_dbg(&dev->dev, "end dependent options\n");
			option_flags = 0;
			break;
		case _STAG_IOPORT:
			if (size != 7)
				goto __skip;
			isapnp_parse_port_resource(dev, option, size);
			isapnp_parse_port_resource(dev, option_flags, size);
			size = 0;
			break;
		case _STAG_FIXEDIO:
			if (size != 3)
				goto __skip;
			isapnp_parse_fixed_port_resource(dev, option, size);
			isapnp_parse_fixed_port_resource(dev, option_flags,
							 size);
			size = 0;
			break;
		case _STAG_VENDOR:
@@ -686,7 +675,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
		case _LTAG_MEMRANGE:
			if (size != 9)
				goto __skip;
			isapnp_parse_mem_resource(dev, option, size);
			isapnp_parse_mem_resource(dev, option_flags, size);
			size = 0;
			break;
		case _LTAG_ANSISTR:
@@ -701,13 +690,14 @@ static int __init isapnp_create_device(struct pnp_card *card,
		case _LTAG_MEM32RANGE:
			if (size != 17)
				goto __skip;
			isapnp_parse_mem32_resource(dev, option, size);
			isapnp_parse_mem32_resource(dev, option_flags, size);
			size = 0;
			break;
		case _LTAG_FIXEDMEM32RANGE:
			if (size != 9)
				goto __skip;
			isapnp_parse_fixed_mem32_resource(dev, option, size);
			isapnp_parse_fixed_mem32_resource(dev, option_flags,
							  size);
			size = 0;
			break;
		case _STAG_END:
+46 −99
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
 *
 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
 *	Bjorn Helgaas <bjorn.helgaas@hp.com>
 */

#include <linux/errno.h>
@@ -228,102 +230,51 @@ static void pnp_clean_resource_table(struct pnp_dev *dev)
/**
 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
 * @dev: pointer to the desired device
 * @depnum: the dependent function number
 *
 * Only set depnum to 0 if the device does not have dependent options.
 * @set: the dependent function number
 */
static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
static int pnp_assign_resources(struct pnp_dev *dev, int set)
{
	struct pnp_port *port;
	struct pnp_mem *mem;
	struct pnp_irq *irq;
	struct pnp_dma *dma;
	struct pnp_option *option;
	int nport = 0, nmem = 0, nirq = 0, ndma = 0;
	int ret = 0;

	dbg_pnp_show_resources(dev, "before pnp_assign_resources");
	dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
	mutex_lock(&pnp_res_mutex);
	pnp_clean_resource_table(dev);
	if (dev->independent) {
		dev_dbg(&dev->dev, "assigning independent options\n");
		port = dev->independent->port;
		mem = dev->independent->mem;
		irq = dev->independent->irq;
		dma = dev->independent->dma;
		while (port) {
			if (pnp_assign_port(dev, port, nport) < 0)
				goto fail;
			nport++;
			port = port->next;
		}
		while (mem) {
			if (pnp_assign_mem(dev, mem, nmem) < 0)
				goto fail;
			nmem++;
			mem = mem->next;
		}
		while (irq) {
			if (pnp_assign_irq(dev, irq, nirq) < 0)
				goto fail;
			nirq++;
			irq = irq->next;
		}
		while (dma) {
			if (pnp_assign_dma(dev, dma, ndma) < 0)
				goto fail;
			ndma++;
			dma = dma->next;
		}
	}

	if (depnum) {
		struct pnp_option *dep;
		int i;

		dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
		for (i = 1, dep = dev->dependent; i < depnum;
		     i++, dep = dep->next)
			if (!dep)
				goto fail;
		port = dep->port;
		mem = dep->mem;
		irq = dep->irq;
		dma = dep->dma;
		while (port) {
			if (pnp_assign_port(dev, port, nport) < 0)
				goto fail;
			nport++;
			port = port->next;
		}
		while (mem) {
			if (pnp_assign_mem(dev, mem, nmem) < 0)
				goto fail;
			nmem++;
			mem = mem->next;
		}
		while (irq) {
			if (pnp_assign_irq(dev, irq, nirq) < 0)
				goto fail;
			nirq++;
			irq = irq->next;
		}
		while (dma) {
			if (pnp_assign_dma(dev, dma, ndma) < 0)
				goto fail;
			ndma++;
			dma = dma->next;
		}
	} else if (dev->dependent)
		goto fail;
	list_for_each_entry(option, &dev->options, list) {
		if (pnp_option_is_dependent(option) &&
		    pnp_option_set(option) != set)
				continue;

		switch (option->type) {
		case IORESOURCE_IO:
			ret = pnp_assign_port(dev, &option->u.port, nport++);
			break;
		case IORESOURCE_MEM:
			ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
			break;
		case IORESOURCE_IRQ:
			ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
			break;
		case IORESOURCE_DMA:
			ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
			break;
		default:
			ret = -EINVAL;
			break;
		}
		if (ret < 0)
			break;
	}

	mutex_unlock(&pnp_res_mutex);
	dbg_pnp_show_resources(dev, "after pnp_assign_resources");
	return 1;

fail:
	if (ret < 0) {
		dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
		pnp_clean_resource_table(dev);
	mutex_unlock(&pnp_res_mutex);
	dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
	return 0;
	} else
		dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
	return ret;
}

/**
@@ -332,29 +283,25 @@ fail:
 */
int pnp_auto_config_dev(struct pnp_dev *dev)
{
	struct pnp_option *dep;
	int i = 1;
	int i, ret;

	if (!pnp_can_configure(dev)) {
		dev_dbg(&dev->dev, "configuration not supported\n");
		return -ENODEV;
	}

	if (!dev->dependent) {
		if (pnp_assign_resources(dev, 0))
	ret = pnp_assign_resources(dev, 0);
	if (ret == 0)
		return 0;
	} else {
		dep = dev->dependent;
		do {
			if (pnp_assign_resources(dev, i))

	for (i = 1; i < dev->num_dependent_sets; i++) {
		ret = pnp_assign_resources(dev, i);
		if (ret == 0)
			return 0;
			dep = dep->next;
			i++;
		} while (dep);
	}

	dev_err(&dev->dev, "unable to assign resources\n");
	return -EBUSY;
	return ret;
}

/**
Loading