179 lines · 4.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * support.c - standard functions for the use of pnp protocol drivers * * 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/module.h>#include <linux/ctype.h>#include <linux/hex.h>#include <linux/pnp.h>#include "base.h" /** * pnp_is_active - Determines if a device is active based on its current *	resources * @dev: pointer to the desired PnP device */int pnp_is_active(struct pnp_dev *dev){	/*	 * I don't think this is very reliable because pnp_disable_dev()	 * only clears out auto-assigned resources.	 */	if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&	    !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&	    pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)		return 0;	else		return 1;}EXPORT_SYMBOL(pnp_is_active); /* * Functionally similar to acpi_ex_eisa_id_to_string(), but that's * buried in the ACPI CA, and we can't depend on it being present. */void pnp_eisa_id_to_string(u32 id, char *str){	id = be32_to_cpu(id); 	/*	 * According to the specs, the first three characters are five-bit	 * compressed ASCII, and the left-over high order bit should be zero.	 * However, the Linux ISAPNP code historically used six bits for the	 * first character, and there seem to be IDs that depend on that,	 * e.g., "nEC8241" in the Linux 8250_pnp serial driver and the	 * FreeBSD sys/pc98/cbus/sio_cbus.c driver.	 */	str[0] = 'A' + ((id >> 26) & 0x3f) - 1;	str[1] = 'A' + ((id >> 21) & 0x1f) - 1;	str[2] = 'A' + ((id >> 16) & 0x1f) - 1;	str[3] = hex_asc_hi(id >> 8);	str[4] = hex_asc_lo(id >> 8);	str[5] = hex_asc_hi(id);	str[6] = hex_asc_lo(id);	str[7] = '\0';} char *pnp_resource_type_name(struct resource *res){	switch (pnp_resource_type(res)) {	case IORESOURCE_IO:		return "io";	case IORESOURCE_MEM:		return "mem";	case IORESOURCE_IRQ:		return "irq";	case IORESOURCE_DMA:		return "dma";	case IORESOURCE_BUS:		return "bus";	}	return "unknown";} void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc){	struct pnp_resource *pnp_res; 	if (list_empty(&dev->resources))		pnp_dbg(&dev->dev, "%s: no current resources\n", desc);	else {		pnp_dbg(&dev->dev, "%s: current resources:\n", desc);		list_for_each_entry(pnp_res, &dev->resources, list)			pnp_dbg(&dev->dev, "%pr\n", &pnp_res->res);	}} char *pnp_option_priority_name(struct pnp_option *option){	switch (pnp_option_priority(option)) {	case PNP_RES_PRIORITY_PREFERRED:		return "preferred";	case PNP_RES_PRIORITY_ACCEPTABLE:		return "acceptable";	case PNP_RES_PRIORITY_FUNCTIONAL:		return "functional";	}	return "invalid";} void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option){	char buf[128];	int len = 0, i;	struct pnp_port *port;	struct pnp_mem *mem;	struct pnp_irq *irq;	struct pnp_dma *dma; 	if (pnp_option_is_dependent(option))		len += scnprintf(buf + len, sizeof(buf) - len,				 "  dependent set %d (%s) ",				 pnp_option_set(option),				 pnp_option_priority_name(option));	else		len += scnprintf(buf + len, sizeof(buf) - len,				 "  independent "); 	switch (option->type) {	case IORESOURCE_IO:		port = &option->u.port;		len += scnprintf(buf + len, sizeof(buf) - len, "io  min %#llx "				 "max %#llx align %lld size %lld flags %#x",				 (unsigned long long) port->min,				 (unsigned long long) port->max,				 (unsigned long long) port->align,				 (unsigned long long) port->size, port->flags);		break;	case IORESOURCE_MEM:		mem = &option->u.mem;		len += scnprintf(buf + len, sizeof(buf) - len, "mem min %#llx "				 "max %#llx align %lld size %lld flags %#x",				 (unsigned long long) mem->min,				 (unsigned long long) mem->max,				 (unsigned long long) mem->align,				 (unsigned long long) mem->size, mem->flags);		break;	case IORESOURCE_IRQ:		irq = &option->u.irq;		len += scnprintf(buf + len, sizeof(buf) - len, "irq");		if (bitmap_empty(irq->map.bits, PNP_IRQ_NR))			len += scnprintf(buf + len, sizeof(buf) - len,					 " <none>");		else {			for (i = 0; i < PNP_IRQ_NR; i++)				if (test_bit(i, irq->map.bits))					len += scnprintf(buf + len,							 sizeof(buf) - len,							 " %d", i);		}		len += scnprintf(buf + len, sizeof(buf) - len, " flags %#x",				 irq->flags);		if (irq->flags & IORESOURCE_IRQ_OPTIONAL)			len += scnprintf(buf + len, sizeof(buf) - len,					 " (optional)");		break;	case IORESOURCE_DMA:		dma = &option->u.dma;		len += scnprintf(buf + len, sizeof(buf) - len, "dma");		if (!dma->map)			len += scnprintf(buf + len, sizeof(buf) - len,					 " <none>");		else {			for (i = 0; i < 8; i++)				if (dma->map & (1 << i))					len += scnprintf(buf + len,							 sizeof(buf) - len,							 " %d", i);		}		len += scnprintf(buf + len, sizeof(buf) - len, " (bitmask %#x) "				 "flags %#x", dma->map, dma->flags);		break;	}	pnp_dbg(&dev->dev, "%s\n", buf);}