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