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