// 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(…);