18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> 68c2ecf20Sopenharmony_ci * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 88c2ecf20Sopenharmony_ci * Bjorn Helgaas <bjorn.helgaas@hp.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/pnp.h> 168c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include "base.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciDEFINE_MUTEX(pnp_res_mutex); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct resource *pnp_find_resource(struct pnp_dev *dev, 238c2ecf20Sopenharmony_ci unsigned char rule, 248c2ecf20Sopenharmony_ci unsigned long type, 258c2ecf20Sopenharmony_ci unsigned int bar) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct resource *res = pnp_get_resource(dev, type, bar); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* when the resource already exists, set its resource bits from rule */ 308c2ecf20Sopenharmony_ci if (res) { 318c2ecf20Sopenharmony_ci res->flags &= ~IORESOURCE_BITS; 328c2ecf20Sopenharmony_ci res->flags |= rule & IORESOURCE_BITS; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return res; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct resource *res, local_res; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx); 438c2ecf20Sopenharmony_ci if (res) { 448c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " io %d already set to %#llx-%#llx " 458c2ecf20Sopenharmony_ci "flags %#lx\n", idx, (unsigned long long) res->start, 468c2ecf20Sopenharmony_ci (unsigned long long) res->end, res->flags); 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci res = &local_res; 518c2ecf20Sopenharmony_ci res->flags = rule->flags | IORESOURCE_AUTO; 528c2ecf20Sopenharmony_ci res->start = 0; 538c2ecf20Sopenharmony_ci res->end = 0; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (!rule->size) { 568c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 578c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " io %d disabled\n", idx); 588c2ecf20Sopenharmony_ci goto __add; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci res->start = rule->min; 628c2ecf20Sopenharmony_ci res->end = res->start + rule->size - 1; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci while (!pnp_check_port(dev, res)) { 658c2ecf20Sopenharmony_ci res->start += rule->align; 668c2ecf20Sopenharmony_ci res->end = res->start + rule->size - 1; 678c2ecf20Sopenharmony_ci if (res->start > rule->max || !rule->align) { 688c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " couldn't assign io %d " 698c2ecf20Sopenharmony_ci "(min %#llx max %#llx)\n", idx, 708c2ecf20Sopenharmony_ci (unsigned long long) rule->min, 718c2ecf20Sopenharmony_ci (unsigned long long) rule->max); 728c2ecf20Sopenharmony_ci return -EBUSY; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci__add: 778c2ecf20Sopenharmony_ci pnp_add_io_resource(dev, res->start, res->end, res->flags); 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct resource *res, local_res; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx); 868c2ecf20Sopenharmony_ci if (res) { 878c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " mem %d already set to %#llx-%#llx " 888c2ecf20Sopenharmony_ci "flags %#lx\n", idx, (unsigned long long) res->start, 898c2ecf20Sopenharmony_ci (unsigned long long) res->end, res->flags); 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci res = &local_res; 948c2ecf20Sopenharmony_ci res->flags = rule->flags | IORESOURCE_AUTO; 958c2ecf20Sopenharmony_ci res->start = 0; 968c2ecf20Sopenharmony_ci res->end = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* ??? rule->flags restricted to 8 bits, all tests bogus ??? */ 998c2ecf20Sopenharmony_ci if (!(rule->flags & IORESOURCE_MEM_WRITEABLE)) 1008c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_READONLY; 1018c2ecf20Sopenharmony_ci if (rule->flags & IORESOURCE_MEM_RANGELENGTH) 1028c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_RANGELENGTH; 1038c2ecf20Sopenharmony_ci if (rule->flags & IORESOURCE_MEM_SHADOWABLE) 1048c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_SHADOWABLE; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (!rule->size) { 1078c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 1088c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " mem %d disabled\n", idx); 1098c2ecf20Sopenharmony_ci goto __add; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci res->start = rule->min; 1138c2ecf20Sopenharmony_ci res->end = res->start + rule->size - 1; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci while (!pnp_check_mem(dev, res)) { 1168c2ecf20Sopenharmony_ci res->start += rule->align; 1178c2ecf20Sopenharmony_ci res->end = res->start + rule->size - 1; 1188c2ecf20Sopenharmony_ci if (res->start > rule->max || !rule->align) { 1198c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " couldn't assign mem %d " 1208c2ecf20Sopenharmony_ci "(min %#llx max %#llx)\n", idx, 1218c2ecf20Sopenharmony_ci (unsigned long long) rule->min, 1228c2ecf20Sopenharmony_ci (unsigned long long) rule->max); 1238c2ecf20Sopenharmony_ci return -EBUSY; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci__add: 1288c2ecf20Sopenharmony_ci pnp_add_mem_resource(dev, res->start, res->end, res->flags); 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct resource *res, local_res; 1358c2ecf20Sopenharmony_ci int i; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* IRQ priority: this table is good for i386 */ 1388c2ecf20Sopenharmony_ci static unsigned short xtab[16] = { 1398c2ecf20Sopenharmony_ci 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2 1408c2ecf20Sopenharmony_ci }; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx); 1438c2ecf20Sopenharmony_ci if (res) { 1448c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n", 1458c2ecf20Sopenharmony_ci idx, (int) res->start, res->flags); 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci res = &local_res; 1508c2ecf20Sopenharmony_ci res->flags = rule->flags | IORESOURCE_AUTO; 1518c2ecf20Sopenharmony_ci res->start = -1; 1528c2ecf20Sopenharmony_ci res->end = -1; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) { 1558c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 1568c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " irq %d disabled\n", idx); 1578c2ecf20Sopenharmony_ci goto __add; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* TBD: need check for >16 IRQ */ 1618c2ecf20Sopenharmony_ci res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16); 1628c2ecf20Sopenharmony_ci if (res->start < PNP_IRQ_NR) { 1638c2ecf20Sopenharmony_ci res->end = res->start; 1648c2ecf20Sopenharmony_ci goto __add; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 1678c2ecf20Sopenharmony_ci if (test_bit(xtab[i], rule->map.bits)) { 1688c2ecf20Sopenharmony_ci res->start = res->end = xtab[i]; 1698c2ecf20Sopenharmony_ci if (pnp_check_irq(dev, res)) 1708c2ecf20Sopenharmony_ci goto __add; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (rule->flags & IORESOURCE_IRQ_OPTIONAL) { 1758c2ecf20Sopenharmony_ci res->start = -1; 1768c2ecf20Sopenharmony_ci res->end = -1; 1778c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 1788c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " irq %d disabled (optional)\n", idx); 1798c2ecf20Sopenharmony_ci goto __add; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " couldn't assign irq %d\n", idx); 1838c2ecf20Sopenharmony_ci return -EBUSY; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci__add: 1868c2ecf20Sopenharmony_ci pnp_add_irq_resource(dev, res->start, res->flags); 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#ifdef CONFIG_ISA_DMA_API 1918c2ecf20Sopenharmony_cistatic int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct resource *res, local_res; 1948c2ecf20Sopenharmony_ci int i; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* DMA priority: this table is good for i386 */ 1978c2ecf20Sopenharmony_ci static unsigned short xtab[8] = { 1988c2ecf20Sopenharmony_ci 1, 3, 5, 6, 7, 0, 2, 4 1998c2ecf20Sopenharmony_ci }; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx); 2028c2ecf20Sopenharmony_ci if (res) { 2038c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n", 2048c2ecf20Sopenharmony_ci idx, (int) res->start, res->flags); 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci res = &local_res; 2098c2ecf20Sopenharmony_ci res->flags = rule->flags | IORESOURCE_AUTO; 2108c2ecf20Sopenharmony_ci res->start = -1; 2118c2ecf20Sopenharmony_ci res->end = -1; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!rule->map) { 2148c2ecf20Sopenharmony_ci res->flags |= IORESOURCE_DISABLED; 2158c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " dma %d disabled\n", idx); 2168c2ecf20Sopenharmony_ci goto __add; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 2208c2ecf20Sopenharmony_ci if (rule->map & (1 << xtab[i])) { 2218c2ecf20Sopenharmony_ci res->start = res->end = xtab[i]; 2228c2ecf20Sopenharmony_ci if (pnp_check_dma(dev, res)) 2238c2ecf20Sopenharmony_ci goto __add; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, " couldn't assign dma %d\n", idx); 2288c2ecf20Sopenharmony_ci return -EBUSY; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci__add: 2318c2ecf20Sopenharmony_ci pnp_add_dma_resource(dev, res->start, res->flags); 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci#endif /* CONFIG_ISA_DMA_API */ 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_civoid pnp_init_resources(struct pnp_dev *dev) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci pnp_free_resources(dev); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void pnp_clean_resource_table(struct pnp_dev *dev) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct pnp_resource *pnp_res, *tmp; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) { 2468c2ecf20Sopenharmony_ci if (pnp_res->res.flags & IORESOURCE_AUTO) 2478c2ecf20Sopenharmony_ci pnp_free_resource(pnp_res); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/** 2528c2ecf20Sopenharmony_ci * pnp_assign_resources - assigns resources to the device based on the specified dependent number 2538c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 2548c2ecf20Sopenharmony_ci * @set: the dependent function number 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic int pnp_assign_resources(struct pnp_dev *dev, int set) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct pnp_option *option; 2598c2ecf20Sopenharmony_ci int nport = 0, nmem = 0, nirq = 0; 2608c2ecf20Sopenharmony_ci int ndma __maybe_unused = 0; 2618c2ecf20Sopenharmony_ci int ret = 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set); 2648c2ecf20Sopenharmony_ci mutex_lock(&pnp_res_mutex); 2658c2ecf20Sopenharmony_ci pnp_clean_resource_table(dev); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci list_for_each_entry(option, &dev->options, list) { 2688c2ecf20Sopenharmony_ci if (pnp_option_is_dependent(option) && 2698c2ecf20Sopenharmony_ci pnp_option_set(option) != set) 2708c2ecf20Sopenharmony_ci continue; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci switch (option->type) { 2738c2ecf20Sopenharmony_ci case IORESOURCE_IO: 2748c2ecf20Sopenharmony_ci ret = pnp_assign_port(dev, &option->u.port, nport++); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case IORESOURCE_MEM: 2778c2ecf20Sopenharmony_ci ret = pnp_assign_mem(dev, &option->u.mem, nmem++); 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case IORESOURCE_IRQ: 2808c2ecf20Sopenharmony_ci ret = pnp_assign_irq(dev, &option->u.irq, nirq++); 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci#ifdef CONFIG_ISA_DMA_API 2838c2ecf20Sopenharmony_ci case IORESOURCE_DMA: 2848c2ecf20Sopenharmony_ci ret = pnp_assign_dma(dev, &option->u.dma, ndma++); 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci#endif 2878c2ecf20Sopenharmony_ci default: 2888c2ecf20Sopenharmony_ci ret = -EINVAL; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci if (ret < 0) 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci mutex_unlock(&pnp_res_mutex); 2968c2ecf20Sopenharmony_ci if (ret < 0) { 2978c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret); 2988c2ecf20Sopenharmony_ci pnp_clean_resource_table(dev); 2998c2ecf20Sopenharmony_ci } else 3008c2ecf20Sopenharmony_ci dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded"); 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/** 3058c2ecf20Sopenharmony_ci * pnp_auto_config_dev - automatically assigns resources to a device 3068c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ciint pnp_auto_config_dev(struct pnp_dev *dev) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci int i, ret; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (!pnp_can_configure(dev)) { 3138c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "configuration not supported\n"); 3148c2ecf20Sopenharmony_ci return -ENODEV; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ret = pnp_assign_resources(dev, 0); 3188c2ecf20Sopenharmony_ci if (ret == 0) 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci for (i = 1; i < dev->num_dependent_sets; i++) { 3228c2ecf20Sopenharmony_ci ret = pnp_assign_resources(dev, i); 3238c2ecf20Sopenharmony_ci if (ret == 0) 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci dev_err(&dev->dev, "unable to assign resources\n"); 3288c2ecf20Sopenharmony_ci return ret; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/** 3328c2ecf20Sopenharmony_ci * pnp_start_dev - low-level start of the PnP device 3338c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * assumes that resources have already been allocated 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ciint pnp_start_dev(struct pnp_dev *dev) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci if (!pnp_can_write(dev)) { 3408c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "activation not supported\n"); 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci dbg_pnp_show_resources(dev, "pnp_start_dev"); 3458c2ecf20Sopenharmony_ci if (dev->protocol->set(dev) < 0) { 3468c2ecf20Sopenharmony_ci dev_err(&dev->dev, "activation failed\n"); 3478c2ecf20Sopenharmony_ci return -EIO; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci dev_info(&dev->dev, "activated\n"); 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/** 3558c2ecf20Sopenharmony_ci * pnp_stop_dev - low-level disable of the PnP device 3568c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * does not free resources 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ciint pnp_stop_dev(struct pnp_dev *dev) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci if (!pnp_can_disable(dev)) { 3638c2ecf20Sopenharmony_ci pnp_dbg(&dev->dev, "disabling not supported\n"); 3648c2ecf20Sopenharmony_ci return -EINVAL; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci if (dev->protocol->disable(dev) < 0) { 3678c2ecf20Sopenharmony_ci dev_err(&dev->dev, "disable failed\n"); 3688c2ecf20Sopenharmony_ci return -EIO; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci dev_info(&dev->dev, "disabled\n"); 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/** 3768c2ecf20Sopenharmony_ci * pnp_activate_dev - activates a PnP device for use 3778c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * does not validate or set resources so be careful. 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ciint pnp_activate_dev(struct pnp_dev *dev) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci int error; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (dev->active) 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* ensure resources are allocated */ 3898c2ecf20Sopenharmony_ci if (pnp_auto_config_dev(dev)) 3908c2ecf20Sopenharmony_ci return -EBUSY; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci error = pnp_start_dev(dev); 3938c2ecf20Sopenharmony_ci if (error) 3948c2ecf20Sopenharmony_ci return error; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci dev->active = 1; 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/** 4018c2ecf20Sopenharmony_ci * pnp_disable_dev - disables device 4028c2ecf20Sopenharmony_ci * @dev: pointer to the desired device 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * inform the correct pnp protocol so that resources can be used by other devices 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ciint pnp_disable_dev(struct pnp_dev *dev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci int error; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (!dev->active) 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci error = pnp_stop_dev(dev); 4148c2ecf20Sopenharmony_ci if (error) 4158c2ecf20Sopenharmony_ci return error; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dev->active = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* release the resources so that other devices can use them */ 4208c2ecf20Sopenharmony_ci mutex_lock(&pnp_res_mutex); 4218c2ecf20Sopenharmony_ci pnp_clean_resource_table(dev); 4228c2ecf20Sopenharmony_ci mutex_unlock(&pnp_res_mutex); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pnp_start_dev); 4288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pnp_stop_dev); 4298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pnp_activate_dev); 4308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pnp_disable_dev); 431