File Index
Files and directories
Sign in
FILE

ipmi_si_port_io.c

File preview with syntax highlighting.

linux-6.19.14/drivers/char/ipmi/ipmi_si_port_io.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2
  3#include <linux/io.h>
  4#include "ipmi_si.h"
  5
  6static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset)
  7{
  8	unsigned int addr = io->addr_data;
  9
 10	return inb(addr + (offset * io->regspacing));
 11}
 12
 13static void port_outb(const struct si_sm_io *io, unsigned int offset,
 14		      unsigned char b)
 15{
 16	unsigned int addr = io->addr_data;
 17
 18	outb(b, addr + (offset * io->regspacing));
 19}
 20
 21static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset)
 22{
 23	unsigned int addr = io->addr_data;
 24
 25	return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
 26}
 27
 28static void port_outw(const struct si_sm_io *io, unsigned int offset,
 29		      unsigned char b)
 30{
 31	unsigned int addr = io->addr_data;
 32
 33	outw(b << io->regshift, addr + (offset * io->regspacing));
 34}
 35
 36static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset)
 37{
 38	unsigned int addr = io->addr_data;
 39
 40	return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff;
 41}
 42
 43static void port_outl(const struct si_sm_io *io, unsigned int offset,
 44		      unsigned char b)
 45{
 46	unsigned int addr = io->addr_data;
 47
 48	outl(b << io->regshift, addr+(offset * io->regspacing));
 49}
 50
 51static void port_cleanup(struct si_sm_io *io)
 52{
 53	unsigned int addr = io->addr_data;
 54	int          idx;
 55
 56	if (addr) {
 57		for (idx = 0; idx < io->io_size; idx++)
 58			release_region(addr + idx * io->regspacing,
 59				       io->regsize);
 60	}
 61}
 62
 63int ipmi_si_port_setup(struct si_sm_io *io)
 64{
 65	unsigned int addr = io->addr_data;
 66	int          idx;
 67
 68	if (!addr)
 69		return -ENODEV;
 70
 71	/*
 72	 * Figure out the actual inb/inw/inl/etc routine to use based
 73	 * upon the register size.
 74	 */
 75	switch (io->regsize) {
 76	case 1:
 77		io->inputb = port_inb;
 78		io->outputb = port_outb;
 79		break;
 80	case 2:
 81		io->inputb = port_inw;
 82		io->outputb = port_outw;
 83		break;
 84	case 4:
 85		io->inputb = port_inl;
 86		io->outputb = port_outl;
 87		break;
 88	default:
 89		dev_warn(io->dev, "Invalid register size: %d\n",
 90			 io->regsize);
 91		return -EINVAL;
 92	}
 93
 94	/*
 95	 * Some BIOSes reserve disjoint I/O regions in their ACPI
 96	 * tables.  This causes problems when trying to register the
 97	 * entire I/O region.  Therefore we must register each I/O
 98	 * port separately.
 99	 */
100	for (idx = 0; idx < io->io_size; idx++) {
101		if (request_region(addr + idx * io->regspacing,
102				   io->regsize, SI_DEVICE_NAME) == NULL) {
103			/* Undo allocations */
104			while (idx--)
105				release_region(addr + idx * io->regspacing,
106					       io->regsize);
107			return -EIO;
108		}
109	}
110
111	io->io_cleanup = port_cleanup;
112
113	return 0;
114}
~/ Read-only file preview.