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> 5*1f32ca31SBjorn Helgaas * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 6*1f32ca31SBjorn 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 { 7881b5c75fSBjorn Helgaas #ifdef DEBUG 79aee3ad81SBjorn Helgaas char buf[128]; 80aee3ad81SBjorn Helgaas int len = 0; 81aee3ad81SBjorn Helgaas struct pnp_resource *pnp_res; 8281b5c75fSBjorn Helgaas struct resource *res; 8381b5c75fSBjorn Helgaas 84819beac3SBjorn Helgaas if (list_empty(&dev->resources)) { 85819beac3SBjorn Helgaas dev_dbg(&dev->dev, "%s: no current resources\n", desc); 86819beac3SBjorn Helgaas return; 87819beac3SBjorn Helgaas } 88819beac3SBjorn Helgaas 89819beac3SBjorn Helgaas dev_dbg(&dev->dev, "%s: current resources:\n", desc); 90aee3ad81SBjorn Helgaas list_for_each_entry(pnp_res, &dev->resources, list) { 91aee3ad81SBjorn Helgaas res = &pnp_res->res; 9281b5c75fSBjorn Helgaas 93aee3ad81SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, " %-3s ", 94aee3ad81SBjorn Helgaas pnp_resource_type_name(res)); 95aee3ad81SBjorn Helgaas 96aee3ad81SBjorn Helgaas if (res->flags & IORESOURCE_DISABLED) { 97aee3ad81SBjorn Helgaas dev_dbg(&dev->dev, "%sdisabled\n", buf); 98aee3ad81SBjorn Helgaas continue; 9981b5c75fSBjorn Helgaas } 100aee3ad81SBjorn Helgaas 101aee3ad81SBjorn Helgaas switch (pnp_resource_type(res)) { 102aee3ad81SBjorn Helgaas case IORESOURCE_IO: 103aee3ad81SBjorn Helgaas case IORESOURCE_MEM: 104aee3ad81SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 105aee3ad81SBjorn Helgaas "%#llx-%#llx flags %#lx", 10681b5c75fSBjorn Helgaas (unsigned long long) res->start, 107aee3ad81SBjorn Helgaas (unsigned long long) res->end, 108aee3ad81SBjorn Helgaas res->flags); 109aee3ad81SBjorn Helgaas break; 110aee3ad81SBjorn Helgaas case IORESOURCE_IRQ: 111aee3ad81SBjorn Helgaas case IORESOURCE_DMA: 112aee3ad81SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 113aee3ad81SBjorn Helgaas "%lld flags %#lx", 11481b5c75fSBjorn Helgaas (unsigned long long) res->start, 115aee3ad81SBjorn Helgaas res->flags); 116aee3ad81SBjorn Helgaas break; 117aee3ad81SBjorn Helgaas } 118aee3ad81SBjorn Helgaas dev_dbg(&dev->dev, "%s\n", buf); 11981b5c75fSBjorn Helgaas } 12081b5c75fSBjorn Helgaas #endif 12181b5c75fSBjorn Helgaas } 122*1f32ca31SBjorn Helgaas 123*1f32ca31SBjorn Helgaas char *pnp_option_priority_name(struct pnp_option *option) 124*1f32ca31SBjorn Helgaas { 125*1f32ca31SBjorn Helgaas switch (pnp_option_priority(option)) { 126*1f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_PREFERRED: 127*1f32ca31SBjorn Helgaas return "preferred"; 128*1f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_ACCEPTABLE: 129*1f32ca31SBjorn Helgaas return "acceptable"; 130*1f32ca31SBjorn Helgaas case PNP_RES_PRIORITY_FUNCTIONAL: 131*1f32ca31SBjorn Helgaas return "functional"; 132*1f32ca31SBjorn Helgaas } 133*1f32ca31SBjorn Helgaas return "invalid"; 134*1f32ca31SBjorn Helgaas } 135*1f32ca31SBjorn Helgaas 136*1f32ca31SBjorn Helgaas void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option) 137*1f32ca31SBjorn Helgaas { 138*1f32ca31SBjorn Helgaas #ifdef DEBUG 139*1f32ca31SBjorn Helgaas char buf[128]; 140*1f32ca31SBjorn Helgaas int len = 0, i; 141*1f32ca31SBjorn Helgaas struct pnp_port *port; 142*1f32ca31SBjorn Helgaas struct pnp_mem *mem; 143*1f32ca31SBjorn Helgaas struct pnp_irq *irq; 144*1f32ca31SBjorn Helgaas struct pnp_dma *dma; 145*1f32ca31SBjorn Helgaas 146*1f32ca31SBjorn Helgaas if (pnp_option_is_dependent(option)) 147*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 148*1f32ca31SBjorn Helgaas " dependent set %d (%s) ", 149*1f32ca31SBjorn Helgaas pnp_option_set(option), 150*1f32ca31SBjorn Helgaas pnp_option_priority_name(option)); 151*1f32ca31SBjorn Helgaas else 152*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, " independent "); 153*1f32ca31SBjorn Helgaas 154*1f32ca31SBjorn Helgaas switch (option->type) { 155*1f32ca31SBjorn Helgaas case IORESOURCE_IO: 156*1f32ca31SBjorn Helgaas port = &option->u.port; 157*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, "io min %#llx " 158*1f32ca31SBjorn Helgaas "max %#llx align %lld size %lld flags %#x", 159*1f32ca31SBjorn Helgaas (unsigned long long) port->min, 160*1f32ca31SBjorn Helgaas (unsigned long long) port->max, 161*1f32ca31SBjorn Helgaas (unsigned long long) port->align, 162*1f32ca31SBjorn Helgaas (unsigned long long) port->size, port->flags); 163*1f32ca31SBjorn Helgaas break; 164*1f32ca31SBjorn Helgaas case IORESOURCE_MEM: 165*1f32ca31SBjorn Helgaas mem = &option->u.mem; 166*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, "mem min %#llx " 167*1f32ca31SBjorn Helgaas "max %#llx align %lld size %lld flags %#x", 168*1f32ca31SBjorn Helgaas (unsigned long long) mem->min, 169*1f32ca31SBjorn Helgaas (unsigned long long) mem->max, 170*1f32ca31SBjorn Helgaas (unsigned long long) mem->align, 171*1f32ca31SBjorn Helgaas (unsigned long long) mem->size, mem->flags); 172*1f32ca31SBjorn Helgaas break; 173*1f32ca31SBjorn Helgaas case IORESOURCE_IRQ: 174*1f32ca31SBjorn Helgaas irq = &option->u.irq; 175*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, "irq"); 176*1f32ca31SBjorn Helgaas if (bitmap_empty(irq->map.bits, PNP_IRQ_NR)) 177*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 178*1f32ca31SBjorn Helgaas " <none>"); 179*1f32ca31SBjorn Helgaas else { 180*1f32ca31SBjorn Helgaas for (i = 0; i < PNP_IRQ_NR; i++) 181*1f32ca31SBjorn Helgaas if (test_bit(i, irq->map.bits)) 182*1f32ca31SBjorn Helgaas len += snprintf(buf + len, 183*1f32ca31SBjorn Helgaas sizeof(buf) - len, 184*1f32ca31SBjorn Helgaas " %d", i); 185*1f32ca31SBjorn Helgaas } 186*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, " flags %#x", 187*1f32ca31SBjorn Helgaas irq->flags); 188*1f32ca31SBjorn Helgaas if (irq->flags & IORESOURCE_IRQ_OPTIONAL) 189*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 190*1f32ca31SBjorn Helgaas " (optional)"); 191*1f32ca31SBjorn Helgaas break; 192*1f32ca31SBjorn Helgaas case IORESOURCE_DMA: 193*1f32ca31SBjorn Helgaas dma = &option->u.dma; 194*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, "dma"); 195*1f32ca31SBjorn Helgaas if (!dma->map) 196*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, 197*1f32ca31SBjorn Helgaas " <none>"); 198*1f32ca31SBjorn Helgaas else { 199*1f32ca31SBjorn Helgaas for (i = 0; i < 8; i++) 200*1f32ca31SBjorn Helgaas if (dma->map & (1 << i)) 201*1f32ca31SBjorn Helgaas len += snprintf(buf + len, 202*1f32ca31SBjorn Helgaas sizeof(buf) - len, 203*1f32ca31SBjorn Helgaas " %d", i); 204*1f32ca31SBjorn Helgaas } 205*1f32ca31SBjorn Helgaas len += snprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) " 206*1f32ca31SBjorn Helgaas "flags %#x", dma->map, dma->flags); 207*1f32ca31SBjorn Helgaas break; 208*1f32ca31SBjorn Helgaas } 209*1f32ca31SBjorn Helgaas dev_dbg(&dev->dev, "%s\n", buf); 210*1f32ca31SBjorn Helgaas #endif 211*1f32ca31SBjorn Helgaas } 212