11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4c1017a4cdb68ae5368fbc9ee42c77f1f5dca8916Jaroslav Kysela * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 61f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 71f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas * Bjorn Helgaas <bjorn.helgaas@hp.com> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pnp.h> 154e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/bitmap.h> 16b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker#include <linux/mutex.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "base.h" 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel WalkerDEFINE_MUTEX(pnp_res_mutex); 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas struct resource *res, local_res; 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = pnp_get_resource(dev, IORESOURCE_IO, idx); 26aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (res) { 272f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " io %d already set to %#llx-%#llx " 2828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas "flags %#lx\n", idx, (unsigned long long) res->start, 2928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas (unsigned long long) res->end, res->flags); 306e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 3181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 3281b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas 33aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = &local_res; 34aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->flags = rule->flags | IORESOURCE_AUTO; 35aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->start = 0; 36aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->end = 0; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rule->size) { 3928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_DISABLED; 402f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " io %d disabled\n", idx); 41aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4428ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start = rule->min; 4528ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->end = res->start + rule->size - 1; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47f5d94ff014cb7e6212f40fc6644f3fd68507df33Bjorn Helgaas while (!pnp_check_port(dev, res)) { 4828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start += rule->align; 4928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->end = res->start + rule->size - 1; 5028ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas if (res->start > rule->max || !rule->align) { 512f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " couldn't assign io %d " 52fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas "(min %#llx max %#llx)\n", idx, 53fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas (unsigned long long) rule->min, 54fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas (unsigned long long) rule->max); 556e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return -EBUSY; 5681b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas 59aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add: 60aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_add_io_resource(dev, res->start, res->end, res->flags); 616e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 66aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas struct resource *res, local_res; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = pnp_get_resource(dev, IORESOURCE_MEM, idx); 69aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (res) { 702f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " 7128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas "flags %#lx\n", idx, (unsigned long long) res->start, 7228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas (unsigned long long) res->end, res->flags); 736e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 7481b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 7581b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas 76aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = &local_res; 77aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->flags = rule->flags | IORESOURCE_AUTO; 78aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->start = 0; 79aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->end = 0; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) 8228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_READONLY; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rule->flags & IORESOURCE_MEM_CACHEABLE) 8428ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_CACHEABLE; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rule->flags & IORESOURCE_MEM_RANGELENGTH) 8628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_RANGELENGTH; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rule->flags & IORESOURCE_MEM_SHADOWABLE) 8828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_SHADOWABLE; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rule->size) { 9128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_DISABLED; 922f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " mem %d disabled\n", idx); 93aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start = rule->min; 9728ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->end = res->start + rule->size - 1; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 99f5d94ff014cb7e6212f40fc6644f3fd68507df33Bjorn Helgaas while (!pnp_check_mem(dev, res)) { 10028ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start += rule->align; 10128ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->end = res->start + rule->size - 1; 10228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas if (res->start > rule->max || !rule->align) { 1032f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " couldn't assign mem %d " 104fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas "(min %#llx max %#llx)\n", idx, 105fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas (unsigned long long) rule->min, 106fcfb7ce3d688d5c15fc9bc0a2a48e1ededdb046fBjorn Helgaas (unsigned long long) rule->max); 1076e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return -EBUSY; 10881b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 110aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas 111aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add: 112aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_add_mem_resource(dev, res->start, res->end, res->flags); 1136e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1169dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaasstatic int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 118aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas struct resource *res, local_res; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IRQ priority: this table is good for i386 */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned short xtab[16] = { 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = pnp_get_resource(dev, IORESOURCE_IRQ, idx); 127aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (res) { 1282f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", 12928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas idx, (int) res->start, res->flags); 1306e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 13181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 13281b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas 133aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = &local_res; 134aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->flags = rule->flags | IORESOURCE_AUTO; 135aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->start = -1; 136aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->end = -1; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1387aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) { 13928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->flags |= IORESOURCE_DISABLED; 1402f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " irq %d disabled\n", idx); 141aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TBD: need check for >16 IRQ */ 1457aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16); 14628ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas if (res->start < PNP_IRQ_NR) { 14728ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->end = res->start; 148aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 1517aefff51854ccd33599c40b4e360d94cb2b7622fBjorn Helgaas if (test_bit(xtab[i], rule->map.bits)) { 15228ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start = res->end = xtab[i]; 153aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (pnp_check_irq(dev, res)) 154aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 157d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas 158d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas if (rule->flags & IORESOURCE_IRQ_OPTIONAL) { 159d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas res->start = -1; 160d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas res->end = -1; 161d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas res->flags |= IORESOURCE_DISABLED; 1622f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " irq %d disabled (optional)\n", idx); 163d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas goto __add; 164d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas } 165d5ebde6ef5c2d51828f975a81d7d0e58bccfd833Bjorn Helgaas 1662f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " couldn't assign irq %d\n", idx); 1676e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return -EBUSY; 168aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas 169aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add: 170aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_add_irq_resource(dev, res->start, res->flags); 1716e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#ifdef CONFIG_ISA_DMA_API 1756e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaasstatic int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 177aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas struct resource *res, local_res; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA priority: this table is good for i386 */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned short xtab[8] = { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, 3, 5, 6, 7, 0, 2, 4 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = pnp_get_resource(dev, IORESOURCE_DMA, idx); 186aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (res) { 1872f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", 18828ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas idx, (int) res->start, res->flags); 1896e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 19081b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas } 19181b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas 192aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res = &local_res; 193aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->flags = rule->flags | IORESOURCE_AUTO; 194aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->start = -1; 195aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->end = -1; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) { 1989dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas if (rule->map & (1 << xtab[i])) { 19928ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start = res->end = xtab[i]; 200aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (pnp_check_dma(dev, res)) 201aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas goto __add; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2047ef36390fabe2168fe31f245e49eb4e5f3762622Jan Beulich#ifdef MAX_DMA_CHANNELS 20528ccffcf028777e830cbdc30bc54ba8a37e2fc23Bjorn Helgaas res->start = res->end = MAX_DMA_CHANNELS; 2067ef36390fabe2168fe31f245e49eb4e5f3762622Jan Beulich#endif 207aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas res->flags |= IORESOURCE_DISABLED; 2082f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, " disable dma %d\n", idx); 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas__add: 211aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_add_dma_resource(dev, res->start, res->flags); 2126e906f0e1c8633ed357a64e9861f1822789bee3dBjorn Helgaas return 0; 213d948a8daa059cf5b3e7f002e7b92acf00fc70c49Bjorn Helgaas} 214586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#endif /* CONFIG_ISA_DMA_API */ 215d948a8daa059cf5b3e7f002e7b92acf00fc70c49Bjorn Helgaas 2162cd1393098073426256cb4543c897f8c340d0b93Bjorn Helgaasvoid pnp_init_resources(struct pnp_dev *dev) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 218aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_free_resources(dev); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2216969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaasstatic void pnp_clean_resource_table(struct pnp_dev *dev) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 223aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas struct pnp_resource *pnp_res, *tmp; 224aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas 225aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) { 226aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas if (pnp_res->res.flags & IORESOURCE_AUTO) 227aee3ad815dd291a7193ab01da0f1a30c84d00061Bjorn Helgaas pnp_free_resource(pnp_res); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_assign_resources - assigns resources to the device based on the specified dependent number 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device 2341f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas * @set: the dependent function number 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2361f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaasstatic int pnp_assign_resources(struct pnp_dev *dev, int set) 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2381f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas struct pnp_option *option; 239586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes int nport = 0, nmem = 0, nirq = 0; 240586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes int ndma __maybe_unused = 0; 2411f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas int ret = 0; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2432f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set); 244b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker mutex_lock(&pnp_res_mutex); 2456969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaas pnp_clean_resource_table(dev); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas list_for_each_entry(option, &dev->options, list) { 2481f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas if (pnp_option_is_dependent(option) && 2491f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas pnp_option_set(option) != set) 2501f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas continue; 2511f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas 2521f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas switch (option->type) { 2531f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas case IORESOURCE_IO: 2541f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_port(dev, &option->u.port, nport++); 2551f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 2561f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas case IORESOURCE_MEM: 2571f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_mem(dev, &option->u.mem, nmem++); 2581f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 2591f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas case IORESOURCE_IRQ: 2601f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_irq(dev, &option->u.irq, nirq++); 2611f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 262586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#ifdef CONFIG_ISA_DMA_API 2631f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas case IORESOURCE_DMA: 2641f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_dma(dev, &option->u.dma, ndma++); 2651f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 266586f83e2b4c080073b115c1a0fcc2757f52839b8David Rientjes#endif 2671f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas default: 2681f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = -EINVAL; 2691f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2711f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas if (ret < 0) 2721f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas break; 2731f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas } 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 275b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker mutex_unlock(&pnp_res_mutex); 2761f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas if (ret < 0) { 2772f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret); 2781f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas pnp_clean_resource_table(dev); 2791f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas } else 2801f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded"); 2811f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas return ret; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_auto_config_dev - automatically assigns resources to a device 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_auto_config_dev(struct pnp_dev *dev) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2901f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas int i, ret; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2929dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas if (!pnp_can_configure(dev)) { 2932f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, "configuration not supported\n"); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_resources(dev, 0); 2981f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas if (ret == 0) 2991f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas return 0; 3001f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas 3011f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas for (i = 1; i < dev->num_dependent_sets; i++) { 3021f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas ret = pnp_assign_resources(dev, i); 3031f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas if (ret == 0) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 307a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas dev_err(&dev->dev, "unable to assign resources\n"); 3081f32ca31e7409d37c1b25e5f81840fb184380cdfBjorn Helgaas return ret; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 31268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_start_dev - low-level start of the PnP device 31368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device 31468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * 31507d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas * assumes that resources have already been allocated 31668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */ 31768094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_start_dev(struct pnp_dev *dev) 31868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{ 31968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman if (!pnp_can_write(dev)) { 3202f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, "activation not supported\n"); 32168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return -EINVAL; 32268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman } 32368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 32481b5c75f0ed22a93c3da00650d0898eec56e1d62Bjorn Helgaas dbg_pnp_show_resources(dev, "pnp_start_dev"); 32559284cb4099411bc6f4915a5a4cb76414440c447Bjorn Helgaas if (dev->protocol->set(dev) < 0) { 326a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas dev_err(&dev->dev, "activation failed\n"); 32768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return -EIO; 32868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman } 32968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 330a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas dev_info(&dev->dev, "activated\n"); 33168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return 0; 33268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman} 33368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 33468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/** 33568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * pnp_stop_dev - low-level disable of the PnP device 33668094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * @dev: pointer to the desired device 33768094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * 33868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman * does not free resources 33968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman */ 34068094e3251a664ee1389fcf179497237cbf78331Pierre Ossmanint pnp_stop_dev(struct pnp_dev *dev) 34168094e3251a664ee1389fcf179497237cbf78331Pierre Ossman{ 34268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman if (!pnp_can_disable(dev)) { 3432f53432c2aedbe79020e44525eb069d9138a01ddBjorn Helgaas pnp_dbg(&dev->dev, "disabling not supported\n"); 34468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return -EINVAL; 34568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman } 3469dd78466c956ac4b4f38e12032dc4249ccf57ad1Bjorn Helgaas if (dev->protocol->disable(dev) < 0) { 347a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas dev_err(&dev->dev, "disable failed\n"); 34868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return -EIO; 34968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman } 35068094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 351a05d0781695566296e74a3670dd5bbd3daf24ae2Bjorn Helgaas dev_info(&dev->dev, "disabled\n"); 35268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return 0; 35368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman} 35468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 35568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman/** 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_activate_dev - activates a PnP device for use 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not validate or set resources so be careful. 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_activate_dev(struct pnp_dev *dev) 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman int error; 36468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 36507d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas if (dev->active) 366cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas return 0; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ensure resources are allocated */ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pnp_auto_config_dev(dev)) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37268094e3251a664ee1389fcf179497237cbf78331Pierre Ossman error = pnp_start_dev(dev); 37368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman if (error) 37468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return error; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->active = 1; 377cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas return 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pnp_disable_dev - disables device 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @dev: pointer to the desired device 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inform the correct pnp protocol so that resources can be used by other devices 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pnp_disable_dev(struct pnp_dev *dev) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38868094e3251a664ee1389fcf179497237cbf78331Pierre Ossman int error; 38968094e3251a664ee1389fcf179497237cbf78331Pierre Ossman 39007d4e9af109221ab731c5aaf832e89776c64b013Bjorn Helgaas if (!dev->active) 391cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas return 0; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39368094e3251a664ee1389fcf179497237cbf78331Pierre Ossman error = pnp_stop_dev(dev); 39468094e3251a664ee1389fcf179497237cbf78331Pierre Ossman if (error) 39568094e3251a664ee1389fcf179497237cbf78331Pierre Ossman return error; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->active = 0; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* release the resources so that other devices can use them */ 400b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker mutex_lock(&pnp_res_mutex); 4016969c7ed558cf5e9eff01734be0174a296938092Bjorn Helgaas pnp_clean_resource_table(dev); 402b3bd86e2fdce01d6b49271a553d2a18b3e0510f3Daniel Walker mutex_unlock(&pnp_res_mutex); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 404cc8259a6666de456460bacdd5637f5e2d71790eaBjorn Helgaas return 0; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40768094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_start_dev); 40868094e3251a664ee1389fcf179497237cbf78331Pierre OssmanEXPORT_SYMBOL(pnp_stop_dev); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_activate_dev); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(pnp_disable_dev); 411