1 1.39 andvar /* $NetBSD: pm_direct.c,v 1.39 2024/06/02 13:28:46 andvar Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /* 4 1.1 tsubai * Copyright (C) 1997 Takashi Hamada 5 1.1 tsubai * All rights reserved. 6 1.1 tsubai * 7 1.1 tsubai * Redistribution and use in source and binary forms, with or without 8 1.1 tsubai * modification, are permitted provided that the following conditions 9 1.1 tsubai * are met: 10 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 11 1.1 tsubai * notice, this list of conditions and the following disclaimer. 12 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 14 1.1 tsubai * documentation and/or other materials provided with the distribution. 15 1.1 tsubai * 3. All advertising materials mentioning features or use of this software 16 1.1 tsubai * must display the following acknowledgement: 17 1.1 tsubai * This product includes software developed by Takashi Hamada 18 1.1 tsubai * 4. The name of the author may not be used to endorse or promote products 19 1.1 tsubai * derived from this software without specific prior written permission. 20 1.1 tsubai * 21 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 1.1 tsubai */ 32 1.1 tsubai /* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ 33 1.20 lukem 34 1.21 briggs /* 35 1.21 briggs * TODO : Check bounds on PMData in pmgrop 36 1.21 briggs * callers should specify how much room for data is in the buffer 37 1.21 briggs * and that should be respected by the pmgrop 38 1.21 briggs */ 39 1.21 briggs 40 1.20 lukem #include <sys/cdefs.h> 41 1.39 andvar __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.39 2024/06/02 13:28:46 andvar Exp $"); 42 1.1 tsubai 43 1.1 tsubai #ifdef DEBUG 44 1.1 tsubai #ifndef ADB_DEBUG 45 1.1 tsubai #define ADB_DEBUG 46 1.1 tsubai #endif 47 1.1 tsubai #endif 48 1.1 tsubai 49 1.1 tsubai /* #define PM_GRAB_SI 1 */ 50 1.1 tsubai 51 1.1 tsubai #include <sys/param.h> 52 1.1 tsubai #include <sys/device.h> 53 1.1 tsubai #include <sys/systm.h> 54 1.1 tsubai 55 1.1 tsubai #include <machine/adbsys.h> 56 1.23 briggs #include <machine/autoconf.h> 57 1.1 tsubai #include <machine/cpu.h> 58 1.32 garbled #include <machine/pio.h> 59 1.1 tsubai 60 1.23 briggs #include <dev/ofw/openfirm.h> 61 1.23 briggs 62 1.1 tsubai #include <macppc/dev/adbvar.h> 63 1.1 tsubai #include <macppc/dev/pm_direct.h> 64 1.1 tsubai #include <macppc/dev/viareg.h> 65 1.1 tsubai 66 1.1 tsubai extern int adb_polling; /* Are we polling? (Debugger mode) */ 67 1.1 tsubai 68 1.1 tsubai /* hardware dependent values */ 69 1.1 tsubai #define ADBDelay 100 /* XXX */ 70 1.1 tsubai 71 1.1 tsubai /* useful macros */ 72 1.1 tsubai #define PM_SR() read_via_reg(VIA1, vSR) 73 1.1 tsubai #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90) 74 1.1 tsubai #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10) 75 1.1 tsubai #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90) 76 1.25 briggs 77 1.1 tsubai #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10) 78 1.1 tsubai #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10) 79 1.1 tsubai #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08)) 80 1.1 tsubai #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08)) 81 1.1 tsubai 82 1.1 tsubai /* 83 1.1 tsubai * Variables for internal use 84 1.1 tsubai */ 85 1.1 tsubai u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 86 1.1 tsubai u_int pm_LCD_brightness = 0x0; 87 1.1 tsubai u_int pm_LCD_contrast = 0x0; 88 1.1 tsubai u_int pm_counter = 0; /* clock count */ 89 1.1 tsubai 90 1.23 briggs static enum batt_type { BATT_COMET, BATT_HOOPER, BATT_SMART } pmu_batt_type; 91 1.23 briggs static int pmu_nbatt; 92 1.27 nathanw static int strinlist(const char *, char *, int); 93 1.23 briggs static enum pmu_type { PMU_UNKNOWN, PMU_OHARE, PMU_G3, PMU_KEYLARGO } pmu_type; 94 1.23 briggs 95 1.1 tsubai /* these values shows that number of data returned after 'send' cmd is sent */ 96 1.1 tsubai signed char pm_send_cmd_type[] = { 97 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 98 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 99 1.1 tsubai 0x01, 0x01, -1, -1, -1, -1, -1, -1, 100 1.1 tsubai 0x00, 0x00, -1, -1, -1, -1, -1, 0x00, 101 1.1 tsubai -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1, 102 1.1 tsubai 0x00, -1, -1, -1, -1, -1, -1, -1, 103 1.5 tsubai 0x04, 0x14, -1, 0x03, -1, -1, -1, -1, 104 1.5 tsubai 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1, 105 1.1 tsubai 0x01, 0x01, -1, -1, -1, -1, -1, -1, 106 1.7 tsubai 0x00, 0x00, -1, -1, 0x01, -1, -1, -1, 107 1.1 tsubai 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01, 108 1.1 tsubai 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1, 109 1.1 tsubai 0x02, -1, -1, -1, -1, -1, -1, -1, 110 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1, 111 1.1 tsubai 0x01, 0x01, 0x01, -1, -1, -1, -1, -1, 112 1.1 tsubai 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04, 113 1.1 tsubai 0x04, -1, 0x00, -1, -1, -1, -1, -1, 114 1.1 tsubai 0x00, -1, -1, -1, -1, -1, -1, -1, 115 1.1 tsubai 0x01, 0x02, -1, -1, -1, -1, -1, -1, 116 1.1 tsubai 0x00, 0x00, -1, -1, -1, -1, -1, -1, 117 1.1 tsubai 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1, 118 1.1 tsubai 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1, 119 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 120 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 121 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 122 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 123 1.1 tsubai 0x00, -1, -1, -1, -1, -1, -1, -1, 124 1.1 tsubai 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1, 125 1.1 tsubai -1, 0x04, 0x00, -1, -1, -1, -1, -1, 126 1.1 tsubai 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00, 127 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 128 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1 129 1.1 tsubai }; 130 1.1 tsubai 131 1.1 tsubai /* these values shows that number of data returned after 'receive' cmd is sent */ 132 1.1 tsubai signed char pm_receive_cmd_type[] = { 133 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 135 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 1.1 tsubai 0x02, 0x02, -1, -1, -1, -1, -1, 0x00, 137 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 139 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 1.5 tsubai 0x05, 0x15, -1, 0x02, -1, -1, -1, -1, 141 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 1.1 tsubai 0x02, 0x02, -1, -1, -1, -1, -1, -1, 143 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 1.1 tsubai 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1, 145 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 1.1 tsubai 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1, 147 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 1.1 tsubai -1, -1, -1, -1, -1, -1, 0x01, 0x01, 149 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 1.1 tsubai 0x06, -1, -1, -1, -1, -1, -1, -1, 151 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 1.1 tsubai 0x02, 0x02, -1, -1, -1, -1, -1, -1, 153 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 1.1 tsubai 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1, 155 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 157 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 159 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 1.1 tsubai 0x02, 0x02, -1, -1, 0x02, -1, -1, -1, 161 1.1 tsubai 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 162 1.1 tsubai -1, -1, 0x02, -1, -1, -1, -1, 0x00, 163 1.1 tsubai 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 1.1 tsubai -1, -1, -1, -1, -1, -1, -1, -1, 165 1.1 tsubai }; 166 1.1 tsubai 167 1.1 tsubai 168 1.1 tsubai /* 169 1.1 tsubai * Define the private functions 170 1.1 tsubai */ 171 1.1 tsubai 172 1.1 tsubai /* for debugging */ 173 1.1 tsubai #ifdef ADB_DEBUG 174 1.34 dsl void pm_printerr(const char *, int, int, const char *); 175 1.1 tsubai #endif 176 1.1 tsubai 177 1.34 dsl int pm_wait_busy(int); 178 1.34 dsl int pm_wait_free(int); 179 1.1 tsubai 180 1.34 dsl static int pm_receive(u_char *); 181 1.34 dsl static int pm_send(u_char); 182 1.1 tsubai 183 1.1 tsubai /* these functions are called from adb_direct.c */ 184 1.34 dsl void pm_setup_adb(void); 185 1.34 dsl void pm_check_adb_devices(int); 186 1.34 dsl int pm_adb_op(u_char *, adbComp *, volatile int *, int); 187 1.1 tsubai 188 1.1 tsubai /* these functions also use the variables of adb_direct.c */ 189 1.34 dsl void pm_adb_get_TALK_result(PMData *); 190 1.34 dsl void pm_adb_get_ADB_data(PMData *); 191 1.1 tsubai 192 1.1 tsubai 193 1.1 tsubai /* 194 1.1 tsubai * These variables are in adb_direct.c. 195 1.1 tsubai */ 196 1.1 tsubai extern u_char *adbBuffer; /* pointer to user data area */ 197 1.27 nathanw extern adbComp *adbCompRout; /* pointer to the completion routine */ 198 1.27 nathanw extern volatile int *adbCompData; /* pointer to the completion routine data */ 199 1.1 tsubai extern int adbWaiting; /* waiting for return data from the device */ 200 1.1 tsubai extern int adbWaitingCmd; /* ADB command we are waiting for */ 201 1.1 tsubai extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 202 1.1 tsubai 203 1.1 tsubai #define ADB_MAX_MSG_LENGTH 16 204 1.1 tsubai #define ADB_MAX_HDR_LENGTH 8 205 1.1 tsubai struct adbCommand { 206 1.1 tsubai u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 207 1.1 tsubai u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 208 1.1 tsubai u_char *saveBuf; /* where to save result */ 209 1.27 nathanw adbComp *compRout; /* completion routine pointer */ 210 1.27 nathanw volatile int *compData; /* completion routine data pointer */ 211 1.1 tsubai u_int cmd; /* the original command for this data */ 212 1.1 tsubai u_int unsol; /* 1 if packet was unsolicited */ 213 1.1 tsubai u_int ack_only; /* 1 for no special processing */ 214 1.1 tsubai }; 215 1.34 dsl extern void adb_pass_up(struct adbCommand *); 216 1.1 tsubai 217 1.1 tsubai #if 0 218 1.1 tsubai /* 219 1.1 tsubai * Define the external functions 220 1.1 tsubai */ 221 1.34 dsl extern int zshard(int); /* from zs.c */ 222 1.1 tsubai #endif 223 1.1 tsubai 224 1.1 tsubai #ifdef ADB_DEBUG 225 1.1 tsubai /* 226 1.1 tsubai * This function dumps contents of the PMData 227 1.1 tsubai */ 228 1.1 tsubai void 229 1.35 dsl pm_printerr(const char *ttl, int rval, int num, const char *data) 230 1.1 tsubai { 231 1.1 tsubai int i; 232 1.1 tsubai 233 1.1 tsubai printf("pm: %s:%04x %02x ", ttl, rval, num); 234 1.1 tsubai for (i = 0; i < num; i++) 235 1.1 tsubai printf("%02x ", data[i]); 236 1.1 tsubai printf("\n"); 237 1.1 tsubai } 238 1.1 tsubai #endif 239 1.1 tsubai 240 1.1 tsubai 241 1.1 tsubai 242 1.1 tsubai /* 243 1.1 tsubai * Check the hardware type of the Power Manager 244 1.1 tsubai */ 245 1.1 tsubai void 246 1.37 cegger pm_setup_adb(void) 247 1.1 tsubai { 248 1.1 tsubai } 249 1.1 tsubai 250 1.26 briggs /* 251 1.26 briggs * Search for targ in list. list is an area of listlen bytes 252 1.26 briggs * containing null-terminated strings. 253 1.26 briggs */ 254 1.23 briggs static int 255 1.27 nathanw strinlist(const char *targ, char *list, int listlen) 256 1.23 briggs { 257 1.23 briggs char *str; 258 1.23 briggs int sl; 259 1.26 briggs int targlen; 260 1.23 briggs 261 1.23 briggs str = list; 262 1.26 briggs targlen = strlen(targ); 263 1.23 briggs while (listlen > 0) { 264 1.23 briggs sl = strlen(str); 265 1.26 briggs if (sl == targlen && (strncmp(targ, str, sl) == 0)) 266 1.23 briggs return 1; 267 1.23 briggs str += sl+1; 268 1.23 briggs listlen -= sl+1; 269 1.23 briggs } 270 1.23 briggs return 0; 271 1.23 briggs } 272 1.23 briggs 273 1.23 briggs /* 274 1.23 briggs * Check the hardware type of the Power Manager 275 1.23 briggs */ 276 1.23 briggs void 277 1.23 briggs pm_init(void) 278 1.23 briggs { 279 1.23 briggs uint32_t regs[10]; 280 1.23 briggs PMData pmdata; 281 1.23 briggs char compat[128]; 282 1.27 nathanw int clen, node, pm_imask; 283 1.23 briggs 284 1.23 briggs node = OF_peer(0); 285 1.23 briggs if (node == -1) { 286 1.23 briggs printf("pmu: Failed to get root"); 287 1.23 briggs return; 288 1.23 briggs } 289 1.23 briggs clen = OF_getprop(node, "compatible", compat, sizeof(compat)); 290 1.23 briggs if (clen <= 0) { 291 1.23 briggs printf("pmu: failed to read root compatible data %d\n", clen); 292 1.23 briggs return; 293 1.23 briggs } 294 1.23 briggs 295 1.27 nathanw pm_imask = 296 1.27 nathanw PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | PMU_INT_TICK; 297 1.23 briggs 298 1.23 briggs if (strinlist("AAPL,3500", compat, clen) || 299 1.23 briggs strinlist("AAPL,3400/2400", compat, clen)) { 300 1.23 briggs /* How to distinguish BATT_COMET? */ 301 1.23 briggs pmu_nbatt = 1; 302 1.23 briggs pmu_batt_type = BATT_HOOPER; 303 1.23 briggs pmu_type = PMU_OHARE; 304 1.23 briggs } else if (strinlist("AAPL,PowerBook1998", compat, clen) || 305 1.23 briggs strinlist("PowerBook1,1", compat, clen)) { 306 1.23 briggs pmu_nbatt = 2; 307 1.23 briggs pmu_batt_type = BATT_SMART; 308 1.23 briggs pmu_type = PMU_G3; 309 1.23 briggs } else { 310 1.23 briggs pmu_nbatt = 1; 311 1.23 briggs pmu_batt_type = BATT_SMART; 312 1.23 briggs pmu_type = PMU_KEYLARGO; 313 1.33 garbled node = of_getnode_byname(0, "power-mgt"); 314 1.23 briggs if (node == -1) { 315 1.23 briggs printf("pmu: can't find power-mgt\n"); 316 1.23 briggs return; 317 1.23 briggs } 318 1.23 briggs clen = OF_getprop(node, "prim-info", regs, sizeof(regs)); 319 1.23 briggs if (clen < 24) { 320 1.23 briggs printf("pmu: failed to read prim-info\n"); 321 1.23 briggs return; 322 1.23 briggs } 323 1.23 briggs pmu_nbatt = regs[6] >> 16; 324 1.23 briggs } 325 1.23 briggs 326 1.23 briggs pmdata.command = PMU_SET_IMASK; 327 1.23 briggs pmdata.num_data = 1; 328 1.23 briggs pmdata.s_buf = pmdata.data; 329 1.23 briggs pmdata.r_buf = pmdata.data; 330 1.27 nathanw pmdata.data[0] = pm_imask; 331 1.23 briggs pmgrop(&pmdata); 332 1.23 briggs } 333 1.23 briggs 334 1.1 tsubai 335 1.1 tsubai /* 336 1.1 tsubai * Check the existent ADB devices 337 1.1 tsubai */ 338 1.1 tsubai void 339 1.35 dsl pm_check_adb_devices(int id) 340 1.1 tsubai { 341 1.1 tsubai u_short ed = 0x1; 342 1.1 tsubai 343 1.1 tsubai ed <<= id; 344 1.1 tsubai pm_existent_ADB_devices |= ed; 345 1.1 tsubai } 346 1.1 tsubai 347 1.1 tsubai 348 1.1 tsubai /* 349 1.1 tsubai * Wait until PM IC is busy 350 1.1 tsubai */ 351 1.1 tsubai int 352 1.35 dsl pm_wait_busy(int delaycycles) 353 1.1 tsubai { 354 1.1 tsubai while (PM_IS_ON) { 355 1.1 tsubai #ifdef PM_GRAB_SI 356 1.1 tsubai #if 0 357 1.1 tsubai zshard(0); /* grab any serial interrupts */ 358 1.1 tsubai #else 359 1.1 tsubai (void)intr_dispatch(0x70); 360 1.1 tsubai #endif 361 1.1 tsubai #endif 362 1.27 nathanw if ((--delaycycles) < 0) 363 1.1 tsubai return 1; /* timeout */ 364 1.1 tsubai } 365 1.1 tsubai return 0; 366 1.1 tsubai } 367 1.1 tsubai 368 1.1 tsubai 369 1.1 tsubai /* 370 1.1 tsubai * Wait until PM IC is free 371 1.1 tsubai */ 372 1.1 tsubai int 373 1.35 dsl pm_wait_free(int delaycycles) 374 1.1 tsubai { 375 1.1 tsubai while (PM_IS_OFF) { 376 1.1 tsubai #ifdef PM_GRAB_SI 377 1.1 tsubai #if 0 378 1.1 tsubai zshard(0); /* grab any serial interrupts */ 379 1.1 tsubai #else 380 1.1 tsubai (void)intr_dispatch(0x70); 381 1.1 tsubai #endif 382 1.1 tsubai #endif 383 1.27 nathanw if ((--delaycycles) < 0) 384 1.1 tsubai return 0; /* timeout */ 385 1.1 tsubai } 386 1.1 tsubai return 1; 387 1.1 tsubai } 388 1.1 tsubai 389 1.1 tsubai 390 1.1 tsubai 391 1.1 tsubai /* 392 1.25 briggs * Receive data from PMU 393 1.1 tsubai */ 394 1.25 briggs static int 395 1.35 dsl pm_receive(u_char *data) 396 1.1 tsubai { 397 1.1 tsubai int i; 398 1.1 tsubai int rval; 399 1.1 tsubai 400 1.1 tsubai rval = 0xffffcd34; 401 1.1 tsubai 402 1.1 tsubai switch (1) { 403 1.18 itojun default: 404 1.18 itojun /* set VIA SR to input mode */ 405 1.18 itojun via_reg_or(VIA1, vACR, 0x0c); 406 1.18 itojun via_reg_and(VIA1, vACR, ~0x10); 407 1.18 itojun i = PM_SR(); 408 1.18 itojun 409 1.18 itojun PM_SET_STATE_ACKOFF(); 410 1.18 itojun if (pm_wait_busy((int)ADBDelay*32) != 0) 411 1.18 itojun break; /* timeout */ 412 1.1 tsubai 413 1.18 itojun PM_SET_STATE_ACKON(); 414 1.18 itojun rval = 0xffffcd33; 415 1.18 itojun if (pm_wait_free((int)ADBDelay*32) == 0) 416 1.18 itojun break; /* timeout */ 417 1.1 tsubai 418 1.18 itojun *data = PM_SR(); 419 1.18 itojun rval = 0; 420 1.1 tsubai 421 1.18 itojun break; 422 1.1 tsubai } 423 1.1 tsubai 424 1.1 tsubai PM_SET_STATE_ACKON(); 425 1.1 tsubai via_reg_or(VIA1, vACR, 0x1c); 426 1.1 tsubai 427 1.1 tsubai return rval; 428 1.1 tsubai } 429 1.1 tsubai 430 1.1 tsubai 431 1.1 tsubai 432 1.1 tsubai /* 433 1.25 briggs * Send data to PMU 434 1.1 tsubai */ 435 1.25 briggs static int 436 1.35 dsl pm_send(u_char data) 437 1.1 tsubai { 438 1.1 tsubai int rval; 439 1.1 tsubai 440 1.1 tsubai via_reg_or(VIA1, vACR, 0x1c); 441 1.1 tsubai write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */ 442 1.1 tsubai 443 1.1 tsubai PM_SET_STATE_ACKOFF(); 444 1.1 tsubai rval = 0xffffcd36; 445 1.1 tsubai if (pm_wait_busy((int)ADBDelay*32) != 0) { 446 1.1 tsubai PM_SET_STATE_ACKON(); 447 1.1 tsubai 448 1.1 tsubai via_reg_or(VIA1, vACR, 0x1c); 449 1.1 tsubai 450 1.1 tsubai return rval; 451 1.1 tsubai } 452 1.1 tsubai 453 1.1 tsubai PM_SET_STATE_ACKON(); 454 1.1 tsubai rval = 0xffffcd35; 455 1.1 tsubai if (pm_wait_free((int)ADBDelay*32) != 0) 456 1.1 tsubai rval = 0; 457 1.1 tsubai 458 1.1 tsubai PM_SET_STATE_ACKON(); 459 1.1 tsubai via_reg_or(VIA1, vACR, 0x1c); 460 1.1 tsubai 461 1.1 tsubai return rval; 462 1.1 tsubai } 463 1.1 tsubai 464 1.1 tsubai 465 1.1 tsubai 466 1.1 tsubai /* 467 1.25 briggs * The PMgrOp routine 468 1.1 tsubai */ 469 1.1 tsubai int 470 1.35 dsl pmgrop(PMData *pmdata) 471 1.1 tsubai { 472 1.1 tsubai int i; 473 1.1 tsubai int s; 474 1.1 tsubai u_char via1_vIER; 475 1.1 tsubai int rval = 0; 476 1.1 tsubai int num_pm_data = 0; 477 1.1 tsubai u_char pm_cmd; 478 1.1 tsubai short pm_num_rx_data; 479 1.1 tsubai u_char pm_data; 480 1.1 tsubai u_char *pm_buf; 481 1.1 tsubai 482 1.1 tsubai s = splhigh(); 483 1.1 tsubai 484 1.39 andvar /* disable all interrupts but PM */ 485 1.1 tsubai via1_vIER = 0x10; 486 1.1 tsubai via1_vIER &= read_via_reg(VIA1, vIER); 487 1.1 tsubai write_via_reg(VIA1, vIER, via1_vIER); 488 1.1 tsubai if (via1_vIER != 0x0) 489 1.1 tsubai via1_vIER |= 0x80; 490 1.1 tsubai 491 1.1 tsubai switch (pmdata->command) { 492 1.18 itojun default: 493 1.18 itojun /* wait until PM is free */ 494 1.18 itojun pm_cmd = (u_char)(pmdata->command & 0xff); 495 1.18 itojun rval = 0xcd38; 496 1.18 itojun if (pm_wait_free(ADBDelay * 4) == 0) 497 1.18 itojun break; /* timeout */ 498 1.18 itojun 499 1.18 itojun /* send PM command */ 500 1.25 briggs if ((rval = pm_send((u_char)(pm_cmd & 0xff)))) 501 1.18 itojun break; /* timeout */ 502 1.18 itojun 503 1.18 itojun /* send number of PM data */ 504 1.18 itojun num_pm_data = pmdata->num_data; 505 1.25 briggs if (pm_send_cmd_type[pm_cmd] < 0) { 506 1.25 briggs if ((rval = pm_send((u_char)(num_pm_data & 0xff))) != 0) 507 1.25 briggs break; /* timeout */ 508 1.25 briggs pmdata->command = 0; 509 1.25 briggs } 510 1.18 itojun /* send PM data */ 511 1.18 itojun pm_buf = (u_char *)pmdata->s_buf; 512 1.18 itojun for (i = 0 ; i < num_pm_data; i++) 513 1.25 briggs if ((rval = pm_send(pm_buf[i])) != 0) 514 1.18 itojun break; /* timeout */ 515 1.18 itojun if (i != num_pm_data) 516 1.18 itojun break; /* timeout */ 517 1.1 tsubai 518 1.1 tsubai 519 1.18 itojun /* check if PM will send me data */ 520 1.18 itojun pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 521 1.18 itojun pmdata->num_data = pm_num_rx_data; 522 1.18 itojun if (pm_num_rx_data == 0) { 523 1.18 itojun rval = 0; 524 1.18 itojun break; /* no return data */ 525 1.18 itojun } 526 1.18 itojun 527 1.18 itojun /* receive PM command */ 528 1.18 itojun pm_data = pmdata->command; 529 1.25 briggs pm_num_rx_data--; 530 1.25 briggs if (pm_num_rx_data == 0) 531 1.25 briggs if ((rval = pm_receive(&pm_data)) != 0) { 532 1.18 itojun rval = 0xffffcd37; 533 1.18 itojun break; 534 1.1 tsubai } 535 1.25 briggs pmdata->command = pm_data; 536 1.1 tsubai 537 1.18 itojun /* receive number of PM data */ 538 1.25 briggs if (pm_num_rx_data < 0) { 539 1.25 briggs if ((rval = pm_receive(&pm_data)) != 0) 540 1.25 briggs break; /* timeout */ 541 1.18 itojun num_pm_data = pm_data; 542 1.25 briggs } else 543 1.25 briggs num_pm_data = pm_num_rx_data; 544 1.25 briggs pmdata->num_data = num_pm_data; 545 1.1 tsubai 546 1.18 itojun /* receive PM data */ 547 1.18 itojun pm_buf = (u_char *)pmdata->r_buf; 548 1.18 itojun for (i = 0; i < num_pm_data; i++) { 549 1.25 briggs if ((rval = pm_receive(&pm_data)) != 0) 550 1.18 itojun break; /* timeout */ 551 1.18 itojun pm_buf[i] = pm_data; 552 1.18 itojun } 553 1.1 tsubai 554 1.18 itojun rval = 0; 555 1.1 tsubai } 556 1.1 tsubai 557 1.1 tsubai /* restore former value */ 558 1.1 tsubai write_via_reg(VIA1, vIER, via1_vIER); 559 1.1 tsubai splx(s); 560 1.1 tsubai 561 1.1 tsubai return rval; 562 1.1 tsubai } 563 1.1 tsubai 564 1.1 tsubai 565 1.1 tsubai /* 566 1.25 briggs * My PMU interrupt routine 567 1.1 tsubai */ 568 1.24 briggs int 569 1.25 briggs pm_intr(void *arg) 570 1.1 tsubai { 571 1.1 tsubai int s; 572 1.1 tsubai int rval; 573 1.1 tsubai PMData pmdata; 574 1.1 tsubai 575 1.1 tsubai s = splhigh(); 576 1.1 tsubai 577 1.1 tsubai PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 578 1.38 andvar /* ask PM what happened */ 579 1.23 briggs pmdata.command = PMU_INT_ACK; 580 1.1 tsubai pmdata.num_data = 0; 581 1.1 tsubai pmdata.s_buf = &pmdata.data[2]; 582 1.1 tsubai pmdata.r_buf = &pmdata.data[2]; 583 1.25 briggs rval = pmgrop(&pmdata); 584 1.1 tsubai if (rval != 0) { 585 1.1 tsubai #ifdef ADB_DEBUG 586 1.1 tsubai if (adb_debug) 587 1.1 tsubai printf("pm: PM is not ready. error code: %08x\n", rval); 588 1.1 tsubai #endif 589 1.1 tsubai splx(s); 590 1.24 briggs return 0; 591 1.1 tsubai } 592 1.1 tsubai 593 1.1 tsubai switch ((u_int)(pmdata.data[2] & 0xff)) { 594 1.21 briggs case 0x00: /* no event pending? */ 595 1.18 itojun break; 596 1.18 itojun case 0x80: /* 1 sec interrupt? */ 597 1.18 itojun pm_counter++; 598 1.18 itojun break; 599 1.18 itojun case 0x08: /* Brightness/Contrast button on LCD panel */ 600 1.18 itojun /* get brightness and contrast of the LCD */ 601 1.18 itojun pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 602 1.18 itojun pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 603 1.25 briggs 604 1.25 briggs /* this is experimental code */ 605 1.23 briggs pmdata.command = PMU_SET_BRIGHTNESS; 606 1.18 itojun pmdata.num_data = 1; 607 1.18 itojun pmdata.s_buf = pmdata.data; 608 1.18 itojun pmdata.r_buf = pmdata.data; 609 1.18 itojun pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2; 610 1.18 itojun if (pm_LCD_brightness < 0x08) 611 1.18 itojun pm_LCD_brightness = 0x08; 612 1.18 itojun if (pm_LCD_brightness > 0x78) 613 1.18 itojun pm_LCD_brightness = 0x78; 614 1.18 itojun pmdata.data[0] = pm_LCD_brightness; 615 1.25 briggs rval = pmgrop(&pmdata); 616 1.18 itojun break; 617 1.25 briggs 618 1.23 briggs case 0x10: /* ADB data requested by TALK command */ 619 1.18 itojun case 0x14: 620 1.18 itojun pm_adb_get_TALK_result(&pmdata); 621 1.18 itojun break; 622 1.18 itojun case 0x16: /* ADB device event */ 623 1.18 itojun case 0x18: 624 1.18 itojun case 0x1e: 625 1.18 itojun pm_adb_get_ADB_data(&pmdata); 626 1.18 itojun break; 627 1.18 itojun default: 628 1.1 tsubai #ifdef ADB_DEBUG 629 1.18 itojun if (adb_debug) 630 1.23 briggs pm_printerr("driver does not support this event.", 631 1.18 itojun pmdata.data[2], pmdata.num_data, 632 1.18 itojun pmdata.data); 633 1.1 tsubai #endif 634 1.18 itojun break; 635 1.1 tsubai } 636 1.1 tsubai 637 1.1 tsubai splx(s); 638 1.24 briggs 639 1.24 briggs return 1; 640 1.1 tsubai } 641 1.1 tsubai 642 1.1 tsubai 643 1.1 tsubai /* 644 1.1 tsubai * Synchronous ADBOp routine for the Power Manager 645 1.1 tsubai */ 646 1.1 tsubai int 647 1.35 dsl pm_adb_op(u_char *buffer, adbComp *compRout, volatile int *data, int command) 648 1.1 tsubai { 649 1.1 tsubai int i; 650 1.1 tsubai int s; 651 1.1 tsubai int rval; 652 1.12 tsubai int timo; 653 1.1 tsubai PMData pmdata; 654 1.1 tsubai struct adbCommand packet; 655 1.1 tsubai 656 1.1 tsubai if (adbWaiting == 1) 657 1.1 tsubai return 1; 658 1.1 tsubai 659 1.1 tsubai s = splhigh(); 660 1.1 tsubai write_via_reg(VIA1, vIER, 0x10); 661 1.1 tsubai 662 1.1 tsubai adbBuffer = buffer; 663 1.1 tsubai adbCompRout = compRout; 664 1.1 tsubai adbCompData = data; 665 1.1 tsubai 666 1.23 briggs pmdata.command = PMU_ADB_CMD; 667 1.1 tsubai pmdata.s_buf = pmdata.data; 668 1.1 tsubai pmdata.r_buf = pmdata.data; 669 1.1 tsubai 670 1.1 tsubai /* if the command is LISTEN, add number of ADB data to number of PM data */ 671 1.1 tsubai if ((command & 0xc) == 0x8) { 672 1.1 tsubai if (buffer != (u_char *)0) 673 1.1 tsubai pmdata.num_data = buffer[0] + 3; 674 1.1 tsubai } else { 675 1.1 tsubai pmdata.num_data = 3; 676 1.1 tsubai } 677 1.1 tsubai 678 1.1 tsubai pmdata.data[0] = (u_char)(command & 0xff); 679 1.1 tsubai pmdata.data[1] = 0; 680 1.1 tsubai if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 681 1.1 tsubai if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 682 1.1 tsubai pmdata.data[2] = buffer[0]; /* number of data */ 683 1.1 tsubai for (i = 0; i < buffer[0]; i++) 684 1.1 tsubai pmdata.data[3 + i] = buffer[1 + i]; 685 1.1 tsubai } else 686 1.1 tsubai pmdata.data[2] = 0; 687 1.1 tsubai } else 688 1.1 tsubai pmdata.data[2] = 0; 689 1.1 tsubai 690 1.1 tsubai if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 691 1.1 tsubai /* set up stuff for adb_pass_up */ 692 1.1 tsubai packet.data[0] = 1 + pmdata.data[2]; 693 1.1 tsubai packet.data[1] = command; 694 1.1 tsubai for (i = 0; i < pmdata.data[2]; i++) 695 1.1 tsubai packet.data[i+2] = pmdata.data[i+3]; 696 1.1 tsubai packet.saveBuf = adbBuffer; 697 1.1 tsubai packet.compRout = adbCompRout; 698 1.1 tsubai packet.compData = adbCompData; 699 1.1 tsubai packet.cmd = command; 700 1.1 tsubai packet.unsol = 0; 701 1.1 tsubai packet.ack_only = 1; 702 1.1 tsubai adb_polling = 1; 703 1.1 tsubai adb_pass_up(&packet); 704 1.1 tsubai adb_polling = 0; 705 1.1 tsubai } 706 1.1 tsubai 707 1.1 tsubai rval = pmgrop(&pmdata); 708 1.9 tsubai if (rval != 0) { 709 1.9 tsubai splx(s); 710 1.1 tsubai return 1; 711 1.9 tsubai } 712 1.1 tsubai 713 1.12 tsubai delay(10000); 714 1.12 tsubai 715 1.1 tsubai adbWaiting = 1; 716 1.1 tsubai adbWaitingCmd = command; 717 1.1 tsubai 718 1.1 tsubai PM_VIA_INTR_ENABLE(); 719 1.1 tsubai 720 1.16 wiz /* wait until the PM interrupt has occurred */ 721 1.12 tsubai timo = 0x80000; 722 1.1 tsubai while (adbWaiting == 1) { 723 1.1 tsubai if (read_via_reg(VIA1, vIFR) & 0x14) 724 1.24 briggs pm_intr(NULL); 725 1.1 tsubai #ifdef PM_GRAB_SI 726 1.1 tsubai #if 0 727 1.1 tsubai zshard(0); /* grab any serial interrupts */ 728 1.1 tsubai #else 729 1.1 tsubai (void)intr_dispatch(0x70); 730 1.1 tsubai #endif 731 1.1 tsubai #endif 732 1.12 tsubai if ((--timo) < 0) { 733 1.17 dbj /* Try to take an interrupt anyway, just in case. 734 1.17 dbj * This has been observed to happen on my ibook 735 1.17 dbj * when i press a key after boot and before adb 736 1.17 dbj * is attached; For example, when booting with -d. 737 1.17 dbj */ 738 1.24 briggs pm_intr(NULL); 739 1.17 dbj if (adbWaiting) { 740 1.17 dbj printf("pm_adb_op: timeout. command = 0x%x\n",command); 741 1.17 dbj splx(s); 742 1.17 dbj return 1; 743 1.17 dbj } 744 1.17 dbj #ifdef ADB_DEBUG 745 1.17 dbj else { 746 1.17 dbj printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command); 747 1.17 dbj } 748 1.17 dbj #endif 749 1.9 tsubai } 750 1.1 tsubai } 751 1.1 tsubai 752 1.1 tsubai /* this command enables the interrupt by operating ADB devices */ 753 1.25 briggs pmdata.command = PMU_ADB_CMD; 754 1.25 briggs pmdata.num_data = 4; 755 1.25 briggs pmdata.s_buf = pmdata.data; 756 1.25 briggs pmdata.r_buf = pmdata.data; 757 1.25 briggs pmdata.data[0] = 0x00; 758 1.25 briggs pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 759 1.25 briggs pmdata.data[2] = 0x00; 760 1.25 briggs pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 761 1.1 tsubai rval = pmgrop(&pmdata); 762 1.1 tsubai 763 1.1 tsubai splx(s); 764 1.1 tsubai return rval; 765 1.1 tsubai } 766 1.1 tsubai 767 1.1 tsubai 768 1.1 tsubai void 769 1.35 dsl pm_adb_get_TALK_result(PMData *pmdata) 770 1.1 tsubai { 771 1.1 tsubai int i; 772 1.1 tsubai struct adbCommand packet; 773 1.1 tsubai 774 1.1 tsubai /* set up data for adb_pass_up */ 775 1.1 tsubai packet.data[0] = pmdata->num_data-1; 776 1.1 tsubai packet.data[1] = pmdata->data[3]; 777 1.1 tsubai for (i = 0; i <packet.data[0]-1; i++) 778 1.1 tsubai packet.data[i+2] = pmdata->data[i+4]; 779 1.1 tsubai 780 1.1 tsubai packet.saveBuf = adbBuffer; 781 1.1 tsubai packet.compRout = adbCompRout; 782 1.1 tsubai packet.compData = adbCompData; 783 1.1 tsubai packet.unsol = 0; 784 1.1 tsubai packet.ack_only = 0; 785 1.1 tsubai adb_polling = 1; 786 1.1 tsubai adb_pass_up(&packet); 787 1.1 tsubai adb_polling = 0; 788 1.1 tsubai 789 1.1 tsubai adbWaiting = 0; 790 1.1 tsubai adbBuffer = (long)0; 791 1.1 tsubai adbCompRout = (long)0; 792 1.1 tsubai adbCompData = (long)0; 793 1.1 tsubai } 794 1.1 tsubai 795 1.1 tsubai 796 1.1 tsubai void 797 1.35 dsl pm_adb_get_ADB_data(PMData *pmdata) 798 1.1 tsubai { 799 1.1 tsubai int i; 800 1.1 tsubai struct adbCommand packet; 801 1.1 tsubai 802 1.23 briggs if (pmu_type == PMU_OHARE && pmdata->num_data == 4 && 803 1.23 briggs pmdata->data[1] == 0x2c && pmdata->data[3] == 0xff && 804 1.23 briggs ((pmdata->data[2] & ~1) == 0xf4)) { 805 1.23 briggs if (pmdata->data[2] == 0xf4) { 806 1.23 briggs pm_eject_pcmcia(0); 807 1.23 briggs } else { 808 1.23 briggs pm_eject_pcmcia(1); 809 1.23 briggs } 810 1.23 briggs return; 811 1.23 briggs } 812 1.1 tsubai /* set up data for adb_pass_up */ 813 1.1 tsubai packet.data[0] = pmdata->num_data-1; /* number of raw data */ 814 1.1 tsubai packet.data[1] = pmdata->data[3]; /* ADB command */ 815 1.1 tsubai for (i = 0; i <packet.data[0]-1; i++) 816 1.1 tsubai packet.data[i+2] = pmdata->data[i+4]; 817 1.1 tsubai packet.unsol = 1; 818 1.1 tsubai packet.ack_only = 0; 819 1.1 tsubai adb_pass_up(&packet); 820 1.1 tsubai } 821 1.1 tsubai 822 1.1 tsubai 823 1.1 tsubai void 824 1.37 cegger pm_adb_restart(void) 825 1.1 tsubai { 826 1.1 tsubai PMData p; 827 1.1 tsubai 828 1.4 tsubai p.command = PMU_RESET_CPU; 829 1.1 tsubai p.num_data = 0; 830 1.1 tsubai p.s_buf = p.data; 831 1.1 tsubai p.r_buf = p.data; 832 1.6 tsubai pmgrop(&p); 833 1.6 tsubai } 834 1.6 tsubai 835 1.6 tsubai void 836 1.37 cegger pm_adb_poweroff(void) 837 1.6 tsubai { 838 1.6 tsubai PMData p; 839 1.6 tsubai 840 1.6 tsubai p.command = PMU_POWER_OFF; 841 1.6 tsubai p.num_data = 4; 842 1.6 tsubai p.s_buf = p.data; 843 1.6 tsubai p.r_buf = p.data; 844 1.6 tsubai strcpy(p.data, "MATT"); 845 1.1 tsubai pmgrop(&p); 846 1.2 tsubai } 847 1.2 tsubai 848 1.2 tsubai void 849 1.35 dsl pm_read_date_time(u_long *t) 850 1.2 tsubai { 851 1.2 tsubai PMData p; 852 1.2 tsubai 853 1.4 tsubai p.command = PMU_READ_RTC; 854 1.2 tsubai p.num_data = 0; 855 1.2 tsubai p.s_buf = p.data; 856 1.2 tsubai p.r_buf = p.data; 857 1.2 tsubai pmgrop(&p); 858 1.2 tsubai 859 1.30 kardel memcpy(t, p.data, 4); 860 1.4 tsubai } 861 1.4 tsubai 862 1.4 tsubai void 863 1.35 dsl pm_set_date_time(u_long t) 864 1.4 tsubai { 865 1.4 tsubai PMData p; 866 1.4 tsubai 867 1.4 tsubai p.command = PMU_SET_RTC; 868 1.4 tsubai p.num_data = 4; 869 1.4 tsubai p.s_buf = p.r_buf = p.data; 870 1.30 kardel memcpy(p.data, &t, 4); 871 1.7 tsubai pmgrop(&p); 872 1.7 tsubai } 873 1.7 tsubai 874 1.7 tsubai int 875 1.37 cegger pm_read_brightness(void) 876 1.7 tsubai { 877 1.7 tsubai PMData p; 878 1.7 tsubai 879 1.7 tsubai p.command = PMU_READ_BRIGHTNESS; 880 1.7 tsubai p.num_data = 1; /* XXX why 1? */ 881 1.7 tsubai p.s_buf = p.r_buf = p.data; 882 1.7 tsubai p.data[0] = 0; 883 1.7 tsubai pmgrop(&p); 884 1.7 tsubai 885 1.7 tsubai return p.data[0]; 886 1.7 tsubai } 887 1.7 tsubai 888 1.7 tsubai void 889 1.35 dsl pm_set_brightness(int val) 890 1.7 tsubai { 891 1.7 tsubai PMData p; 892 1.7 tsubai 893 1.7 tsubai val = 0x7f - val / 2; 894 1.7 tsubai if (val < 0x08) 895 1.7 tsubai val = 0x08; 896 1.7 tsubai if (val > 0x78) 897 1.7 tsubai val = 0x78; 898 1.7 tsubai 899 1.7 tsubai p.command = PMU_SET_BRIGHTNESS; 900 1.7 tsubai p.num_data = 1; 901 1.7 tsubai p.s_buf = p.r_buf = p.data; 902 1.7 tsubai p.data[0] = val; 903 1.7 tsubai pmgrop(&p); 904 1.7 tsubai } 905 1.7 tsubai 906 1.7 tsubai void 907 1.37 cegger pm_init_brightness(void) 908 1.7 tsubai { 909 1.7 tsubai int val; 910 1.7 tsubai 911 1.7 tsubai val = pm_read_brightness(); 912 1.7 tsubai pm_set_brightness(val); 913 1.7 tsubai } 914 1.7 tsubai 915 1.7 tsubai void 916 1.35 dsl pm_eject_pcmcia(int slot) 917 1.7 tsubai { 918 1.7 tsubai PMData p; 919 1.7 tsubai 920 1.7 tsubai if (slot != 0 && slot != 1) 921 1.7 tsubai return; 922 1.7 tsubai 923 1.7 tsubai p.command = PMU_EJECT_PCMCIA; 924 1.7 tsubai p.num_data = 1; 925 1.7 tsubai p.s_buf = p.r_buf = p.data; 926 1.8 tsubai p.data[0] = 5 + slot; /* XXX */ 927 1.5 tsubai pmgrop(&p); 928 1.19 itojun } 929 1.19 itojun 930 1.19 itojun /* 931 1.19 itojun * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation 932 1.19 itojun * for a clear description of the PMU results. 933 1.19 itojun */ 934 1.23 briggs static int 935 1.23 briggs pm_battery_info_smart(int battery, struct pmu_battery_info *info) 936 1.19 itojun { 937 1.19 itojun PMData p; 938 1.19 itojun 939 1.19 itojun p.command = PMU_SMART_BATTERY_STATE; 940 1.19 itojun p.num_data = 1; 941 1.19 itojun p.s_buf = p.r_buf = p.data; 942 1.19 itojun p.data[0] = battery + 1; 943 1.19 itojun pmgrop(&p); 944 1.19 itojun 945 1.19 itojun info->flags = p.data[1]; 946 1.19 itojun 947 1.22 briggs info->secs_remaining = 0; 948 1.19 itojun switch (p.data[0]) { 949 1.19 itojun case 3: 950 1.19 itojun case 4: 951 1.19 itojun info->cur_charge = p.data[2]; 952 1.19 itojun info->max_charge = p.data[3]; 953 1.19 itojun info->draw = *((signed char *)&p.data[4]); 954 1.19 itojun info->voltage = p.data[5]; 955 1.19 itojun break; 956 1.19 itojun case 5: 957 1.19 itojun info->cur_charge = ((p.data[2] << 8) | (p.data[3])); 958 1.19 itojun info->max_charge = ((p.data[4] << 8) | (p.data[5])); 959 1.19 itojun info->draw = *((signed short *)&p.data[6]); 960 1.19 itojun info->voltage = ((p.data[8] << 8) | (p.data[7])); 961 1.19 itojun break; 962 1.19 itojun default: 963 1.19 itojun /* XXX - Error condition */ 964 1.19 itojun info->cur_charge = 0; 965 1.19 itojun info->max_charge = 0; 966 1.19 itojun info->draw = 0; 967 1.19 itojun info->voltage = 0; 968 1.19 itojun break; 969 1.19 itojun } 970 1.22 briggs if (info->draw) { 971 1.22 briggs if (info->flags & PMU_PWR_AC_PRESENT && info->draw > 0) { 972 1.22 briggs info->secs_remaining = 973 1.22 briggs ((info->max_charge - info->cur_charge) * 3600) 974 1.22 briggs / info->draw; 975 1.22 briggs } else { 976 1.22 briggs info->secs_remaining = 977 1.22 briggs (info->cur_charge * 3600) / -info->draw; 978 1.22 briggs } 979 1.22 briggs } 980 1.19 itojun 981 1.19 itojun return 1; 982 1.5 tsubai } 983 1.5 tsubai 984 1.23 briggs static int 985 1.23 briggs pm_battery_info_legacy(int battery, struct pmu_battery_info *info, int ty) 986 1.23 briggs { 987 1.23 briggs PMData p; 988 1.27 nathanw long pcharge=0, charge, vb, vmax, chargemax; 989 1.23 briggs long vmax_charging, vmax_charged, amperage, voltage; 990 1.23 briggs 991 1.23 briggs p.command = PMU_BATTERY_STATE; 992 1.23 briggs p.num_data = 0; 993 1.23 briggs p.s_buf = p.r_buf = p.data; 994 1.23 briggs pmgrop(&p); 995 1.23 briggs 996 1.23 briggs info->flags = p.data[0]; 997 1.23 briggs 998 1.23 briggs if (info->flags & PMU_PWR_BATT_PRESENT) { 999 1.23 briggs if (ty == BATT_COMET) { 1000 1.23 briggs vmax_charging = 213; 1001 1.23 briggs vmax_charged = 189; 1002 1.27 nathanw chargemax = 6500; 1003 1.23 briggs } else { 1004 1.23 briggs /* Experimental values */ 1005 1.23 briggs vmax_charging = 365; 1006 1.23 briggs vmax_charged = 365; 1007 1.27 nathanw chargemax = 6500; 1008 1.23 briggs } 1009 1.23 briggs vmax = vmax_charged; 1010 1.23 briggs vb = (p.data[1] << 8) | p.data[2]; 1011 1.23 briggs voltage = (vb * 256 + 72665) / 10; 1012 1.23 briggs amperage = (unsigned char) p.data[5]; 1013 1.23 briggs if ((info->flags & PMU_PWR_AC_PRESENT) == 0) { 1014 1.23 briggs if (amperage > 200) 1015 1.23 briggs vb += ((amperage - 200) * 15)/100; 1016 1.23 briggs } else if (info->flags & PMU_PWR_BATT_CHARGING) { 1017 1.23 briggs vb = (vb * 97) / 100; 1018 1.23 briggs vmax = vmax_charging; 1019 1.23 briggs } 1020 1.23 briggs charge = (100 * vb) / vmax; 1021 1.23 briggs if (info->flags & PMU_PWR_PCHARGE_RESET) { 1022 1.23 briggs pcharge = (p.data[6] << 8) | p.data[7]; 1023 1.27 nathanw if (pcharge > chargemax) 1024 1.27 nathanw pcharge = chargemax; 1025 1.23 briggs pcharge *= 100; 1026 1.27 nathanw pcharge = 100 - pcharge / chargemax; 1027 1.23 briggs if (pcharge < charge) 1028 1.23 briggs charge = pcharge; 1029 1.23 briggs } 1030 1.23 briggs info->cur_charge = charge; 1031 1.23 briggs info->max_charge = 100; 1032 1.23 briggs info->draw = -amperage; 1033 1.23 briggs info->voltage = voltage; 1034 1.23 briggs if (amperage > 0) 1035 1.23 briggs info->secs_remaining = (charge * 16440) / amperage; 1036 1.23 briggs else 1037 1.23 briggs info->secs_remaining = 0; 1038 1.23 briggs } else { 1039 1.23 briggs info->cur_charge = 0; 1040 1.23 briggs info->max_charge = 0; 1041 1.23 briggs info->draw = 0; 1042 1.23 briggs info->voltage = 0; 1043 1.23 briggs info->secs_remaining = 0; 1044 1.23 briggs } 1045 1.23 briggs 1046 1.23 briggs return 1; 1047 1.23 briggs } 1048 1.23 briggs 1049 1.23 briggs int 1050 1.23 briggs pm_battery_info(int battery, struct pmu_battery_info *info) 1051 1.23 briggs { 1052 1.23 briggs 1053 1.23 briggs if (battery > pmu_nbatt) 1054 1.23 briggs return 0; 1055 1.23 briggs 1056 1.23 briggs switch (pmu_batt_type) { 1057 1.23 briggs case BATT_COMET: 1058 1.23 briggs case BATT_HOOPER: 1059 1.23 briggs return pm_battery_info_legacy(battery, info, pmu_batt_type); 1060 1.23 briggs 1061 1.23 briggs case BATT_SMART: 1062 1.23 briggs return pm_battery_info_smart(battery, info); 1063 1.23 briggs } 1064 1.23 briggs 1065 1.23 briggs return 0; 1066 1.23 briggs } 1067 1.23 briggs 1068 1.5 tsubai int 1069 1.35 dsl pm_read_nvram(int addr) 1070 1.5 tsubai { 1071 1.5 tsubai PMData p; 1072 1.5 tsubai 1073 1.5 tsubai p.command = PMU_READ_NVRAM; 1074 1.5 tsubai p.num_data = 2; 1075 1.5 tsubai p.s_buf = p.r_buf = p.data; 1076 1.5 tsubai p.data[0] = addr >> 8; 1077 1.5 tsubai p.data[1] = addr; 1078 1.5 tsubai pmgrop(&p); 1079 1.5 tsubai 1080 1.5 tsubai return p.data[0]; 1081 1.5 tsubai } 1082 1.5 tsubai 1083 1.5 tsubai void 1084 1.36 dsl pm_write_nvram(int addr, int val) 1085 1.5 tsubai { 1086 1.5 tsubai PMData p; 1087 1.5 tsubai 1088 1.5 tsubai p.command = PMU_WRITE_NVRAM; 1089 1.5 tsubai p.num_data = 3; 1090 1.5 tsubai p.s_buf = p.r_buf = p.data; 1091 1.5 tsubai p.data[0] = addr >> 8; 1092 1.5 tsubai p.data[1] = addr; 1093 1.5 tsubai p.data[2] = val; 1094 1.4 tsubai pmgrop(&p); 1095 1.1 tsubai } 1096