Home | History | Annotate | Line # | Download | only in dev
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