Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/ipmi/ipmi_si_port_io.c
26282 views
1
// SPDX-License-Identifier: GPL-2.0+
2
3
#include <linux/io.h>
4
#include "ipmi_si.h"
5
6
static 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
13
static 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
21
static 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
28
static 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
36
static 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
43
static 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
51
static 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
63
int 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
}
115
116