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