pm_direct.c revision 1.42 1 /* $NetBSD: pm_direct.c,v 1.42 2025/05/12 00:28:07 nat Exp $ */
2
3 /*
4 * Copyright (c) 2024, 2025 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.42 2025/05/12 00:28:07 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/kthread.h>
52 #include <sys/proc.h>
53 #include <sys/mutex.h>
54 #include <sys/systm.h>
55
56 #include <dev/sysmon/sysmonvar.h>
57
58 #include <machine/viareg.h>
59 #include <machine/param.h>
60 #include <machine/cpu.h>
61 #include <machine/adbsys.h>
62
63 #include <mac68k/mac68k/macrom.h>
64 #include <mac68k/dev/adbvar.h>
65 #include <mac68k/dev/pm_direct.h>
66
67 /* hardware dependent values */
68 extern u_short ADBDelay;
69 extern u_int32_t HwCfgFlags3;
70 extern struct mac68k_machine_S mac68k_machine;
71
72
73 /* useful macros */
74 #define PM_SR() via_reg(VIA1, vSR)
75 #define PM_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x90
76 #define PM_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x10
77 #define PM_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x90
78 #define PM_SET_STATE_ACKON() via_reg(VIA2, vBufB) |= 0x04
79 #define PM_SET_STATE_ACKOFF() via_reg(VIA2, vBufB) &= ~0x04
80 #define PM_IS_ON (0x02 == (via_reg(VIA2, vBufB) & 0x02))
81 #define PM_IS_OFF (0x00 == (via_reg(VIA2, vBufB) & 0x02))
82
83 /*
84 * Variables for internal use
85 */
86 int pmHardware = PM_HW_UNKNOWN;
87 u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */
88 u_int pm_LCD_brightness = 0x0;
89 u_int pm_LCD_contrast = 0x0;
90 u_int pm_counter = 0; /* clock count */
91 struct sysmon_pswitch pbutton;
92
93 /* these values shows that number of data returned after 'send' cmd is sent */
94 char pm_send_cmd_type[] = {
95 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
96 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
97 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
99 0xff, 0x00, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff,
100 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101 0x04, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
102 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff,
103 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
104 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
105 0x01, 0x00, 0x02, 0x02, 0xff, 0x01, 0x03, 0x01,
106 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
107 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
109 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
110 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04, 0x04,
111 0x04, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
112 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
113 0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
114 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115 0x02, 0x02, 0x02, 0x04, 0xff, 0x00, 0xff, 0xff,
116 0x01, 0x01, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff,
117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
120 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
121 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
122 0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
123 0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
124 0x03, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
126 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
127 };
128
129 /* these values shows that number of data returned after 'receive' cmd is sent */
130 char pm_receive_cmd_type[] = {
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x05, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x02, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x04, 0x04, 0x03, 0x09, 0xff, 0xff, 0xff, 0xff,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff,
159 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
163 };
164
165
166 /* Spin mutex to seriaize powermanager requests. */
167 kmutex_t pm_mutex;
168
169 /*
170 * Define the private functions
171 */
172
173 /* for debugging */
174 #ifdef ADB_DEBUG
175 void pm_printerr(const char *, int, int, char *);
176 #endif
177
178 int pm_wait_busy(int);
179 int pm_wait_free(int);
180
181 /* these functions are for the PB1XX series */
182 int pm_receive_pm1(u_char *);
183 int pm_send_pm1(u_char, int);
184 int pm_pmgrop_pm1(PMData *);
185 void pm_intr_pm1(void *);
186 void brightness_slider(void *); /* brightness slider thread */
187
188 /* these functions are for the PB Duo series and the PB 5XX series */
189 int pm_receive_pm2(u_char *);
190 int pm_send_pm2(u_char);
191 int pm_pmgrop_pm2(PMData *);
192 void pm_intr_pm2(void *);
193
194 /* this function is MRG-Based (for testing) */
195 int pm_pmgrop_mrg(PMData *);
196
197 /* these functions are called from adb_direct.c */
198 void pm_setup_adb(void);
199 void pm_check_adb_devices(int);
200 void pm_intr(void *);
201 int pm_adb_op(u_char *, void *, void *, int);
202 void pm_hw_setup(void);
203
204 /* these functions also use the variables of adb_direct.c */
205 void pm_adb_get_TALK_result(PMData *);
206 void pm_adb_get_ADB_data(PMData *);
207 void pm_adb_poll_next_device_pm1(PMData *);
208
209
210 /*
211 * These variables are in adb_direct.c.
212 */
213 extern u_char *adbBuffer; /* pointer to user data area */
214 extern void *adbCompRout; /* pointer to the completion routine */
215 extern void *adbCompData; /* pointer to the completion routine data */
216 extern int adbWaiting; /* waiting for return data from the device */
217 extern int adbWaitingCmd; /* ADB command we are waiting for */
218 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
219
220 #define ADB_MAX_MSG_LENGTH 16
221 #define ADB_MAX_HDR_LENGTH 8
222 struct adbCommand {
223 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
224 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
225 u_char *saveBuf; /* where to save result */
226 u_char *compRout; /* completion routine pointer */
227 u_char *compData; /* completion routine data pointer */
228 u_int cmd; /* the original command for this data */
229 u_int unsol; /* 1 if packet was unsolicited */
230 u_int ack_only; /* 1 for no special processing */
231 };
232 extern void adb_pass_up(struct adbCommand *);
233
234 #ifdef ADB_DEBUG
235 /*
236 * This function dumps contents of the PMData
237 */
238 void
239 pm_printerr(const char *ttl, int rval, int num, char *data)
240 {
241 int i;
242
243 printf("pm: %s:%04x %02x ", ttl, rval, num);
244 for (i = 0; i < num; i++)
245 printf("%02x ", data[i]);
246 printf("\n");
247 }
248 #endif
249
250
251
252 /*
253 * Check the hardware type of the Power Manager
254 */
255 void
256 pm_setup_adb(void)
257 {
258 mutex_init(&pm_mutex, MUTEX_DEFAULT, IPL_HIGH);
259 switch (mac68k_machine.machineid) {
260 case MACH_MACPB140:
261 case MACH_MACPB145:
262 case MACH_MACPB160:
263 case MACH_MACPB165:
264 case MACH_MACPB165C:
265 case MACH_MACPB170:
266 case MACH_MACPB180:
267 case MACH_MACPB180C:
268 pmHardware = PM_HW_PB1XX;
269
270 memset(&pbutton, 0, sizeof(struct sysmon_pswitch));
271 pbutton.smpsw_name = "PB";
272 pbutton.smpsw_type = PSWITCH_TYPE_POWER;
273 if (sysmon_pswitch_register(&pbutton) != 0)
274 printf("Unable to register soft power\n");
275 kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
276 brightness_slider, NULL, NULL, "britethrd");
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 void
625 brightness_slider(void *arg)
626 {
627 int s;
628 int rval;
629 PMData pmdata;
630
631 for (;;) {
632 kpause("brslider", false, hz / 4, NULL);
633
634 s = splhigh();
635
636 pmdata.command = 0x49;
637 pmdata.num_data = 0;
638 pmdata.data[0] = pmdata.data[1] = 0;
639 pmdata.s_buf = &pmdata.data[0];
640 pmdata.r_buf = &pmdata.data[0];
641 rval = pm_pmgrop_pm1(&pmdata);
642 if (rval != 0) {
643 #ifdef ADB_DEBUG
644 if (adb_debug) {
645 printf("pm: PM is not ready. "
646 "error code=%08x\n", rval);
647 }
648 #endif
649 splx(s);
650 continue;
651 }
652
653 if (((uint8_t)pmdata.data[0] / 8) != pm_LCD_brightness) {
654 pm_LCD_brightness = (uint8_t)pmdata.data[0] / 8;
655 pm_LCD_brightness =
656 pm_set_brightness(pm_LCD_brightness);
657 }
658
659 splx(s);
660 }
661 }
662
663 /*
664 * Functions for the PB Duo series and the PB 5XX series
665 */
666
667 /*
668 * Receive data from PM for the PB Duo series and the PB 5XX series
669 */
670 int
671 pm_receive_pm2(u_char *data)
672 {
673 int rval;
674
675 rval = 0xffffcd34;
676
677 switch (1) {
678 default:
679 /* set VIA SR to input mode */
680 via_reg(VIA1, vACR) |= 0x0c;
681 via_reg(VIA1, vACR) &= ~0x10;
682 PM_SR();
683
684 PM_SET_STATE_ACKOFF();
685 if (pm_wait_busy((int)ADBDelay*32) != 0)
686 break; /* timeout */
687
688 PM_SET_STATE_ACKON();
689 rval = 0xffffcd33;
690 if (pm_wait_free((int)ADBDelay*32) == 0)
691 break; /* timeout */
692
693 *data = PM_SR();
694 rval = 0;
695
696 break;
697 }
698
699 PM_SET_STATE_ACKON();
700 via_reg(VIA1, vACR) |= 0x1c;
701
702 return rval;
703 }
704
705
706
707 /*
708 * Send data to PM for the PB Duo series and the PB 5XX series
709 */
710 int
711 pm_send_pm2(u_char data)
712 {
713 int rval;
714
715 via_reg(VIA1, vACR) |= 0x1c;
716 PM_SR() = data;
717
718 PM_SET_STATE_ACKOFF();
719 if (pm_wait_busy((int)ADBDelay*32) == 0) {
720 PM_SET_STATE_ACKON();
721 if (pm_wait_free((int)ADBDelay*32) != 0)
722 rval = 0;
723 else
724 rval = 0xffffcd35;
725 } else {
726 rval = 0xffffcd36;
727 }
728
729 PM_SET_STATE_ACKON();
730 via_reg(VIA1, vACR) |= 0x1c;
731
732 return rval;
733 }
734
735
736
737 /*
738 * My PMgrOp routine for the PB Duo series and the PB 5XX series
739 */
740 int
741 pm_pmgrop_pm2(PMData *pmdata)
742 {
743 int i;
744 int s;
745 u_char via1_vIER;
746 int rval = 0;
747 int num_pm_data = 0;
748 u_char pm_cmd;
749 short pm_num_rx_data;
750 u_char pm_data;
751 u_char *pm_buf;
752
753 mutex_spin_enter(&pm_mutex);
754 s = splhigh();
755
756 /* disable all interrupts but PM */
757 via1_vIER = 0x10;
758 via1_vIER &= via_reg(VIA1, vIER);
759 via_reg(VIA1, vIER) = via1_vIER;
760 if (via1_vIER != 0x0)
761 via1_vIER |= 0x80;
762
763 switch (pmdata->command) {
764 default:
765 /* wait until PM is free */
766 pm_cmd = (u_char)(pmdata->command & 0xff);
767 rval = 0xcd38;
768 if (pm_wait_free(ADBDelay * 4) == 0)
769 break; /* timeout */
770
771 if (HwCfgFlags3 & 0x00200000) {
772 /* PB 160, PB 165(c), PB 180(c)? */
773 int xdelay = ADBDelay * 16;
774
775 via_reg(VIA2, vDirA) = 0x00;
776 while ((via_reg(VIA2, 0x200) == 0x07) &&
777 (xdelay >= 0))
778 xdelay--;
779
780 if (xdelay < 0) {
781 rval = 0xffffcd38;
782 break; /* timeout */
783 }
784 }
785
786 /* send PM command */
787 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
788 break; /* timeout */
789
790 /* send number of PM data */
791 num_pm_data = pmdata->num_data;
792 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
793 if (pm_send_cmd_type[pm_cmd] < 0) {
794 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
795 break; /* timeout */
796 pmdata->command = 0;
797 }
798 } else { /* PB 1XX series ? */
799 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
800 break; /* timeout */
801 }
802 /* send PM data */
803 pm_buf = (u_char *)pmdata->s_buf;
804 for (i = 0 ; i < num_pm_data; i++)
805 if ((rval = pm_send_pm2(pm_buf[i])) != 0)
806 break; /* timeout */
807 if (i != num_pm_data)
808 break; /* timeout */
809
810
811 /* check if PM will send me data */
812 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
813 pmdata->num_data = pm_num_rx_data;
814 if (pm_num_rx_data == 0) {
815 rval = 0;
816 break; /* no return data */
817 }
818
819 /* receive PM command */
820 pm_data = pmdata->command;
821 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
822 pm_num_rx_data--;
823 if (pm_num_rx_data == 0)
824 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
825 rval = 0xffffcd37;
826 break;
827 }
828 pmdata->command = pm_data;
829 } else { /* PB 1XX series ? */
830 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
831 rval = 0xffffcd37;
832 break;
833 }
834 pmdata->command = pm_data;
835 }
836
837 /* receive number of PM data */
838 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
839 if (pm_num_rx_data < 0) {
840 if ((rval = pm_receive_pm2(&pm_data)) != 0)
841 break; /* timeout */
842 num_pm_data = pm_data;
843 } else
844 num_pm_data = pm_num_rx_data;
845 pmdata->num_data = num_pm_data;
846 } else { /* PB 1XX serias ? */
847 if ((rval = pm_receive_pm2(&pm_data)) != 0)
848 break; /* timeout */
849 num_pm_data = pm_data;
850 pmdata->num_data = num_pm_data;
851 }
852
853 /* receive PM data */
854 pm_buf = (u_char *)pmdata->r_buf;
855 for (i = 0; i < num_pm_data; i++) {
856 if ((rval = pm_receive_pm2(&pm_data)) != 0)
857 break; /* timeout */
858 pm_buf[i] = pm_data;
859 }
860
861 rval = 0;
862 }
863
864 /* restore former value */
865 via_reg(VIA1, vIER) = via1_vIER;
866 splx(s);
867
868 mutex_spin_exit(&pm_mutex);
869 return rval;
870 }
871
872
873 /*
874 * My PM interrupt routine for the PB Duo series and the PB 5XX series
875 */
876 void
877 pm_intr_pm2(void *arg)
878 {
879 int s;
880 int rval;
881 PMData pmdata;
882
883 s = splhigh();
884
885 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
886 /* ask PM what happened */
887 pmdata.command = 0x78;
888 pmdata.num_data = 0;
889 pmdata.s_buf = &pmdata.data[2];
890 pmdata.r_buf = &pmdata.data[2];
891 rval = pm_pmgrop_pm2(&pmdata);
892 if (rval != 0) {
893 #ifdef ADB_DEBUG
894 if (adb_debug)
895 printf("pm: PM is not ready. error code: %08x\n", rval);
896 #endif
897 splx(s);
898 return;
899 }
900
901 switch ((u_int)(pmdata.data[2] & 0xff)) {
902 case 0x00: /* 1 sec interrupt? */
903 break;
904 case 0x80: /* 1 sec interrupt? */
905 pm_counter++;
906 break;
907 case 0x08: /* Brightness/Contrast button on LCD panel */
908 /* get brightness and contrast of the LCD */
909 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
910 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
911 /*
912 pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
913 pmdata.command = 0x33;
914 pmdata.num_data = 1;
915 pmdata.s_buf = pmdata.data;
916 pmdata.r_buf = pmdata.data;
917 pmdata.data[0] = pm_LCD_contrast;
918 rval = pm_pmgrop_pm2(&pmdata);
919 pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
920 */
921 pm_LCD_brightness =
922 pm_set_brightness(pm_LCD_brightness);
923 break;
924 case 0x10: /* ADB data that were requested by TALK command */
925 case 0x14:
926 pm_adb_get_TALK_result(&pmdata);
927 break;
928 case 0x16: /* ADB device event */
929 case 0x18:
930 case 0x1e:
931 pm_adb_get_ADB_data(&pmdata);
932 break;
933 default:
934 #ifdef ADB_DEBUG
935 if (adb_debug)
936 pm_printerr("driver does not supported this event.",
937 pmdata.data[2], pmdata.num_data,
938 pmdata.data);
939 #endif
940 break;
941 }
942
943 splx(s);
944 }
945
946
947 /*
948 * MRG-based PMgrOp routine
949 */
950 int
951 pm_pmgrop_mrg(PMData *pmdata)
952 {
953 u_int32_t rval=0;
954
955 __asm volatile(
956 " movl %1,%%a0 \n"
957 " .word 0xa085 \n"
958 " movl %%d0,%0"
959 : "=g" (rval)
960 : "g" (pmdata)
961 : "a0","d0");
962
963 return rval;
964 }
965
966
967 /*
968 * My PMgrOp routine
969 */
970 int
971 pmgrop(PMData *pmdata)
972 {
973 switch (pmHardware) {
974 case PM_HW_PB1XX:
975 return (pm_pmgrop_pm1(pmdata));
976 break;
977 case PM_HW_PB5XX:
978 return (pm_pmgrop_pm2(pmdata));
979 break;
980 default:
981 /* return (pmgrop_mrg(pmdata)); */
982 return 1;
983 }
984 }
985
986
987 /*
988 * My PM interrupt routine
989 */
990 void
991 pm_intr(void *arg)
992 {
993 switch (pmHardware) {
994 case PM_HW_PB1XX:
995 pm_intr_pm1(arg);
996 break;
997 case PM_HW_PB5XX:
998 pm_intr_pm2(arg);
999 break;
1000 default:
1001 break;
1002 }
1003 }
1004
1005
1006 void
1007 pm_hw_setup(void)
1008 {
1009 switch (pmHardware) {
1010 case PM_HW_PB1XX:
1011 via1_register_irq(4, pm_intr_pm1, (void *)0);
1012 PM_VIA_CLR_INTR();
1013 break;
1014 case PM_HW_PB5XX:
1015 via1_register_irq(4, pm_intr_pm2, (void *)0);
1016 PM_VIA_CLR_INTR();
1017 break;
1018 default:
1019 break;
1020 }
1021 }
1022
1023
1024 /*
1025 * Synchronous ADBOp routine for the Power Manager
1026 */
1027 int
1028 pm_adb_op(u_char *buffer, void *compRout, void *data, int command)
1029 {
1030 int i;
1031 int s;
1032 int rval;
1033 int xdelay;
1034 PMData pmdata;
1035 struct adbCommand packet;
1036
1037 if (adbWaiting == 1)
1038 return 1;
1039
1040 s = splhigh();
1041 via_reg(VIA1, vIER) = 0x10;
1042
1043 adbBuffer = buffer;
1044 adbCompRout = compRout;
1045 adbCompData = data;
1046
1047 pmdata.command = 0x20;
1048 pmdata.s_buf = pmdata.data;
1049 pmdata.r_buf = pmdata.data;
1050
1051 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */
1052 if (buffer != (u_char *)0)
1053 pmdata.num_data = buffer[0] + 3;
1054 } else {
1055 pmdata.num_data = 3;
1056 }
1057
1058 pmdata.data[0] = (u_char)(command & 0xff);
1059 pmdata.data[1] = 0;
1060 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1061 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1062 pmdata.data[2] = buffer[0]; /* number of data */
1063 for (i = 0; i < buffer[0]; i++)
1064 pmdata.data[3 + i] = buffer[1 + i];
1065 } else
1066 pmdata.data[2] = 0;
1067 } else
1068 pmdata.data[2] = 0;
1069
1070 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1071 /* set up stuff fNULLor adb_pass_up */
1072 packet.data[0] = 1 + pmdata.data[2];
1073 packet.data[1] = command;
1074 for (i = 0; i < pmdata.data[2]; i++)
1075 packet.data[i+2] = pmdata.data[i+3];
1076 packet.saveBuf = adbBuffer;
1077 packet.compRout = adbCompRout;
1078 packet.compData = adbCompData;
1079 packet.cmd = command;
1080 packet.unsol = 0;
1081 packet.ack_only = 1;
1082 adb_polling = 1;
1083 adb_pass_up(&packet);
1084 adb_polling = 0;
1085 }
1086
1087 rval = pmgrop(&pmdata);
1088 if (rval != 0) {
1089 splx(s);
1090 return 1;
1091 }
1092
1093 adbWaiting = 1;
1094 adbWaitingCmd = command;
1095
1096 PM_VIA_INTR_ENABLE();
1097
1098 /* wait until the PM interrupt has occurred */
1099 xdelay = 0x80000;
1100 while (adbWaiting == 1) {
1101 switch (mac68k_machine.machineid) {
1102 case MACH_MACPB150:
1103 case MACH_MACPB210:
1104 case MACH_MACPB230: /* daishi tested with Duo230 */
1105 case MACH_MACPB250:
1106 case MACH_MACPB270:
1107 case MACH_MACPB280:
1108 case MACH_MACPB280C:
1109 case MACH_MACPB190:
1110 case MACH_MACPB190CS:
1111 pm_intr((void *)0);
1112 break;
1113 default:
1114 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1115 pm_intr((void *)0);
1116 break;
1117 }
1118 #ifdef PM_GRAB_SI
1119 (void)intr_dispatch(0x70); /* grab any serial interrupts */
1120 #endif
1121 if ((--xdelay) < 0) {
1122 splx(s);
1123 return 1;
1124 }
1125 }
1126
1127 /* this command enables the interrupt by operating ADB devices */
1128 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1129 pmdata.command = 0x20;
1130 pmdata.num_data = 4;
1131 pmdata.s_buf = pmdata.data;
1132 pmdata.r_buf = pmdata.data;
1133 pmdata.data[0] = 0x00;
1134 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1135 pmdata.data[2] = 0x00;
1136 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1137 } else { /* PB 1XX series */
1138 pmdata.command = 0x20;
1139 pmdata.num_data = 3;
1140 pmdata.s_buf = pmdata.data;
1141 pmdata.r_buf = pmdata.data;
1142 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1143 pmdata.data[1] = 0x04;
1144 pmdata.data[2] = 0x00;
1145 }
1146 rval = pmgrop(&pmdata);
1147
1148 splx(s);
1149 return rval;
1150 }
1151
1152
1153 void
1154 pm_adb_get_TALK_result(PMData *pmdata)
1155 {
1156 int i;
1157 struct adbCommand packet;
1158
1159 /* set up data for adb_pass_up */
1160 packet.data[0] = pmdata->num_data-1;
1161 packet.data[1] = pmdata->data[3];
1162 for (i = 0; i <packet.data[0]-1; i++)
1163 packet.data[i+2] = pmdata->data[i+4];
1164
1165 packet.saveBuf = adbBuffer;
1166 packet.compRout = adbCompRout;
1167 packet.compData = adbCompData;
1168 packet.unsol = 0;
1169 packet.ack_only = 0;
1170 adb_polling = 1;
1171 adb_pass_up(&packet);
1172 adb_polling = 0;
1173
1174 adbWaiting = 0;
1175 adbBuffer = (long)0;
1176 adbCompRout = (long)0;
1177 adbCompData = (long)0;
1178 }
1179
1180
1181 void
1182 pm_adb_get_ADB_data(PMData *pmdata)
1183 {
1184 int i;
1185 struct adbCommand packet;
1186
1187 /* set up data for adb_pass_up */
1188 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1189 packet.data[1] = pmdata->data[3]; /* ADB command */
1190 for (i = 0; i <packet.data[0]-1; i++)
1191 packet.data[i+2] = pmdata->data[i+4];
1192 packet.unsol = 1;
1193 packet.ack_only = 0;
1194 adb_pass_up(&packet);
1195 }
1196
1197
1198 void
1199 pm_adb_poll_next_device_pm1(PMData *pmdata)
1200 {
1201 int i;
1202 int ndid;
1203 u_short bendid = 0x1;
1204 PMData tmp_pmdata;
1205
1206 /* find another existent ADB device to poll */
1207 for (i = 1; i < 16; i++) {
1208 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1209 bendid <<= ndid;
1210 if ((pm_existent_ADB_devices & bendid) != 0)
1211 break;
1212 }
1213
1214 /* poll the other device */
1215 tmp_pmdata.command = 0x20;
1216 tmp_pmdata.num_data = 3;
1217 tmp_pmdata.s_buf = tmp_pmdata.data;
1218 tmp_pmdata.r_buf = tmp_pmdata.data;
1219 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1220 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1221 tmp_pmdata.data[2] = 0x00;
1222 pmgrop(&tmp_pmdata);
1223 }
1224
1225 void
1226 pm_poweroff(void)
1227 {
1228 PMData pmdata;
1229 int attempt = 3;
1230
1231 while (pmHardware == PM_HW_PB1XX && attempt > 0) {
1232 pmdata.command = 0xef;
1233 pmdata.num_data = 0;
1234 pmdata.data[0] = pmdata.data[1] = 0;
1235 pmdata.s_buf = &pmdata.data[2];
1236 pmdata.r_buf = &pmdata.data[2];
1237 (void)pm_pmgrop_pm1(&pmdata);
1238 attempt--;
1239 }
1240
1241 return;
1242 }
1243
1244 u_int
1245 pm_set_brightness(u_int brightness)
1246 {
1247 PMData pmdata;
1248
1249 pmdata.num_data = 1;
1250 pmdata.s_buf = pmdata.data;
1251 pmdata.r_buf = pmdata.data;
1252
1253 switch (pmHardware) {
1254 case PM_HW_PB5XX:
1255 /* this is an experimental code */
1256 pmdata.command = 0x41;
1257 if ((int)brightness < 0)
1258 brightness = 0;
1259 if ((int)brightness > 31)
1260 brightness = 31;
1261 pmdata.data[0] = (31 - brightness) * 23 / 10 + 37;
1262 (void)pm_pmgrop_pm2(&pmdata);
1263 break;
1264 case PM_HW_PB1XX:
1265 /* this is an experimental code also */
1266 pmdata.command = 0x40;
1267 if ((int)brightness < 0)
1268 brightness = 0;
1269 if ((int)brightness > 31)
1270 brightness = 31;
1271 pmdata.data[0] = 31 - brightness;
1272 (void)pm_pmgrop_pm1(&pmdata);
1273 break;
1274 default:
1275
1276 return 0;
1277 break;
1278 }
1279
1280 return brightness;
1281 }
1282