1 1.43 nat /* $NetBSD: pm_direct.c,v 1.43 2025/05/14 06:31:45 nat Exp $ */ 2 1.1 scottr 3 1.1 scottr /* 4 1.40 nat * Copyright (c) 2024, 2025 Nathanial Sloss <nathanialsloss (at) yahoo.com.au> 5 1.33 nat * All rights reserved. 6 1.33 nat * 7 1.1 scottr * Copyright (C) 1997 Takashi Hamada 8 1.1 scottr * All rights reserved. 9 1.1 scottr * 10 1.1 scottr * Redistribution and use in source and binary forms, with or without 11 1.1 scottr * modification, are permitted provided that the following conditions 12 1.1 scottr * are met: 13 1.1 scottr * 1. Redistributions of source code must retain the above copyright 14 1.1 scottr * notice, this list of conditions and the following disclaimer. 15 1.1 scottr * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 scottr * notice, this list of conditions and the following disclaimer in the 17 1.1 scottr * documentation and/or other materials provided with the distribution. 18 1.1 scottr * 3. All advertising materials mentioning features or use of this software 19 1.1 scottr * must display the following acknowledgement: 20 1.5 scottr * This product includes software developed by Takashi Hamada 21 1.1 scottr * 4. The name of the author may not be used to endorse or promote products 22 1.1 scottr * derived from this software without specific prior written permission. 23 1.1 scottr * 24 1.1 scottr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 1.1 scottr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 1.1 scottr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 1.1 scottr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 1.1 scottr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 1.1 scottr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 1.1 scottr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 1.1 scottr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 1.1 scottr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 1.1 scottr * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 scottr */ 35 1.5 scottr /* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */ 36 1.22 lukem 37 1.22 lukem #include <sys/cdefs.h> 38 1.43 nat __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.43 2025/05/14 06:31:45 nat Exp $"); 39 1.1 scottr 40 1.3 scottr #include "opt_adb.h" 41 1.3 scottr 42 1.3 scottr #ifdef DEBUG 43 1.3 scottr #ifndef ADB_DEBUG 44 1.3 scottr #define ADB_DEBUG 45 1.3 scottr #endif 46 1.3 scottr #endif 47 1.1 scottr 48 1.1 scottr /* #define PM_GRAB_SI 1 */ 49 1.1 scottr 50 1.1 scottr #include <sys/types.h> 51 1.40 nat #include <sys/kthread.h> 52 1.40 nat #include <sys/proc.h> 53 1.38 nat #include <sys/mutex.h> 54 1.43 nat #include <sys/sysctl.h> 55 1.3 scottr #include <sys/systm.h> 56 1.1 scottr 57 1.35 nat #include <dev/sysmon/sysmonvar.h> 58 1.35 nat 59 1.1 scottr #include <machine/viareg.h> 60 1.1 scottr #include <machine/param.h> 61 1.1 scottr #include <machine/cpu.h> 62 1.1 scottr #include <machine/adbsys.h> 63 1.1 scottr 64 1.2 scottr #include <mac68k/mac68k/macrom.h> 65 1.2 scottr #include <mac68k/dev/adbvar.h> 66 1.2 scottr #include <mac68k/dev/pm_direct.h> 67 1.1 scottr 68 1.1 scottr /* hardware dependent values */ 69 1.1 scottr extern u_short ADBDelay; 70 1.1 scottr extern u_int32_t HwCfgFlags3; 71 1.1 scottr extern struct mac68k_machine_S mac68k_machine; 72 1.1 scottr 73 1.1 scottr 74 1.1 scottr /* useful macros */ 75 1.1 scottr #define PM_SR() via_reg(VIA1, vSR) 76 1.1 scottr #define PM_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x90 77 1.1 scottr #define PM_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x10 78 1.1 scottr #define PM_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x90 79 1.1 scottr #define PM_SET_STATE_ACKON() via_reg(VIA2, vBufB) |= 0x04 80 1.1 scottr #define PM_SET_STATE_ACKOFF() via_reg(VIA2, vBufB) &= ~0x04 81 1.4 scottr #define PM_IS_ON (0x02 == (via_reg(VIA2, vBufB) & 0x02)) 82 1.4 scottr #define PM_IS_OFF (0x00 == (via_reg(VIA2, vBufB) & 0x02)) 83 1.1 scottr 84 1.4 scottr /* 85 1.4 scottr * Variables for internal use 86 1.1 scottr */ 87 1.1 scottr int pmHardware = PM_HW_UNKNOWN; 88 1.1 scottr u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */ 89 1.1 scottr u_int pm_LCD_brightness = 0x0; 90 1.1 scottr u_int pm_LCD_contrast = 0x0; 91 1.1 scottr u_int pm_counter = 0; /* clock count */ 92 1.35 nat struct sysmon_pswitch pbutton; 93 1.43 nat struct sysctllog *sc_log; /* Sysctl log */ 94 1.1 scottr 95 1.1 scottr /* these values shows that number of data returned after 'send' cmd is sent */ 96 1.1 scottr char pm_send_cmd_type[] = { 97 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 98 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 99 1.4 scottr 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 100 1.4 scottr 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 101 1.4 scottr 0xff, 0x00, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 102 1.4 scottr 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 103 1.4 scottr 0x04, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 104 1.4 scottr 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 105 1.4 scottr 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 106 1.4 scottr 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 107 1.4 scottr 0x01, 0x00, 0x02, 0x02, 0xff, 0x01, 0x03, 0x01, 108 1.4 scottr 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 109 1.4 scottr 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 110 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 111 1.4 scottr 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 112 1.4 scottr 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04, 0x04, 113 1.4 scottr 0x04, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 114 1.4 scottr 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 115 1.4 scottr 0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 116 1.4 scottr 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 117 1.4 scottr 0x02, 0x02, 0x02, 0x04, 0xff, 0x00, 0xff, 0xff, 118 1.4 scottr 0x01, 0x01, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff, 119 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 120 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 121 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 122 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 123 1.4 scottr 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 124 1.4 scottr 0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 125 1.4 scottr 0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 126 1.4 scottr 0x03, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 127 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 128 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 129 1.1 scottr }; 130 1.1 scottr 131 1.1 scottr /* these values shows that number of data returned after 'receive' cmd is sent */ 132 1.1 scottr char pm_receive_cmd_type[] = { 133 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 135 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 1.4 scottr 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 137 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 139 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 1.4 scottr 0x05, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 141 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 142 1.4 scottr 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 143 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 144 1.4 scottr 0x02, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff, 145 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 146 1.4 scottr 0x04, 0x04, 0x03, 0x09, 0xff, 0xff, 0xff, 0xff, 147 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 148 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 149 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 150 1.4 scottr 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 151 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 152 1.4 scottr 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 153 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 154 1.4 scottr 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 155 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 156 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 157 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 159 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 1.4 scottr 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 161 1.4 scottr 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 162 1.4 scottr 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00, 163 1.4 scottr 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 1.4 scottr 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 165 1.1 scottr }; 166 1.1 scottr 167 1.1 scottr 168 1.38 nat /* Spin mutex to seriaize powermanager requests. */ 169 1.38 nat kmutex_t pm_mutex; 170 1.38 nat 171 1.1 scottr /* 172 1.1 scottr * Define the private functions 173 1.1 scottr */ 174 1.1 scottr 175 1.1 scottr /* for debugging */ 176 1.3 scottr #ifdef ADB_DEBUG 177 1.25 christos void pm_printerr(const char *, int, int, char *); 178 1.1 scottr #endif 179 1.1 scottr 180 1.23 chs int pm_wait_busy(int); 181 1.23 chs int pm_wait_free(int); 182 1.1 scottr 183 1.1 scottr /* these functions are for the PB1XX series */ 184 1.23 chs int pm_receive_pm1(u_char *); 185 1.23 chs int pm_send_pm1(u_char, int); 186 1.23 chs int pm_pmgrop_pm1(PMData *); 187 1.23 chs void pm_intr_pm1(void *); 188 1.40 nat void brightness_slider(void *); /* brightness slider thread */ 189 1.1 scottr 190 1.1 scottr /* these functions are for the PB Duo series and the PB 5XX series */ 191 1.23 chs int pm_receive_pm2(u_char *); 192 1.23 chs int pm_send_pm2(u_char); 193 1.23 chs int pm_pmgrop_pm2(PMData *); 194 1.23 chs void pm_intr_pm2(void *); 195 1.1 scottr 196 1.1 scottr /* this function is MRG-Based (for testing) */ 197 1.23 chs int pm_pmgrop_mrg(PMData *); 198 1.1 scottr 199 1.1 scottr /* these functions are called from adb_direct.c */ 200 1.23 chs void pm_setup_adb(void); 201 1.23 chs void pm_check_adb_devices(int); 202 1.23 chs void pm_intr(void *); 203 1.23 chs int pm_adb_op(u_char *, void *, void *, int); 204 1.23 chs void pm_hw_setup(void); 205 1.1 scottr 206 1.1 scottr /* these functions also use the variables of adb_direct.c */ 207 1.23 chs void pm_adb_get_TALK_result(PMData *); 208 1.23 chs void pm_adb_get_ADB_data(PMData *); 209 1.23 chs void pm_adb_poll_next_device_pm1(PMData *); 210 1.1 scottr 211 1.43 nat static void brightness_sysctl_setup(void *); 212 1.43 nat static int sysctl_brightness(SYSCTLFN_PROTO); 213 1.1 scottr 214 1.1 scottr /* 215 1.1 scottr * These variables are in adb_direct.c. 216 1.1 scottr */ 217 1.1 scottr extern u_char *adbBuffer; /* pointer to user data area */ 218 1.1 scottr extern void *adbCompRout; /* pointer to the completion routine */ 219 1.1 scottr extern void *adbCompData; /* pointer to the completion routine data */ 220 1.1 scottr extern int adbWaiting; /* waiting for return data from the device */ 221 1.1 scottr extern int adbWaitingCmd; /* ADB command we are waiting for */ 222 1.1 scottr extern int adbStarting; /* doing ADB reinit, so do "polling" differently */ 223 1.1 scottr 224 1.5 scottr #define ADB_MAX_MSG_LENGTH 16 225 1.5 scottr #define ADB_MAX_HDR_LENGTH 8 226 1.5 scottr struct adbCommand { 227 1.5 scottr u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */ 228 1.5 scottr u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */ 229 1.5 scottr u_char *saveBuf; /* where to save result */ 230 1.5 scottr u_char *compRout; /* completion routine pointer */ 231 1.5 scottr u_char *compData; /* completion routine data pointer */ 232 1.5 scottr u_int cmd; /* the original command for this data */ 233 1.5 scottr u_int unsol; /* 1 if packet was unsolicited */ 234 1.5 scottr u_int ack_only; /* 1 for no special processing */ 235 1.5 scottr }; 236 1.23 chs extern void adb_pass_up(struct adbCommand *); 237 1.5 scottr 238 1.3 scottr #ifdef ADB_DEBUG 239 1.1 scottr /* 240 1.1 scottr * This function dumps contents of the PMData 241 1.1 scottr */ 242 1.1 scottr void 243 1.25 christos pm_printerr(const char *ttl, int rval, int num, char *data) 244 1.1 scottr { 245 1.1 scottr int i; 246 1.1 scottr 247 1.4 scottr printf("pm: %s:%04x %02x ", ttl, rval, num); 248 1.4 scottr for (i = 0; i < num; i++) 249 1.4 scottr printf("%02x ", data[i]); 250 1.4 scottr printf("\n"); 251 1.1 scottr } 252 1.1 scottr #endif 253 1.1 scottr 254 1.1 scottr 255 1.1 scottr 256 1.1 scottr /* 257 1.1 scottr * Check the hardware type of the Power Manager 258 1.1 scottr */ 259 1.1 scottr void 260 1.23 chs pm_setup_adb(void) 261 1.1 scottr { 262 1.38 nat mutex_init(&pm_mutex, MUTEX_DEFAULT, IPL_HIGH); 263 1.1 scottr switch (mac68k_machine.machineid) { 264 1.1 scottr case MACH_MACPB140: 265 1.1 scottr case MACH_MACPB145: 266 1.1 scottr case MACH_MACPB160: 267 1.1 scottr case MACH_MACPB165: 268 1.1 scottr case MACH_MACPB165C: 269 1.1 scottr case MACH_MACPB170: 270 1.1 scottr case MACH_MACPB180: 271 1.1 scottr case MACH_MACPB180C: 272 1.1 scottr pmHardware = PM_HW_PB1XX; 273 1.35 nat 274 1.35 nat memset(&pbutton, 0, sizeof(struct sysmon_pswitch)); 275 1.35 nat pbutton.smpsw_name = "PB"; 276 1.35 nat pbutton.smpsw_type = PSWITCH_TYPE_POWER; 277 1.35 nat if (sysmon_pswitch_register(&pbutton) != 0) 278 1.35 nat printf("Unable to register soft power\n"); 279 1.43 nat brightness_sysctl_setup(NULL); 280 1.40 nat kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, 281 1.40 nat brightness_slider, NULL, NULL, "britethrd"); 282 1.1 scottr break; 283 1.19 shiba case MACH_MACPB150: 284 1.1 scottr case MACH_MACPB210: 285 1.1 scottr case MACH_MACPB230: 286 1.1 scottr case MACH_MACPB250: 287 1.1 scottr case MACH_MACPB270: 288 1.1 scottr case MACH_MACPB280: 289 1.1 scottr case MACH_MACPB280C: 290 1.1 scottr case MACH_MACPB500: 291 1.21 shiba case MACH_MACPB190: 292 1.21 shiba case MACH_MACPB190CS: 293 1.1 scottr pmHardware = PM_HW_PB5XX; 294 1.35 nat #if notyet 295 1.35 nat memset(&pbutton, 0, sizeof(struct sysmon_pswitch)); 296 1.35 nat pbutton.smpsw_name = "PB"; 297 1.35 nat pbutton.smpsw_type = PSWITCH_TYPE_POWER; 298 1.35 nat if (sysmon_pswitch_register(&pbutton) != 0) 299 1.35 nat printf("Unable to register soft power\n"); 300 1.35 nat #endif 301 1.1 scottr break; 302 1.1 scottr default: 303 1.1 scottr break; 304 1.1 scottr } 305 1.1 scottr } 306 1.1 scottr 307 1.1 scottr 308 1.1 scottr /* 309 1.1 scottr * Check the existent ADB devices 310 1.1 scottr */ 311 1.1 scottr void 312 1.23 chs pm_check_adb_devices(int id) 313 1.1 scottr { 314 1.1 scottr u_short ed = 0x1; 315 1.1 scottr 316 1.1 scottr ed <<= id; 317 1.1 scottr pm_existent_ADB_devices |= ed; 318 1.1 scottr } 319 1.1 scottr 320 1.1 scottr 321 1.1 scottr /* 322 1.1 scottr * Wait until PM IC is busy 323 1.1 scottr */ 324 1.1 scottr int 325 1.24 jmc pm_wait_busy(int xdelay) 326 1.1 scottr { 327 1.4 scottr while (PM_IS_ON) { 328 1.1 scottr #ifdef PM_GRAB_SI 329 1.15 scottr (void)intr_dispatch(0x70); /* grab any serial interrupts */ 330 1.1 scottr #endif 331 1.24 jmc if ((--xdelay) < 0) 332 1.5 scottr return 1; /* timeout */ 333 1.1 scottr } 334 1.5 scottr return 0; 335 1.1 scottr } 336 1.1 scottr 337 1.1 scottr 338 1.1 scottr /* 339 1.1 scottr * Wait until PM IC is free 340 1.1 scottr */ 341 1.1 scottr int 342 1.24 jmc pm_wait_free(int xdelay) 343 1.1 scottr { 344 1.4 scottr while (PM_IS_OFF) { 345 1.1 scottr #ifdef PM_GRAB_SI 346 1.15 scottr (void)intr_dispatch(0x70); /* grab any serial interrupts */ 347 1.1 scottr #endif 348 1.24 jmc if ((--xdelay) < 0) 349 1.5 scottr return 0; /* timeout */ 350 1.1 scottr } 351 1.5 scottr return 1; 352 1.1 scottr } 353 1.1 scottr 354 1.1 scottr 355 1.1 scottr 356 1.1 scottr /* 357 1.1 scottr * Functions for the PB1XX series 358 1.1 scottr */ 359 1.1 scottr 360 1.1 scottr /* 361 1.1 scottr * Receive data from PM for the PB1XX series 362 1.1 scottr */ 363 1.1 scottr int 364 1.23 chs pm_receive_pm1(u_char *data) 365 1.1 scottr { 366 1.1 scottr int rval = 0xffffcd34; 367 1.1 scottr 368 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 369 1.1 scottr 370 1.4 scottr switch (1) { 371 1.1 scottr default: 372 1.4 scottr if (pm_wait_busy(0x40) != 0) 373 1.1 scottr break; /* timeout */ 374 1.1 scottr 375 1.1 scottr PM_SET_STATE_ACKOFF(); 376 1.1 scottr *data = via_reg(VIA2, 0x200); 377 1.1 scottr 378 1.1 scottr rval = 0xffffcd33; 379 1.4 scottr if (pm_wait_free(0x40) == 0) 380 1.1 scottr break; /* timeout */ 381 1.1 scottr 382 1.1 scottr rval = 0x00; 383 1.1 scottr break; 384 1.1 scottr } 385 1.1 scottr 386 1.1 scottr PM_SET_STATE_ACKON(); 387 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 388 1.1 scottr 389 1.5 scottr return rval; 390 1.1 scottr } 391 1.1 scottr 392 1.1 scottr 393 1.1 scottr 394 1.1 scottr /* 395 1.1 scottr * Send data to PM for the PB1XX series 396 1.1 scottr */ 397 1.1 scottr int 398 1.23 chs pm_send_pm1(u_char data, int timo) 399 1.1 scottr { 400 1.4 scottr int rval; 401 1.1 scottr 402 1.1 scottr via_reg(VIA2, vDirA) = 0xff; 403 1.1 scottr via_reg(VIA2, 0x200) = data; 404 1.1 scottr 405 1.1 scottr PM_SET_STATE_ACKOFF(); 406 1.14 scottr #if 0 407 1.14 scottr if (pm_wait_busy(0x400) == 0) { 408 1.14 scottr #else 409 1.14 scottr if (pm_wait_busy(timo) == 0) { 410 1.14 scottr #endif 411 1.1 scottr PM_SET_STATE_ACKON(); 412 1.14 scottr if (pm_wait_free(0x40) != 0) 413 1.14 scottr rval = 0x0; 414 1.14 scottr else 415 1.14 scottr rval = 0xffffcd35; 416 1.14 scottr } else { 417 1.14 scottr rval = 0xffffcd36; 418 1.1 scottr } 419 1.1 scottr 420 1.1 scottr PM_SET_STATE_ACKON(); 421 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 422 1.1 scottr 423 1.5 scottr return rval; 424 1.1 scottr } 425 1.1 scottr 426 1.1 scottr 427 1.1 scottr /* 428 1.1 scottr * My PMgrOp routine for the PB1XX series 429 1.1 scottr */ 430 1.1 scottr int 431 1.23 chs pm_pmgrop_pm1(PMData *pmdata) 432 1.1 scottr { 433 1.4 scottr int i; 434 1.4 scottr int s = 0x81815963; 435 1.4 scottr u_char via1_vIER, via1_vDirA; 436 1.4 scottr int rval = 0; 437 1.4 scottr int num_pm_data = 0; 438 1.36 riastrad u_char pm_cmd; 439 1.4 scottr u_char pm_data; 440 1.4 scottr u_char *pm_buf; 441 1.1 scottr 442 1.38 nat mutex_spin_enter(&pm_mutex); 443 1.38 nat 444 1.32 andvar /* disable all interrupts but PM */ 445 1.1 scottr via1_vIER = via_reg(VIA1, vIER); 446 1.1 scottr PM_VIA_INTR_DISABLE(); 447 1.1 scottr 448 1.1 scottr via1_vDirA = via_reg(VIA1, vDirA); 449 1.1 scottr 450 1.4 scottr switch (pmdata->command) { 451 1.1 scottr default: 452 1.4 scottr for (i = 0; i < 7; i++) { 453 1.36 riastrad via_reg(VIA2, vDirA) = 0x00; 454 1.1 scottr 455 1.1 scottr /* wait until PM is free */ 456 1.4 scottr if (pm_wait_free(ADBDelay) == 0) { /* timeout */ 457 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 458 1.1 scottr /* restore formar value */ 459 1.1 scottr via_reg(VIA1, vDirA) = via1_vDirA; 460 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 461 1.38 nat mutex_spin_exit(&pm_mutex); 462 1.5 scottr return 0xffffcd38; 463 1.1 scottr } 464 1.1 scottr 465 1.4 scottr switch (mac68k_machine.machineid) { 466 1.1 scottr case MACH_MACPB160: 467 1.1 scottr case MACH_MACPB165: 468 1.1 scottr case MACH_MACPB165C: 469 1.8 scottr case MACH_MACPB170: 470 1.1 scottr case MACH_MACPB180: 471 1.1 scottr case MACH_MACPB180C: 472 1.1 scottr { 473 1.24 jmc int xdelay = ADBDelay * 16; 474 1.1 scottr 475 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 476 1.24 jmc while ((via_reg(VIA2, 0x200) == 0x7f) && (xdelay >= 0)) 477 1.24 jmc xdelay--; 478 1.1 scottr 479 1.24 jmc if (xdelay < 0) { /* timeout */ 480 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 481 1.1 scottr /* restore formar value */ 482 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 483 1.38 nat mutex_spin_exit(&pm_mutex); 484 1.5 scottr return 0xffffcd38; 485 1.1 scottr } 486 1.1 scottr } 487 1.1 scottr } /* end switch */ 488 1.1 scottr 489 1.4 scottr s = splhigh(); 490 1.1 scottr 491 1.1 scottr via1_vDirA = via_reg(VIA1, vDirA); 492 1.1 scottr via_reg(VIA1, vDirA) &= 0x7f; 493 1.1 scottr 494 1.1 scottr pm_cmd = (u_char)(pmdata->command & 0xff); 495 1.4 scottr if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0) 496 1.4 scottr break; /* send command succeeded */ 497 1.1 scottr 498 1.1 scottr via_reg(VIA1, vDirA) = via1_vDirA; 499 1.1 scottr splx(s); 500 1.1 scottr } /* end for */ 501 1.1 scottr 502 1.1 scottr /* failed to send a command */ 503 1.1 scottr if (i == 7) { 504 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 505 1.1 scottr /* restore formar value */ 506 1.1 scottr via_reg(VIA1, vDirA) = via1_vDirA; 507 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 508 1.13 scottr if (s != 0x81815963) 509 1.13 scottr splx(s); 510 1.38 nat mutex_spin_exit(&pm_mutex); 511 1.13 scottr return 0xffffcd38; 512 1.1 scottr } 513 1.1 scottr 514 1.1 scottr /* send # of PM data */ 515 1.1 scottr num_pm_data = pmdata->num_data; 516 1.4 scottr if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0) 517 1.1 scottr break; /* timeout */ 518 1.1 scottr 519 1.1 scottr /* send PM data */ 520 1.1 scottr pm_buf = (u_char *)pmdata->s_buf; 521 1.4 scottr for (i = 0; i < num_pm_data; i++) 522 1.4 scottr if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0) 523 1.4 scottr break; /* timeout */ 524 1.1 scottr if ((i != num_pm_data) && (num_pm_data != 0)) 525 1.4 scottr break; /* timeout */ 526 1.1 scottr 527 1.1 scottr /* Will PM IC return data? */ 528 1.1 scottr if ((pm_cmd & 0x08) == 0) { 529 1.1 scottr rval = 0; 530 1.4 scottr break; /* no returned data */ 531 1.1 scottr } 532 1.1 scottr 533 1.1 scottr rval = 0xffffcd37; 534 1.4 scottr if (pm_wait_busy(ADBDelay) != 0) 535 1.1 scottr break; /* timeout */ 536 1.1 scottr 537 1.1 scottr /* receive PM command */ 538 1.4 scottr if ((rval = pm_receive_pm1(&pm_data)) != 0) 539 1.1 scottr break; 540 1.1 scottr 541 1.1 scottr pmdata->command = pm_data; 542 1.1 scottr 543 1.1 scottr /* receive number of PM data */ 544 1.4 scottr if ((rval = pm_receive_pm1(&pm_data)) != 0) 545 1.4 scottr break; /* timeout */ 546 1.1 scottr num_pm_data = pm_data; 547 1.1 scottr pmdata->num_data = num_pm_data; 548 1.1 scottr 549 1.1 scottr /* receive PM data */ 550 1.1 scottr pm_buf = (u_char *)pmdata->r_buf; 551 1.4 scottr for (i = 0; i < num_pm_data; i++) { 552 1.4 scottr if ((rval = pm_receive_pm1(&pm_data)) != 0) 553 1.12 scottr break; /* timeout */ 554 1.1 scottr pm_buf[i] = pm_data; 555 1.1 scottr } 556 1.1 scottr 557 1.1 scottr rval = 0; 558 1.1 scottr } 559 1.1 scottr 560 1.36 riastrad via_reg(VIA2, vDirA) = 0x00; 561 1.1 scottr 562 1.1 scottr /* restore formar value */ 563 1.1 scottr via_reg(VIA1, vDirA) = via1_vDirA; 564 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 565 1.1 scottr if (s != 0x81815963) 566 1.1 scottr splx(s); 567 1.1 scottr 568 1.38 nat mutex_spin_exit(&pm_mutex); 569 1.38 nat 570 1.5 scottr return rval; 571 1.1 scottr } 572 1.1 scottr 573 1.1 scottr 574 1.1 scottr /* 575 1.5 scottr * My PM interrupt routine for PB1XX series 576 1.1 scottr */ 577 1.1 scottr void 578 1.23 chs pm_intr_pm1(void *arg) 579 1.1 scottr { 580 1.4 scottr int s; 581 1.4 scottr int rval; 582 1.4 scottr PMData pmdata; 583 1.1 scottr 584 1.1 scottr s = splhigh(); 585 1.1 scottr 586 1.1 scottr PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 587 1.1 scottr 588 1.30 andvar /* ask PM what happened */ 589 1.1 scottr pmdata.command = 0x78; 590 1.1 scottr pmdata.num_data = 0; 591 1.1 scottr pmdata.data[0] = pmdata.data[1] = 0; 592 1.1 scottr pmdata.s_buf = &pmdata.data[2]; 593 1.1 scottr pmdata.r_buf = &pmdata.data[2]; 594 1.4 scottr rval = pm_pmgrop_pm1(&pmdata); 595 1.1 scottr if (rval != 0) { 596 1.3 scottr #ifdef ADB_DEBUG 597 1.3 scottr if (adb_debug) 598 1.3 scottr printf("pm: PM is not ready. error code=%08x\n", rval); 599 1.1 scottr #endif 600 1.1 scottr splx(s); 601 1.31 nat return; 602 1.1 scottr } 603 1.1 scottr 604 1.1 scottr if ((pmdata.data[2] & 0x10) == 0x10) { 605 1.4 scottr if ((pmdata.data[2] & 0x0f) == 0) { 606 1.4 scottr /* ADB data that were requested by TALK command */ 607 1.1 scottr pm_adb_get_TALK_result(&pmdata); 608 1.4 scottr } else if ((pmdata.data[2] & 0x08) == 0x8) { 609 1.4 scottr /* PM is requesting to poll */ 610 1.1 scottr pm_adb_poll_next_device_pm1(&pmdata); 611 1.4 scottr } else if ((pmdata.data[2] & 0x04) == 0x4) { 612 1.4 scottr /* ADB device event */ 613 1.1 scottr pm_adb_get_ADB_data(&pmdata); 614 1.1 scottr } 615 1.35 nat } else if ((pmdata.num_data == 0x1) && (pmdata.data[0] == 0)) { 616 1.35 nat /* PowerBook 160/180 Power button. */ 617 1.35 nat sysmon_pswitch_event(&pbutton, PSWITCH_EVENT_PRESSED); 618 1.1 scottr } else { 619 1.3 scottr #ifdef ADB_DEBUG 620 1.3 scottr if (adb_debug) 621 1.3 scottr pm_printerr("driver does not supported this event.", 622 1.3 scottr rval, pmdata.num_data, pmdata.data); 623 1.1 scottr #endif 624 1.1 scottr } 625 1.1 scottr 626 1.1 scottr splx(s); 627 1.1 scottr } 628 1.1 scottr 629 1.40 nat void 630 1.40 nat brightness_slider(void *arg) 631 1.40 nat { 632 1.40 nat int s; 633 1.40 nat int rval; 634 1.40 nat PMData pmdata; 635 1.40 nat 636 1.40 nat for (;;) { 637 1.41 nat kpause("brslider", false, hz / 4, NULL); 638 1.40 nat 639 1.40 nat s = splhigh(); 640 1.40 nat 641 1.40 nat pmdata.command = 0x49; 642 1.40 nat pmdata.num_data = 0; 643 1.40 nat pmdata.data[0] = pmdata.data[1] = 0; 644 1.40 nat pmdata.s_buf = &pmdata.data[0]; 645 1.40 nat pmdata.r_buf = &pmdata.data[0]; 646 1.40 nat rval = pm_pmgrop_pm1(&pmdata); 647 1.40 nat if (rval != 0) { 648 1.40 nat #ifdef ADB_DEBUG 649 1.40 nat if (adb_debug) { 650 1.40 nat printf("pm: PM is not ready. " 651 1.40 nat "error code=%08x\n", rval); 652 1.40 nat } 653 1.40 nat #endif 654 1.40 nat splx(s); 655 1.40 nat continue; 656 1.40 nat } 657 1.1 scottr 658 1.40 nat if (((uint8_t)pmdata.data[0] / 8) != pm_LCD_brightness) { 659 1.40 nat pm_LCD_brightness = (uint8_t)pmdata.data[0] / 8; 660 1.40 nat pm_LCD_brightness = 661 1.40 nat pm_set_brightness(pm_LCD_brightness); 662 1.40 nat } 663 1.40 nat 664 1.40 nat splx(s); 665 1.40 nat } 666 1.40 nat } 667 1.1 scottr 668 1.1 scottr /* 669 1.1 scottr * Functions for the PB Duo series and the PB 5XX series 670 1.1 scottr */ 671 1.1 scottr 672 1.1 scottr /* 673 1.1 scottr * Receive data from PM for the PB Duo series and the PB 5XX series 674 1.1 scottr */ 675 1.1 scottr int 676 1.23 chs pm_receive_pm2(u_char *data) 677 1.1 scottr { 678 1.4 scottr int rval; 679 1.1 scottr 680 1.1 scottr rval = 0xffffcd34; 681 1.1 scottr 682 1.4 scottr switch (1) { 683 1.1 scottr default: 684 1.1 scottr /* set VIA SR to input mode */ 685 1.1 scottr via_reg(VIA1, vACR) |= 0x0c; 686 1.1 scottr via_reg(VIA1, vACR) &= ~0x10; 687 1.29 martin PM_SR(); 688 1.1 scottr 689 1.1 scottr PM_SET_STATE_ACKOFF(); 690 1.1 scottr if (pm_wait_busy((int)ADBDelay*32) != 0) 691 1.1 scottr break; /* timeout */ 692 1.1 scottr 693 1.1 scottr PM_SET_STATE_ACKON(); 694 1.1 scottr rval = 0xffffcd33; 695 1.1 scottr if (pm_wait_free((int)ADBDelay*32) == 0) 696 1.1 scottr break; /* timeout */ 697 1.1 scottr 698 1.1 scottr *data = PM_SR(); 699 1.1 scottr rval = 0; 700 1.1 scottr 701 1.1 scottr break; 702 1.1 scottr } 703 1.1 scottr 704 1.1 scottr PM_SET_STATE_ACKON(); 705 1.1 scottr via_reg(VIA1, vACR) |= 0x1c; 706 1.1 scottr 707 1.5 scottr return rval; 708 1.36 riastrad } 709 1.1 scottr 710 1.1 scottr 711 1.1 scottr 712 1.1 scottr /* 713 1.1 scottr * Send data to PM for the PB Duo series and the PB 5XX series 714 1.1 scottr */ 715 1.1 scottr int 716 1.23 chs pm_send_pm2(u_char data) 717 1.1 scottr { 718 1.4 scottr int rval; 719 1.1 scottr 720 1.1 scottr via_reg(VIA1, vACR) |= 0x1c; 721 1.1 scottr PM_SR() = data; 722 1.1 scottr 723 1.1 scottr PM_SET_STATE_ACKOFF(); 724 1.14 scottr if (pm_wait_busy((int)ADBDelay*32) == 0) { 725 1.1 scottr PM_SET_STATE_ACKON(); 726 1.14 scottr if (pm_wait_free((int)ADBDelay*32) != 0) 727 1.14 scottr rval = 0; 728 1.14 scottr else 729 1.14 scottr rval = 0xffffcd35; 730 1.14 scottr } else { 731 1.14 scottr rval = 0xffffcd36; 732 1.1 scottr } 733 1.1 scottr 734 1.1 scottr PM_SET_STATE_ACKON(); 735 1.1 scottr via_reg(VIA1, vACR) |= 0x1c; 736 1.1 scottr 737 1.5 scottr return rval; 738 1.1 scottr } 739 1.1 scottr 740 1.1 scottr 741 1.1 scottr 742 1.1 scottr /* 743 1.1 scottr * My PMgrOp routine for the PB Duo series and the PB 5XX series 744 1.1 scottr */ 745 1.1 scottr int 746 1.23 chs pm_pmgrop_pm2(PMData *pmdata) 747 1.1 scottr { 748 1.4 scottr int i; 749 1.4 scottr int s; 750 1.4 scottr u_char via1_vIER; 751 1.4 scottr int rval = 0; 752 1.4 scottr int num_pm_data = 0; 753 1.36 riastrad u_char pm_cmd; 754 1.4 scottr short pm_num_rx_data; 755 1.4 scottr u_char pm_data; 756 1.4 scottr u_char *pm_buf; 757 1.1 scottr 758 1.38 nat mutex_spin_enter(&pm_mutex); 759 1.4 scottr s = splhigh(); 760 1.1 scottr 761 1.32 andvar /* disable all interrupts but PM */ 762 1.1 scottr via1_vIER = 0x10; 763 1.1 scottr via1_vIER &= via_reg(VIA1, vIER); 764 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 765 1.1 scottr if (via1_vIER != 0x0) 766 1.1 scottr via1_vIER |= 0x80; 767 1.1 scottr 768 1.4 scottr switch (pmdata->command) { 769 1.1 scottr default: 770 1.1 scottr /* wait until PM is free */ 771 1.1 scottr pm_cmd = (u_char)(pmdata->command & 0xff); 772 1.1 scottr rval = 0xcd38; 773 1.4 scottr if (pm_wait_free(ADBDelay * 4) == 0) 774 1.1 scottr break; /* timeout */ 775 1.1 scottr 776 1.36 riastrad if (HwCfgFlags3 & 0x00200000) { 777 1.4 scottr /* PB 160, PB 165(c), PB 180(c)? */ 778 1.24 jmc int xdelay = ADBDelay * 16; 779 1.1 scottr 780 1.1 scottr via_reg(VIA2, vDirA) = 0x00; 781 1.4 scottr while ((via_reg(VIA2, 0x200) == 0x07) && 782 1.24 jmc (xdelay >= 0)) 783 1.24 jmc xdelay--; 784 1.1 scottr 785 1.24 jmc if (xdelay < 0) { 786 1.1 scottr rval = 0xffffcd38; 787 1.1 scottr break; /* timeout */ 788 1.1 scottr } 789 1.1 scottr } 790 1.1 scottr 791 1.1 scottr /* send PM command */ 792 1.4 scottr if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff)))) 793 1.1 scottr break; /* timeout */ 794 1.1 scottr 795 1.1 scottr /* send number of PM data */ 796 1.1 scottr num_pm_data = pmdata->num_data; 797 1.1 scottr if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 798 1.1 scottr if (pm_send_cmd_type[pm_cmd] < 0) { 799 1.4 scottr if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 800 1.1 scottr break; /* timeout */ 801 1.1 scottr pmdata->command = 0; 802 1.1 scottr } 803 1.1 scottr } else { /* PB 1XX series ? */ 804 1.4 scottr if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0) 805 1.1 scottr break; /* timeout */ 806 1.36 riastrad } 807 1.1 scottr /* send PM data */ 808 1.1 scottr pm_buf = (u_char *)pmdata->s_buf; 809 1.4 scottr for (i = 0 ; i < num_pm_data; i++) 810 1.4 scottr if ((rval = pm_send_pm2(pm_buf[i])) != 0) 811 1.1 scottr break; /* timeout */ 812 1.1 scottr if (i != num_pm_data) 813 1.1 scottr break; /* timeout */ 814 1.1 scottr 815 1.1 scottr 816 1.1 scottr /* check if PM will send me data */ 817 1.1 scottr pm_num_rx_data = pm_receive_cmd_type[pm_cmd]; 818 1.1 scottr pmdata->num_data = pm_num_rx_data; 819 1.1 scottr if (pm_num_rx_data == 0) { 820 1.1 scottr rval = 0; 821 1.1 scottr break; /* no return data */ 822 1.1 scottr } 823 1.1 scottr 824 1.1 scottr /* receive PM command */ 825 1.1 scottr pm_data = pmdata->command; 826 1.1 scottr if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 827 1.1 scottr pm_num_rx_data--; 828 1.1 scottr if (pm_num_rx_data == 0) 829 1.4 scottr if ((rval = pm_receive_pm2(&pm_data)) != 0) { 830 1.1 scottr rval = 0xffffcd37; 831 1.1 scottr break; 832 1.1 scottr } 833 1.1 scottr pmdata->command = pm_data; 834 1.1 scottr } else { /* PB 1XX series ? */ 835 1.4 scottr if ((rval = pm_receive_pm2(&pm_data)) != 0) { 836 1.1 scottr rval = 0xffffcd37; 837 1.1 scottr break; 838 1.1 scottr } 839 1.1 scottr pmdata->command = pm_data; 840 1.1 scottr } 841 1.1 scottr 842 1.1 scottr /* receive number of PM data */ 843 1.1 scottr if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */ 844 1.1 scottr if (pm_num_rx_data < 0) { 845 1.4 scottr if ((rval = pm_receive_pm2(&pm_data)) != 0) 846 1.1 scottr break; /* timeout */ 847 1.1 scottr num_pm_data = pm_data; 848 1.1 scottr } else 849 1.1 scottr num_pm_data = pm_num_rx_data; 850 1.1 scottr pmdata->num_data = num_pm_data; 851 1.1 scottr } else { /* PB 1XX serias ? */ 852 1.4 scottr if ((rval = pm_receive_pm2(&pm_data)) != 0) 853 1.1 scottr break; /* timeout */ 854 1.1 scottr num_pm_data = pm_data; 855 1.1 scottr pmdata->num_data = num_pm_data; 856 1.1 scottr } 857 1.1 scottr 858 1.1 scottr /* receive PM data */ 859 1.1 scottr pm_buf = (u_char *)pmdata->r_buf; 860 1.4 scottr for (i = 0; i < num_pm_data; i++) { 861 1.4 scottr if ((rval = pm_receive_pm2(&pm_data)) != 0) 862 1.1 scottr break; /* timeout */ 863 1.1 scottr pm_buf[i] = pm_data; 864 1.1 scottr } 865 1.1 scottr 866 1.1 scottr rval = 0; 867 1.1 scottr } 868 1.1 scottr 869 1.1 scottr /* restore former value */ 870 1.1 scottr via_reg(VIA1, vIER) = via1_vIER; 871 1.1 scottr splx(s); 872 1.1 scottr 873 1.38 nat mutex_spin_exit(&pm_mutex); 874 1.5 scottr return rval; 875 1.1 scottr } 876 1.1 scottr 877 1.1 scottr 878 1.1 scottr /* 879 1.1 scottr * My PM interrupt routine for the PB Duo series and the PB 5XX series 880 1.1 scottr */ 881 1.1 scottr void 882 1.23 chs pm_intr_pm2(void *arg) 883 1.1 scottr { 884 1.4 scottr int s; 885 1.4 scottr int rval; 886 1.4 scottr PMData pmdata; 887 1.1 scottr 888 1.1 scottr s = splhigh(); 889 1.1 scottr 890 1.4 scottr PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */ 891 1.30 andvar /* ask PM what happened */ 892 1.1 scottr pmdata.command = 0x78; 893 1.1 scottr pmdata.num_data = 0; 894 1.1 scottr pmdata.s_buf = &pmdata.data[2]; 895 1.1 scottr pmdata.r_buf = &pmdata.data[2]; 896 1.4 scottr rval = pm_pmgrop_pm2(&pmdata); 897 1.1 scottr if (rval != 0) { 898 1.3 scottr #ifdef ADB_DEBUG 899 1.3 scottr if (adb_debug) 900 1.3 scottr printf("pm: PM is not ready. error code: %08x\n", rval); 901 1.1 scottr #endif 902 1.1 scottr splx(s); 903 1.31 nat return; 904 1.1 scottr } 905 1.1 scottr 906 1.4 scottr switch ((u_int)(pmdata.data[2] & 0xff)) { 907 1.4 scottr case 0x00: /* 1 sec interrupt? */ 908 1.1 scottr break; 909 1.4 scottr case 0x80: /* 1 sec interrupt? */ 910 1.1 scottr pm_counter++; 911 1.1 scottr break; 912 1.37 nat case 0x08: /* Brightness/Contrast button on LCD panel */ 913 1.1 scottr /* get brightness and contrast of the LCD */ 914 1.1 scottr pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff; 915 1.1 scottr pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff; 916 1.1 scottr /* 917 1.4 scottr pm_printerr("#08", rval, pmdata.num_data, pmdata.data); 918 1.1 scottr pmdata.command = 0x33; 919 1.1 scottr pmdata.num_data = 1; 920 1.1 scottr pmdata.s_buf = pmdata.data; 921 1.1 scottr pmdata.r_buf = pmdata.data; 922 1.1 scottr pmdata.data[0] = pm_LCD_contrast; 923 1.4 scottr rval = pm_pmgrop_pm2(&pmdata); 924 1.4 scottr pm_printerr("#33", rval, pmdata.num_data, pmdata.data); 925 1.1 scottr */ 926 1.33 nat pm_LCD_brightness = 927 1.33 nat pm_set_brightness(pm_LCD_brightness); 928 1.1 scottr break; 929 1.4 scottr case 0x10: /* ADB data that were requested by TALK command */ 930 1.1 scottr case 0x14: 931 1.1 scottr pm_adb_get_TALK_result(&pmdata); 932 1.1 scottr break; 933 1.4 scottr case 0x16: /* ADB device event */ 934 1.1 scottr case 0x18: 935 1.1 scottr case 0x1e: 936 1.1 scottr pm_adb_get_ADB_data(&pmdata); 937 1.1 scottr break; 938 1.1 scottr default: 939 1.3 scottr #ifdef ADB_DEBUG 940 1.3 scottr if (adb_debug) 941 1.3 scottr pm_printerr("driver does not supported this event.", 942 1.3 scottr pmdata.data[2], pmdata.num_data, 943 1.3 scottr pmdata.data); 944 1.1 scottr #endif 945 1.1 scottr break; 946 1.1 scottr } 947 1.1 scottr 948 1.1 scottr splx(s); 949 1.1 scottr } 950 1.1 scottr 951 1.1 scottr 952 1.1 scottr /* 953 1.1 scottr * MRG-based PMgrOp routine 954 1.1 scottr */ 955 1.1 scottr int 956 1.23 chs pm_pmgrop_mrg(PMData *pmdata) 957 1.1 scottr { 958 1.1 scottr u_int32_t rval=0; 959 1.1 scottr 960 1.27 perry __asm volatile( 961 1.20 thorpej " movl %1,%%a0 \n" 962 1.20 thorpej " .word 0xa085 \n" 963 1.20 thorpej " movl %%d0,%0" 964 1.1 scottr : "=g" (rval) 965 1.1 scottr : "g" (pmdata) 966 1.18 chs : "a0","d0"); 967 1.1 scottr 968 1.1 scottr return rval; 969 1.1 scottr } 970 1.1 scottr 971 1.1 scottr 972 1.1 scottr /* 973 1.1 scottr * My PMgrOp routine 974 1.1 scottr */ 975 1.1 scottr int 976 1.23 chs pmgrop(PMData *pmdata) 977 1.1 scottr { 978 1.4 scottr switch (pmHardware) { 979 1.1 scottr case PM_HW_PB1XX: 980 1.4 scottr return (pm_pmgrop_pm1(pmdata)); 981 1.1 scottr break; 982 1.1 scottr case PM_HW_PB5XX: 983 1.4 scottr return (pm_pmgrop_pm2(pmdata)); 984 1.1 scottr break; 985 1.1 scottr default: 986 1.4 scottr /* return (pmgrop_mrg(pmdata)); */ 987 1.5 scottr return 1; 988 1.1 scottr } 989 1.1 scottr } 990 1.1 scottr 991 1.1 scottr 992 1.1 scottr /* 993 1.1 scottr * My PM interrupt routine 994 1.1 scottr */ 995 1.1 scottr void 996 1.23 chs pm_intr(void *arg) 997 1.1 scottr { 998 1.4 scottr switch (pmHardware) { 999 1.1 scottr case PM_HW_PB1XX: 1000 1.9 briggs pm_intr_pm1(arg); 1001 1.1 scottr break; 1002 1.1 scottr case PM_HW_PB5XX: 1003 1.9 briggs pm_intr_pm2(arg); 1004 1.1 scottr break; 1005 1.1 scottr default: 1006 1.1 scottr break; 1007 1.1 scottr } 1008 1.1 scottr } 1009 1.1 scottr 1010 1.1 scottr 1011 1.9 briggs void 1012 1.23 chs pm_hw_setup(void) 1013 1.9 briggs { 1014 1.9 briggs switch (pmHardware) { 1015 1.9 briggs case PM_HW_PB1XX: 1016 1.9 briggs via1_register_irq(4, pm_intr_pm1, (void *)0); 1017 1.9 briggs PM_VIA_CLR_INTR(); 1018 1.9 briggs break; 1019 1.9 briggs case PM_HW_PB5XX: 1020 1.9 briggs via1_register_irq(4, pm_intr_pm2, (void *)0); 1021 1.9 briggs PM_VIA_CLR_INTR(); 1022 1.9 briggs break; 1023 1.9 briggs default: 1024 1.9 briggs break; 1025 1.9 briggs } 1026 1.9 briggs } 1027 1.9 briggs 1028 1.1 scottr 1029 1.1 scottr /* 1030 1.1 scottr * Synchronous ADBOp routine for the Power Manager 1031 1.1 scottr */ 1032 1.1 scottr int 1033 1.23 chs pm_adb_op(u_char *buffer, void *compRout, void *data, int command) 1034 1.1 scottr { 1035 1.5 scottr int i; 1036 1.4 scottr int s; 1037 1.4 scottr int rval; 1038 1.24 jmc int xdelay; 1039 1.4 scottr PMData pmdata; 1040 1.5 scottr struct adbCommand packet; 1041 1.1 scottr 1042 1.1 scottr if (adbWaiting == 1) 1043 1.5 scottr return 1; 1044 1.1 scottr 1045 1.1 scottr s = splhigh(); 1046 1.1 scottr via_reg(VIA1, vIER) = 0x10; 1047 1.1 scottr 1048 1.1 scottr adbBuffer = buffer; 1049 1.1 scottr adbCompRout = compRout; 1050 1.1 scottr adbCompData = data; 1051 1.1 scottr 1052 1.1 scottr pmdata.command = 0x20; 1053 1.1 scottr pmdata.s_buf = pmdata.data; 1054 1.1 scottr pmdata.r_buf = pmdata.data; 1055 1.1 scottr 1056 1.1 scottr if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */ 1057 1.1 scottr if (buffer != (u_char *)0) 1058 1.1 scottr pmdata.num_data = buffer[0] + 3; 1059 1.1 scottr } else { 1060 1.1 scottr pmdata.num_data = 3; 1061 1.1 scottr } 1062 1.1 scottr 1063 1.1 scottr pmdata.data[0] = (u_char)(command & 0xff); 1064 1.1 scottr pmdata.data[1] = 0; 1065 1.1 scottr if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */ 1066 1.1 scottr if ((buffer != (u_char *)0) && (buffer[0] <= 24)) { 1067 1.1 scottr pmdata.data[2] = buffer[0]; /* number of data */ 1068 1.4 scottr for (i = 0; i < buffer[0]; i++) 1069 1.1 scottr pmdata.data[3 + i] = buffer[1 + i]; 1070 1.1 scottr } else 1071 1.1 scottr pmdata.data[2] = 0; 1072 1.1 scottr } else 1073 1.1 scottr pmdata.data[2] = 0; 1074 1.1 scottr 1075 1.5 scottr if ((command & 0xc) != 0xc) { /* if the command is not TALK */ 1076 1.9 briggs /* set up stuff fNULLor adb_pass_up */ 1077 1.5 scottr packet.data[0] = 1 + pmdata.data[2]; 1078 1.5 scottr packet.data[1] = command; 1079 1.5 scottr for (i = 0; i < pmdata.data[2]; i++) 1080 1.5 scottr packet.data[i+2] = pmdata.data[i+3]; 1081 1.5 scottr packet.saveBuf = adbBuffer; 1082 1.5 scottr packet.compRout = adbCompRout; 1083 1.5 scottr packet.compData = adbCompData; 1084 1.5 scottr packet.cmd = command; 1085 1.5 scottr packet.unsol = 0; 1086 1.5 scottr packet.ack_only = 1; 1087 1.10 scottr adb_polling = 1; 1088 1.5 scottr adb_pass_up(&packet); 1089 1.10 scottr adb_polling = 0; 1090 1.5 scottr } 1091 1.5 scottr 1092 1.4 scottr rval = pmgrop(&pmdata); 1093 1.12 scottr if (rval != 0) { 1094 1.12 scottr splx(s); 1095 1.5 scottr return 1; 1096 1.12 scottr } 1097 1.1 scottr 1098 1.5 scottr adbWaiting = 1; 1099 1.5 scottr adbWaitingCmd = command; 1100 1.1 scottr 1101 1.1 scottr PM_VIA_INTR_ENABLE(); 1102 1.1 scottr 1103 1.17 wiz /* wait until the PM interrupt has occurred */ 1104 1.24 jmc xdelay = 0x80000; 1105 1.4 scottr while (adbWaiting == 1) { 1106 1.15 scottr switch (mac68k_machine.machineid) { 1107 1.19 shiba case MACH_MACPB150: 1108 1.15 scottr case MACH_MACPB210: 1109 1.15 scottr case MACH_MACPB230: /* daishi tested with Duo230 */ 1110 1.15 scottr case MACH_MACPB250: 1111 1.15 scottr case MACH_MACPB270: 1112 1.15 scottr case MACH_MACPB280: 1113 1.15 scottr case MACH_MACPB280C: 1114 1.21 shiba case MACH_MACPB190: 1115 1.21 shiba case MACH_MACPB190CS: 1116 1.9 briggs pm_intr((void *)0); 1117 1.15 scottr break; 1118 1.15 scottr default: 1119 1.15 scottr if ((via_reg(VIA1, vIFR) & 0x10) == 0x10) 1120 1.15 scottr pm_intr((void *)0); 1121 1.15 scottr break; 1122 1.15 scottr } 1123 1.1 scottr #ifdef PM_GRAB_SI 1124 1.15 scottr (void)intr_dispatch(0x70); /* grab any serial interrupts */ 1125 1.1 scottr #endif 1126 1.24 jmc if ((--xdelay) < 0) { 1127 1.12 scottr splx(s); 1128 1.5 scottr return 1; 1129 1.12 scottr } 1130 1.1 scottr } 1131 1.1 scottr 1132 1.4 scottr /* this command enables the interrupt by operating ADB devices */ 1133 1.5 scottr if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */ 1134 1.1 scottr pmdata.command = 0x20; 1135 1.1 scottr pmdata.num_data = 4; 1136 1.1 scottr pmdata.s_buf = pmdata.data; 1137 1.1 scottr pmdata.r_buf = pmdata.data; 1138 1.36 riastrad pmdata.data[0] = 0x00; 1139 1.1 scottr pmdata.data[1] = 0x86; /* magic spell for awaking the PM */ 1140 1.36 riastrad pmdata.data[2] = 0x00; 1141 1.1 scottr pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */ 1142 1.5 scottr } else { /* PB 1XX series */ 1143 1.1 scottr pmdata.command = 0x20; 1144 1.1 scottr pmdata.num_data = 3; 1145 1.1 scottr pmdata.s_buf = pmdata.data; 1146 1.1 scottr pmdata.r_buf = pmdata.data; 1147 1.1 scottr pmdata.data[0] = (u_char)(command & 0xf0) | 0xc; 1148 1.1 scottr pmdata.data[1] = 0x04; 1149 1.1 scottr pmdata.data[2] = 0x00; 1150 1.1 scottr } 1151 1.4 scottr rval = pmgrop(&pmdata); 1152 1.1 scottr 1153 1.1 scottr splx(s); 1154 1.5 scottr return rval; 1155 1.1 scottr } 1156 1.1 scottr 1157 1.1 scottr 1158 1.1 scottr void 1159 1.23 chs pm_adb_get_TALK_result(PMData *pmdata) 1160 1.1 scottr { 1161 1.1 scottr int i; 1162 1.5 scottr struct adbCommand packet; 1163 1.1 scottr 1164 1.5 scottr /* set up data for adb_pass_up */ 1165 1.5 scottr packet.data[0] = pmdata->num_data-1; 1166 1.5 scottr packet.data[1] = pmdata->data[3]; 1167 1.5 scottr for (i = 0; i <packet.data[0]-1; i++) 1168 1.5 scottr packet.data[i+2] = pmdata->data[i+4]; 1169 1.5 scottr 1170 1.5 scottr packet.saveBuf = adbBuffer; 1171 1.5 scottr packet.compRout = adbCompRout; 1172 1.5 scottr packet.compData = adbCompData; 1173 1.5 scottr packet.unsol = 0; 1174 1.5 scottr packet.ack_only = 0; 1175 1.10 scottr adb_polling = 1; 1176 1.5 scottr adb_pass_up(&packet); 1177 1.10 scottr adb_polling = 0; 1178 1.5 scottr 1179 1.5 scottr adbWaiting = 0; 1180 1.5 scottr adbBuffer = (long)0; 1181 1.5 scottr adbCompRout = (long)0; 1182 1.5 scottr adbCompData = (long)0; 1183 1.1 scottr } 1184 1.1 scottr 1185 1.1 scottr 1186 1.1 scottr void 1187 1.23 chs pm_adb_get_ADB_data(PMData *pmdata) 1188 1.1 scottr { 1189 1.1 scottr int i; 1190 1.5 scottr struct adbCommand packet; 1191 1.1 scottr 1192 1.5 scottr /* set up data for adb_pass_up */ 1193 1.5 scottr packet.data[0] = pmdata->num_data-1; /* number of raw data */ 1194 1.5 scottr packet.data[1] = pmdata->data[3]; /* ADB command */ 1195 1.5 scottr for (i = 0; i <packet.data[0]-1; i++) 1196 1.5 scottr packet.data[i+2] = pmdata->data[i+4]; 1197 1.5 scottr packet.unsol = 1; 1198 1.5 scottr packet.ack_only = 0; 1199 1.5 scottr adb_pass_up(&packet); 1200 1.1 scottr } 1201 1.1 scottr 1202 1.1 scottr 1203 1.1 scottr void 1204 1.23 chs pm_adb_poll_next_device_pm1(PMData *pmdata) 1205 1.1 scottr { 1206 1.1 scottr int i; 1207 1.1 scottr int ndid; 1208 1.1 scottr u_short bendid = 0x1; 1209 1.1 scottr PMData tmp_pmdata; 1210 1.1 scottr 1211 1.1 scottr /* find another existent ADB device to poll */ 1212 1.4 scottr for (i = 1; i < 16; i++) { 1213 1.11 scottr ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf; 1214 1.1 scottr bendid <<= ndid; 1215 1.1 scottr if ((pm_existent_ADB_devices & bendid) != 0) 1216 1.1 scottr break; 1217 1.1 scottr } 1218 1.1 scottr 1219 1.1 scottr /* poll the other device */ 1220 1.1 scottr tmp_pmdata.command = 0x20; 1221 1.1 scottr tmp_pmdata.num_data = 3; 1222 1.1 scottr tmp_pmdata.s_buf = tmp_pmdata.data; 1223 1.1 scottr tmp_pmdata.r_buf = tmp_pmdata.data; 1224 1.1 scottr tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc; 1225 1.1 scottr tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */ 1226 1.1 scottr tmp_pmdata.data[2] = 0x00; 1227 1.29 martin pmgrop(&tmp_pmdata); 1228 1.1 scottr } 1229 1.34 nat 1230 1.36 riastrad void 1231 1.34 nat pm_poweroff(void) 1232 1.34 nat { 1233 1.34 nat PMData pmdata; 1234 1.34 nat int attempt = 3; 1235 1.34 nat 1236 1.34 nat while (pmHardware == PM_HW_PB1XX && attempt > 0) { 1237 1.39 nat pmdata.command = 0xef; 1238 1.34 nat pmdata.num_data = 0; 1239 1.34 nat pmdata.data[0] = pmdata.data[1] = 0; 1240 1.34 nat pmdata.s_buf = &pmdata.data[2]; 1241 1.34 nat pmdata.r_buf = &pmdata.data[2]; 1242 1.34 nat (void)pm_pmgrop_pm1(&pmdata); 1243 1.34 nat attempt--; 1244 1.36 riastrad } 1245 1.34 nat 1246 1.34 nat return; 1247 1.34 nat } 1248 1.34 nat 1249 1.33 nat u_int 1250 1.33 nat pm_set_brightness(u_int brightness) 1251 1.33 nat { 1252 1.33 nat PMData pmdata; 1253 1.33 nat 1254 1.33 nat pmdata.num_data = 1; 1255 1.33 nat pmdata.s_buf = pmdata.data; 1256 1.33 nat pmdata.r_buf = pmdata.data; 1257 1.33 nat 1258 1.33 nat switch (pmHardware) { 1259 1.33 nat case PM_HW_PB5XX: 1260 1.33 nat /* this is an experimental code */ 1261 1.33 nat pmdata.command = 0x41; 1262 1.37 nat if ((int)brightness < 0) 1263 1.37 nat brightness = 0; 1264 1.37 nat if ((int)brightness > 31) 1265 1.37 nat brightness = 31; 1266 1.37 nat pmdata.data[0] = (31 - brightness) * 23 / 10 + 37; 1267 1.33 nat (void)pm_pmgrop_pm2(&pmdata); 1268 1.33 nat break; 1269 1.33 nat case PM_HW_PB1XX: 1270 1.33 nat /* this is an experimental code also */ 1271 1.33 nat pmdata.command = 0x40; 1272 1.33 nat if ((int)brightness < 0) 1273 1.33 nat brightness = 0; 1274 1.33 nat if ((int)brightness > 31) 1275 1.33 nat brightness = 31; 1276 1.33 nat pmdata.data[0] = 31 - brightness; 1277 1.33 nat (void)pm_pmgrop_pm1(&pmdata); 1278 1.33 nat break; 1279 1.33 nat default: 1280 1.33 nat 1281 1.33 nat return 0; 1282 1.33 nat break; 1283 1.33 nat } 1284 1.33 nat 1285 1.33 nat return brightness; 1286 1.33 nat } 1287 1.43 nat 1288 1.43 nat static void 1289 1.43 nat brightness_sysctl_setup(void *arg) 1290 1.43 nat { 1291 1.43 nat const struct sysctlnode *rnode; 1292 1.43 nat 1293 1.43 nat if ((sysctl_createv(&sc_log, 0, NULL, &rnode, 1294 1.43 nat 0, CTLTYPE_NODE, "screen", 1295 1.43 nat SYSCTL_DESCR("Internal display output device controls"), 1296 1.43 nat NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) 1297 1.43 nat goto fail; 1298 1.43 nat 1299 1.43 nat (void)sysctl_createv(&sc_log, 0, &rnode, NULL, 1300 1.43 nat CTLFLAG_READWRITE, CTLTYPE_INT, "brightness", 1301 1.43 nat SYSCTL_DESCR("Current brightness level"), 1302 1.43 nat sysctl_brightness, 0, NULL, 0, CTL_CREATE, CTL_EOL); 1303 1.43 nat 1304 1.43 nat return; 1305 1.43 nat 1306 1.43 nat fail: 1307 1.43 nat aprint_error("screen: couldn't add sysctl nodes\n"); 1308 1.43 nat } 1309 1.43 nat 1310 1.43 nat static int 1311 1.43 nat sysctl_brightness(SYSCTLFN_ARGS) 1312 1.43 nat { 1313 1.43 nat struct sysctlnode node; 1314 1.43 nat int val, error; 1315 1.43 nat 1316 1.43 nat node = *rnode; 1317 1.43 nat 1318 1.43 nat val = pm_LCD_brightness; 1319 1.43 nat 1320 1.43 nat node.sysctl_data = &val; 1321 1.43 nat error = sysctl_lookup(SYSCTLFN_CALL(&node)); 1322 1.43 nat if (error || newp == NULL) 1323 1.43 nat return error; 1324 1.43 nat 1325 1.43 nat val = pm_set_brightness(val); 1326 1.43 nat 1327 1.43 nat return error; 1328 1.43 nat } 1329