11da177e4SLinus Torvalds /* 207d4e9afSBjorn Helgaas * support.c - standard functions for the use of pnp protocol drivers 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 51f32ca31SBjorn Helgaas * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 61f32ca31SBjorn Helgaas * Bjorn Helgaas <bjorn.helgaas@hp.com> 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds #include <linux/module.h> 101da177e4SLinus Torvalds #include <linux/ctype.h> 111da177e4SLinus Torvalds #include <linux/pnp.h> 121da177e4SLinus Torvalds #include "base.h" 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds /** 1507d4e9afSBjorn Helgaas * pnp_is_active - Determines if a device is active based on its current 1607d4e9afSBjorn Helgaas * resources 171da177e4SLinus Torvalds * @dev: pointer to the desired PnP device 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds int pnp_is_active(struct pnp_dev *dev) 201da177e4SLinus Torvalds { 21aee3ad81SBjorn Helgaas /* 22aee3ad81SBjorn Helgaas * I don't think this is very reliable because pnp_disable_dev() 23aee3ad81SBjorn Helgaas * only clears out auto-assigned resources. 24aee3ad81SBjorn Helgaas */ 251da177e4SLinus Torvalds if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 && 261da177e4SLinus Torvalds !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 && 279dd78466SBjorn Helgaas pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1) 281da177e4SLinus Torvalds return 0; 291da177e4SLinus Torvalds else 301da177e4SLinus Torvalds return 1; 311da177e4SLinus Torvalds } 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds EXPORT_SYMBOL(pnp_is_active); 3425eb8461SBjorn Helgaas 3525eb8461SBjorn Helgaas /* 3625eb8461SBjorn Helgaas * Functionally similar to acpi_ex_eisa_id_to_string(), but that's 3725eb8461SBjorn Helgaas * buried in the ACPI CA, and we can't depend on it being present. 3825eb8461SBjorn Helgaas */ 3925eb8461SBjorn Helgaas void pnp_eisa_id_to_string(u32 id, char *str) 4025eb8461SBjorn Helgaas { 4125eb8461SBjorn Helgaas id = be32_to_cpu(id); 4225eb8461SBjorn Helgaas 4325eb8461SBjorn Helgaas /* 4425eb8461SBjorn Helgaas * According to the specs, the first three characters are five-bit 4525eb8461SBjorn Helgaas * compressed ASCII, and the left-over high order bit should be zero. 4625eb8461SBjorn Helgaas * However, the Linux ISAPNP code historically used six bits for the 4725eb8461SBjorn Helgaas * first character, and there seem to be IDs that depend on that, 4825eb8461SBjorn Helgaas * e.g., "nEC8241" in the Linux 8250_pnp serial driver and the 4925eb8461SBjorn Helgaas * FreeBSD sys/pc98/cbus/sio_cbus.c driver. 5025eb8461SBjorn Helgaas */ 5125eb8461SBjorn Helgaas str[0] = 'A' + ((id >> 26) & 0x3f) - 1; 5225eb8461SBjorn Helgaas str[1] = 'A' + ((id >> 21) & 0x1f) - 1; 5325eb8461SBjorn Helgaas str[2] = 'A' + ((id >> 16) & 0x1f) - 1; 543fc95772SHarvey Harrison str[3] = hex_asc_hi(id >> 8); 553fc95772SHarvey Harrison str[4] = hex_asc_lo(id >> 8); 563fc95772SHarvey Harrison str[5] = hex_asc_hi(id); 573fc95772SHarvey Harrison str[6] = hex_asc_lo(id); 5825eb8461SBjorn Helgaas str[7] = '\0'; 5925eb8461SBjorn Helgaas } 6081b5c75fSBjorn Helgaas 619fdee4e0SBjorn Helgaas char *pnp_resource_type_name(struct resource *res) 629fdee4e0SBjorn Helgaas { 639fdee4e0SBjorn Helgaas switch (pnp_resource_type(res)) { 649fdee4e0SBjorn Helgaas case IORESOURCE_IO: 659fdee4e0SBjorn Helgaas return "io"; 669fdee4e0SBjorn Helgaas case IORESOURCE_MEM: 679fdee4e0SBjorn Helgaas return "mem"; 689fdee4e0SBjorn Helgaas case IORESOURCE_IRQ: 699fdee4e0SBjorn Helgaas return "irq"; 709fdee4e0SBjorn Helgaas case IORESOURCE_DMA: 719fdee4e0SBjorn Helgaas return "dma"; 729fdee4e0SBjorn Helgaas } 739fdee4e0SBjorn Helgaas return NULL; 749fdee4e0SBjorn Helgaas } 759fdee4e0SBjorn Helgaas 7681b5c75fSBjorn Helgaas void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) 7781b5c75fSBjorn Helgaas { 78aee3ad81SBjorn Helgaas struct pnp_resource *pnp_res; 7981b5c75fSBjorn Helgaas 809a007b37SBjorn Helgaas if (list_empty(&dev->resources)) 812f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "%s: no current resources\n", desc); 829a007b37SBjorn Helgaas else { 832f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "%s: current resources:\n", desc); 849a007b37SBjorn Helgaas list_for_each_entry(pnp_res, &dev->resources, list) 85*c7dabef8SBjorn Helgaas pnp_dbg(&dev->dev, "%pr\n", &pnp_res->res); 8681b5c75fSBjorn Helgaas } 8781b5c75fSBjorn Helgaas } 881f32ca31SBjorn Helgaas 891f32ca31SBjorn Helgaas char *pnp_option_priority_name(struct pnp_option *option) 901f32ca31SBjorn Helgaas { 911f32ca31SBjorn Helgaas switch (pnp_option_priority(option)) { 921f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_PREFERRED: 931f32ca31SBjorn Helgaas return "preferred"; 941f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_ACCEPTABLE: 951f32ca31SBjorn Helgaas return "acceptable"; 961f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_FUNCTIONAL: 971f32ca31SBjorn Helgaas return "functional"; 981f32ca31SBjorn Helgaas } 991f32ca31SBjorn Helgaas return "invalid"; 1001f32ca31SBjorn Helgaas } 1011f32ca31SBjorn Helgaas 1021f32ca31SBjorn Helgaas void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option) 1031f32ca31SBjorn Helgaas { 1041f32ca31SBjorn Helgaas char buf[128]; 1051f32ca31SBjorn Helgaas int len = 0, i; 1061f32ca31SBjorn Helgaas struct pnp_port *port; 1071f32ca31SBjorn Helgaas struct pnp_mem *mem; 1081f32ca31SBjorn Helgaas struct pnp_irq *irq; 1091f32ca31SBjorn Helgaas struct pnp_dma *dma; 1101f32ca31SBjorn Helgaas 1111f32ca31SBjorn Helgaas if (pnp_option_is_dependent(option)) 112ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, 1131f32ca31SBjorn Helgaas " dependent set %d (%s) ", 1141f32ca31SBjorn Helgaas pnp_option_set(option), 1151f32ca31SBjorn Helgaas pnp_option_priority_name(option)); 1161f32ca31SBjorn Helgaas else 117ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, 118ea44c1d6SBjorn Helgaas " independent "); 1191f32ca31SBjorn Helgaas 1201f32ca31SBjorn Helgaas switch (option->type) { 1211f32ca31SBjorn Helgaas case IORESOURCE_IO: 1221f32ca31SBjorn Helgaas port = &option->u.port; 123ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, "io min %#llx " 1241f32ca31SBjorn Helgaas "max %#llx align %lld size %lld flags %#x", 1251f32ca31SBjorn Helgaas (unsigned long long) port->min, 1261f32ca31SBjorn Helgaas (unsigned long long) port->max, 1271f32ca31SBjorn Helgaas (unsigned long long) port->align, 1281f32ca31SBjorn Helgaas (unsigned long long) port->size, port->flags); 1291f32ca31SBjorn Helgaas break; 1301f32ca31SBjorn Helgaas case IORESOURCE_MEM: 1311f32ca31SBjorn Helgaas mem = &option->u.mem; 132ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, "mem min %#llx " 1331f32ca31SBjorn Helgaas "max %#llx align %lld size %lld flags %#x", 1341f32ca31SBjorn Helgaas (unsigned long long) mem->min, 1351f32ca31SBjorn Helgaas (unsigned long long) mem->max, 1361f32ca31SBjorn Helgaas (unsigned long long) mem->align, 1371f32ca31SBjorn Helgaas (unsigned long long) mem->size, mem->flags); 1381f32ca31SBjorn Helgaas break; 1391f32ca31SBjorn Helgaas case IORESOURCE_IRQ: 1401f32ca31SBjorn Helgaas irq = &option->u.irq; 141ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, "irq"); 1421f32ca31SBjorn Helgaas if (bitmap_empty(irq->map.bits, PNP_IRQ_NR)) 143ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, 1441f32ca31SBjorn Helgaas " <none>"); 1451f32ca31SBjorn Helgaas else { 1461f32ca31SBjorn Helgaas for (i = 0; i < PNP_IRQ_NR; i++) 1471f32ca31SBjorn Helgaas if (test_bit(i, irq->map.bits)) 148ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, 1491f32ca31SBjorn Helgaas sizeof(buf) - len, 1501f32ca31SBjorn Helgaas " %d", i); 1511f32ca31SBjorn Helgaas } 152ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, " flags %#x", 1531f32ca31SBjorn Helgaas irq->flags); 1541f32ca31SBjorn Helgaas if (irq->flags & IORESOURCE_IRQ_OPTIONAL) 155ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, 1561f32ca31SBjorn Helgaas " (optional)"); 1571f32ca31SBjorn Helgaas break; 1581f32ca31SBjorn Helgaas case IORESOURCE_DMA: 1591f32ca31SBjorn Helgaas dma = &option->u.dma; 160ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, "dma"); 1611f32ca31SBjorn Helgaas if (!dma->map) 162ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, 1631f32ca31SBjorn Helgaas " <none>"); 1641f32ca31SBjorn Helgaas else { 1651f32ca31SBjorn Helgaas for (i = 0; i < 8; i++) 1661f32ca31SBjorn Helgaas if (dma->map & (1 << i)) 167ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, 1681f32ca31SBjorn Helgaas sizeof(buf) - len, 1691f32ca31SBjorn Helgaas " %d", i); 1701f32ca31SBjorn Helgaas } 171ea44c1d6SBjorn Helgaas len += scnprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " 1721f32ca31SBjorn Helgaas "flags %#x", dma->map, dma->flags); 1731f32ca31SBjorn Helgaas break; 1741f32ca31SBjorn Helgaas } 1752f53432cSBjorn Helgaas pnp_dbg(&dev->dev, "%s\n", buf); 1761f32ca31SBjorn Helgaas } 177