linux/drivers/pcmcia/pcmcia_resource.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * PCMCIA 16-bit resource management functions
 *
 * The initial developer of the original code is David A. Hinds
 * <[email protected]>.  Portions created by David A. Hinds
 * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 *
 * Copyright (C) 1999	     David A. Hinds
 * Copyright (C) 2004-2010   Dominik Brodowski
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/slab.h>

#include <asm/irq.h>

#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>

#include "cs_internal.h"


/* Access speed for IO windows */
static int io_speed;
module_param(io_speed, int, 0444);


int pcmcia_validate_mem(struct pcmcia_socket *s)
{}

struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
				 int low, struct pcmcia_socket *s)
{}


/**
 * release_io_space() - release IO ports allocated with alloc_io_space()
 * @s: pcmcia socket
 * @res: resource to release
 *
 */
static void release_io_space(struct pcmcia_socket *s, struct resource *res)
{}


/**
 * alloc_io_space() - allocate IO ports for use by a PCMCIA device
 * @s: pcmcia socket
 * @res: resource to allocate (begin: begin, end: size)
 * @lines: number of IO lines decoded by the PCMCIA card
 *
 * Special stuff for managing IO windows, because they are scarce
 */
static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
			unsigned int lines)
{}


/*
 * pcmcia_access_config() - read or write card configuration registers
 *
 * pcmcia_access_config() reads and writes configuration registers in
 * attribute memory.  Memory window 0 is reserved for this and the tuple
 * reading services. Drivers must use pcmcia_read_config_byte() or
 * pcmcia_write_config_byte().
 */
static int pcmcia_access_config(struct pcmcia_device *p_dev,
				off_t where, u8 *val,
				int (*accessf) (struct pcmcia_socket *s,
						int attr, unsigned int addr,
						unsigned int len, void *ptr))
{}


/*
 * pcmcia_read_config_byte() - read a byte from a card configuration register
 *
 * pcmcia_read_config_byte() reads a byte from a configuration register in
 * attribute memory.
 */
int pcmcia_read_config_byte(struct pcmcia_device *p_dev, off_t where, u8 *val)
{}
EXPORT_SYMBOL();


/*
 * pcmcia_write_config_byte() - write a byte to a card configuration register
 *
 * pcmcia_write_config_byte() writes a byte to a configuration register in
 * attribute memory.
 */
int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val)
{}
EXPORT_SYMBOL();


/**
 * pcmcia_map_mem_page() - modify iomem window to point to a different offset
 * @p_dev: pcmcia device
 * @res: iomem resource already enabled by pcmcia_request_window()
 * @offset: card_offset to map
 *
 * pcmcia_map_mem_page() modifies what can be read and written by accessing
 * an iomem range previously enabled by pcmcia_request_window(), by setting
 * the card_offset value to @offset.
 */
int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res,
			unsigned int offset)
{}
EXPORT_SYMBOL();


/**
 * pcmcia_fixup_iowidth() - reduce io width to 8bit
 * @p_dev: pcmcia device
 *
 * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the
 * IO width to 8bit after having called pcmcia_enable_device()
 * previously.
 */
int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev)
{}
EXPORT_SYMBOL();


/**
 * pcmcia_fixup_vpp() - set Vpp to a new voltage level
 * @p_dev: pcmcia device
 * @new_vpp: new Vpp voltage
 *
 * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to
 * a new voltage level between calls to pcmcia_enable_device()
 * and pcmcia_disable_device().
 */
int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp)
{}
EXPORT_SYMBOL();


/**
 * pcmcia_release_configuration() - physically disable a PCMCIA device
 * @p_dev: pcmcia device
 *
 * pcmcia_release_configuration() is the 1:1 counterpart to
 * pcmcia_enable_device(): If a PCMCIA device is no longer used by any
 * driver, the Vpp voltage is set to 0, IRQs will no longer be generated,
 * and I/O ranges will be disabled. As pcmcia_release_io() and
 * pcmcia_release_window() still need to be called, device drivers are
 * expected to call pcmcia_disable_device() instead.
 */
int pcmcia_release_configuration(struct pcmcia_device *p_dev)
{}


/**
 * pcmcia_release_io() - release I/O allocated by a PCMCIA device
 * @p_dev: pcmcia device
 *
 * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA
 * device.  This may be invoked some time after a card ejection has
 * already dumped the actual socket configuration, so if the client is
 * "stale", we don't bother checking the port ranges against the
 * current socket values.
 */
static void pcmcia_release_io(struct pcmcia_device *p_dev)
{} /* pcmcia_release_io */


/**
 * pcmcia_release_window() - release reserved iomem for PCMCIA devices
 * @p_dev: pcmcia device
 * @res: iomem resource to release
 *
 * pcmcia_release_window() releases &struct resource *res which was
 * previously reserved by calling pcmcia_request_window().
 */
int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
{} /* pcmcia_release_window */
EXPORT_SYMBOL();


/**
 * pcmcia_enable_device() - set up and activate a PCMCIA device
 * @p_dev: the associated PCMCIA device
 *
 * pcmcia_enable_device() physically enables a PCMCIA device. It parses
 * the flags passed to in @flags and stored in @p_dev->flags and sets up
 * the Vpp voltage, enables the speaker line, I/O ports and store proper
 * values to configuration registers.
 */
int pcmcia_enable_device(struct pcmcia_device *p_dev)
{} /* pcmcia_enable_device */
EXPORT_SYMBOL();


/**
 * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
 * @p_dev: the associated PCMCIA device
 *
 * pcmcia_request_io() attempts to reserve the IO port ranges specified in
 * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The
 * "start" value is the requested start of the IO port resource; "end"
 * reflects the number of ports requested. The number of IO lines requested
 * is specified in &struct pcmcia_device @p_dev->io_lines.
 */
int pcmcia_request_io(struct pcmcia_device *p_dev)
{} /* pcmcia_request_io */
EXPORT_SYMBOL();


/**
 * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device
 * @p_dev: the associated PCMCIA device
 * @handler: IRQ handler to register
 *
 * pcmcia_request_irq() is a wrapper around request_irq() which allows
 * the PCMCIA core to clean up the registration in pcmcia_disable_device().
 * Drivers are free to use request_irq() directly, but then they need to
 * call free_irq() themselves, too. Also, only %IRQF_SHARED capable IRQ
 * handlers are allowed.
 */
int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
				    irq_handler_t handler)
{}
EXPORT_SYMBOL();


#ifdef CONFIG_PCMCIA_PROBE

/* mask of IRQs already reserved by other cards, we should avoid using them */
static u8 pcmcia_used_irq[32];

static irqreturn_t test_action(int cpl, void *dev_id)
{
	return IRQ_NONE;
}

/**
 * pcmcia_setup_isa_irq() - determine whether an ISA IRQ can be used
 * @p_dev: the associated PCMCIA device
 * @type:  IRQ type (flags)
 *
 * locking note: must be called with ops_mutex locked.
 */
static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
{
	struct pcmcia_socket *s = p_dev->socket;
	unsigned int try, irq;
	u32 mask = s->irq_mask;
	int ret = -ENODEV;

	for (try = 0; try < 64; try++) {
		irq = try % 32;

		if (irq > NR_IRQS)
			continue;

		/* marked as available by driver, not blocked by userspace? */
		if (!((mask >> irq) & 1))
			continue;

		/* avoid an IRQ which is already used by another PCMCIA card */
		if ((try < 32) && pcmcia_used_irq[irq])
			continue;

		/* register the correct driver, if possible, to check whether
		 * registering a dummy handle works, i.e. if the IRQ isn't
		 * marked as used by the kernel resource management core */
		ret = request_irq(irq, test_action, type, p_dev->devname,
				  p_dev);
		if (!ret) {
			free_irq(irq, p_dev);
			p_dev->irq = s->pcmcia_irq = irq;
			pcmcia_used_irq[irq]++;
			break;
		}
	}

	return ret;
}

void pcmcia_cleanup_irq(struct pcmcia_socket *s)
{
	pcmcia_used_irq[s->pcmcia_irq]--;
	s->pcmcia_irq = 0;
}

#else /* CONFIG_PCMCIA_PROBE */

static int pcmcia_setup_isa_irq(struct pcmcia_device *p_dev, int type)
{}

void pcmcia_cleanup_irq(struct pcmcia_socket *s)
{}

#endif  /* CONFIG_PCMCIA_PROBE */


/**
 * pcmcia_setup_irq() - determine IRQ to be used for device
 * @p_dev: the associated PCMCIA device
 *
 * locking note: must be called with ops_mutex locked.
 */
int pcmcia_setup_irq(struct pcmcia_device *p_dev)
{}


/**
 * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices
 * @p_dev: the associated PCMCIA device
 * @res: &struct resource pointing to p_dev->resource[2..5]
 * @speed: access speed
 *
 * pcmcia_request_window() attepts to reserve an iomem ranges specified in
 * &struct resource @res pointing to one of the entries in
 * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the
 * requested start of the IO mem resource; "end" reflects the size
 * requested.
 */
int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res,
			unsigned int speed)
{} /* pcmcia_request_window */
EXPORT_SYMBOL();


/**
 * pcmcia_disable_device() - disable and clean up a PCMCIA device
 * @p_dev: the associated PCMCIA device
 *
 * pcmcia_disable_device() is the driver-callable counterpart to
 * pcmcia_enable_device(): If a PCMCIA device is no longer used,
 * drivers are expected to clean up and disable the device by calling
 * this function. Any I/O ranges (iomem and ioports) will be released,
 * the Vpp voltage will be set to 0, and IRQs will no longer be
 * generated -- at least if there is no other card function (of
 * multifunction devices) being used.
 */
void pcmcia_disable_device(struct pcmcia_device *p_dev)
{}
EXPORT_SYMBOL();