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