pmh7tool.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <getopt.h> 6 #include <sys/io.h> 7 #include <errno.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <stdint.h> 11 #include "pmh7tool.h" 12 13 uint8_t pmh7_register_read(uint16_t reg) 14 { 15 outb(reg & 0xff, EC_LENOVO_PMH7_ADDR_L); 16 outb((reg & 0xff00) >> 8, EC_LENOVO_PMH7_ADDR_H); 17 return inb(EC_LENOVO_PMH7_DATA); 18 } 19 20 void pmh7_register_write(uint16_t reg, uint8_t val) 21 { 22 outb(reg & 0xff, EC_LENOVO_PMH7_ADDR_L); 23 outb((reg & 0xff00) >> 8, EC_LENOVO_PMH7_ADDR_H); 24 outb(val, EC_LENOVO_PMH7_DATA); 25 } 26 27 void pmh7_register_set_bit(uint16_t reg, uint8_t bit) 28 { 29 uint8_t val; 30 31 val = pmh7_register_read(reg); 32 pmh7_register_write(reg, val | (1 << bit)); 33 } 34 35 void pmh7_register_clear_bit(uint16_t reg, uint8_t bit) 36 { 37 uint8_t val; 38 39 val = pmh7_register_read(reg); 40 pmh7_register_write(reg, val & ~(1 << bit)); 41 } 42 43 uint8_t pmh7_register_read_bit(int16_t reg, uint8_t bit) 44 { 45 uint8_t val; 46 47 val = pmh7_register_read(reg); 48 return (val >> bit) & 1; 49 } 50 51 void print_usage(const char *name) 52 { 53 printf("usage: %s\n", name); 54 printf("\n" 55 " -h, --help: print this help\n" 56 " -d, --dump: print registers\n" 57 " -w, --write <addr> <data>: write to register\n" 58 " -r, --read <addr>: read from register\n" 59 " -b, --read-bit <addr> <bit> read bit\n" 60 " -c, --clear-bit <addr> <bit> clear bit\n" 61 " -s, --set-bit <addr> <bit> set bit\n" 62 "\n" 63 "Attention! Writing to PMH7 registers is very dangerous, as you\n" 64 " directly manipulate the power rails, enable lines,\n" 65 " interrupt lines or something else of the device.\n" 66 " Proceed with caution." 67 "\n"); 68 } 69 70 enum action {HELP, DUMP, WRITE, READ, READBIT, CLEAR, SET}; 71 72 int main(int argc, char *argv[]) 73 { 74 enum action act = HELP; 75 int opt, option_index = 0; 76 long input_addr = 0, input_data = 0; 77 78 static struct option long_options[] = { 79 {"help", 0, 0, 'h'}, 80 {"dump", 0, 0, 'd'}, 81 {"write", 1, 0, 'w'}, 82 {"read", 1, 0, 'r'}, 83 {"read-bit", 1, 0, 'b'}, 84 {"clear-bit", 1, 0, 'c'}, 85 {"set-bit", 1, 0, 's'}, 86 {0, 0, 0, 0} 87 }; 88 89 if (argv[1] == NULL) { 90 print_usage(argv[0]); 91 exit(0); 92 } 93 94 while ((opt = getopt_long(argc, argv, "hdw:r:c:s:b:", 95 long_options, &option_index)) != EOF) { 96 switch (opt) { 97 case 'd': 98 act = DUMP; 99 break; 100 101 case 'r': 102 input_addr = strtoul(optarg, NULL, 16); 103 act = READ; 104 break; 105 106 case 'w': 107 case 'b': 108 case 'c': 109 case 's': 110 input_addr = strtoul(optarg, NULL, 16); 111 112 if (optind < argc && *argv[optind] != '-') { 113 input_data = strtoul(argv[optind], NULL, 16); 114 optind++; 115 } else { 116 fprintf(stderr, 117 "Error: -%c option requires two arguments\n", 118 opt); 119 exit(1); 120 } 121 122 switch (opt) { 123 case 'w': 124 act = WRITE; 125 break; 126 case 'b': 127 act = READBIT; 128 break; 129 case 'c': 130 act = CLEAR; 131 break; 132 case 's': 133 act = SET; 134 break; 135 } 136 break; 137 } 138 } 139 140 if (optind < argc) { 141 fprintf(stderr, "Error: Extra parameter found.\n"); 142 print_usage(argv[0]); 143 exit(1); 144 } 145 146 if (act == HELP) { 147 print_usage(argv[0]); 148 exit(0); 149 } 150 151 if (input_addr > 0x1ff) { 152 fprintf(stderr, 153 "Error: <addr> cannot be greater than 9 bits long.\n"); 154 exit(1); 155 } 156 157 if (act == SET || act == CLEAR || act == READBIT) { 158 if (input_data > 7) { 159 fprintf(stderr, 160 "Error: <bit> cannot be greater than 7.\n"); 161 exit(1); 162 } 163 } else { 164 if (input_data > 0xff) { 165 fprintf(stderr, 166 "Error: <data> cannot be greater than 8 bits long.\n"); 167 exit(1); 168 } 169 } 170 171 if (geteuid() != 0) { 172 fprintf(stderr, "You must be root.\n"); 173 exit(1); 174 } 175 176 if (ioperm(EC_LENOVO_PMH7_BASE, 0x10, 1)) { 177 fprintf(stderr, "ioperm: %s\n", strerror(errno)); 178 exit(1); 179 } 180 181 switch (act) { 182 case DUMP: 183 for (int i = 0; i < 0x200; i++) { 184 if ((i % 0x10) == 0) { 185 if (i != 0) 186 printf("\n"); 187 printf("%04x: ", i); 188 } 189 printf("%02x ", pmh7_register_read(i)); 190 } 191 printf("\n"); 192 break; 193 194 case READ: 195 printf("%02x\n", pmh7_register_read(input_addr)); 196 break; 197 198 case WRITE: 199 pmh7_register_write(input_addr, input_data); 200 break; 201 202 case READBIT: 203 printf("%d\n", pmh7_register_read_bit(input_addr, input_data)); 204 break; 205 206 case CLEAR: 207 pmh7_register_clear_bit(input_addr, input_data); 208 break; 209 210 case SET: 211 pmh7_register_set_bit(input_addr, input_data); 212 break; 213 214 default: 215 break; 216 } 217 218 return 0; 219 }