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