diff -ruX ignorediff linux-2.2.17pre15-ben1-dmasound/arch/ppc/config.in linux-2.2.17pre15-ben1/arch/ppc/config.in
--- linux-2.2.17pre15-ben1-dmasound/arch/ppc/config.in	Fri Aug  4 15:38:11 2000
+++ linux-2.2.17pre15-ben1/arch/ppc/config.in	Wed Aug  2 15:53:08 2000
@@ -85,6 +85,7 @@
 
 bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
 bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
+bool 'Support for PowerMac ADB Gravis GamePad' CONFIG_ADBGGAMEPAD
 bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
 if [ "$CONFIG_MAC_KEYBOARD" = "y" -o "$CONFIG_ADBMOUSE" = "y" ]; then
    bool '   Enable new input layer' CONFIG_NEW_INPUT_LAYER y
diff -ruX ignorediff linux-2.2.17pre15-ben1-dmasound/drivers/macintosh/mac_keyb.c linux-2.2.17pre15-ben1/drivers/macintosh/mac_keyb.c
--- linux-2.2.17pre15-ben1-dmasound/drivers/macintosh/mac_keyb.c	Wed Aug  2 03:48:58 2000
+++ linux-2.2.17pre15-ben1/drivers/macintosh/mac_keyb.c	Wed Aug  2 16:18:25 2000
@@ -66,7 +66,7 @@
 /* Keep old legacy Xpmac stuff for now, existing install ramdisk
  * need it
  */
-#define OLD_CRAP_COMPATIBLE
+//#define OLD_CRAP_COMPATIBLE
 
 static int adb_message_handler(struct notifier_block *, unsigned long, void *);
 static struct notifier_block mackeyb_adb_notifier = {
@@ -75,6 +75,16 @@
 	0
 };
 
+#ifdef CONFIG_PMAC_PBOOK
+static int (*sound_togglemute)(int);
+static int (*sound_addto_volume)(int, int);
+
+int set_soundcontrols(int (*togglemute)(int),int (*volume)(int,int)){
+  sound_togglemute=togglemute;
+  sound_addto_volume=volume;
+  return 1;
+}
+#endif
 #ifndef CONFIG_INPUT_KEYBDEV
 /* this map indicates which keys shouldn't autorepeat. */
 static unsigned char dont_repeat[128] = {
@@ -331,6 +341,10 @@
 static int last_keycode;
 #endif
 
+/* buttons_input needs to know if shift or option key is down */
+static int shift_down;
+static int option_down;
+
 static void mackeyb_probe(void);
 
 static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
@@ -342,6 +356,7 @@
 #endif
 
 static void buttons_input(unsigned char *, int, struct pt_regs *, int);
+static void buttons_handler(unsigned char *, int);
 
 static void init_trackpad(int id);
 static void init_trackball(int id);
@@ -395,6 +410,109 @@
 #define ADBMOUSE_MS_A3		8	/* Mouse systems A3 trackball (handler 3) */
 #define ADBMOUSE_MACALLY2	9	/* MacAlly 2-button mouse */
 
+#ifdef CONFIG_ADBGGAMEPAD
+#define GRAVIS_GAMEPAD 52
+#endif
+#ifdef GRAVIS_GAMEPAD
+/* gamepad works like this: with the switch on top, if it is switched left, 
+   if you press a key, the next key code from the keyboard is mapped to that
+   button/direction.  switch to the right and the buttons use those mapped
+   keys.  eventually default: directional=arrowkeys, buttons = ijkl diamond
+*/
+
+#define GRAVIS_LEFTARROW     0x01
+#define GRAVIS_DOWNARROW     0x02
+#define GRAVIS_RIGHTARROW    0x04
+#define GRAVIS_UPARROW       0x08
+#define GRAVIS_TOPBUTTON     0x10
+#define GRAVIS_LEFTBUTTON    0x20
+#define GRAVIS_RIGHTBUTTON   0x40
+#define GRAVIS_BOTTOMBUTTON  0x80
+#define GRAVIS_UNSETKEYCODE  0x8000
+
+#define GRAVIS_VOLUMEUP      0x0100
+#define GRAVIS_VOLUMEDOWN    0x0200
+
+static unsigned int gravis_keymap[8][10]={ {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					   {0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000},
+					};
+static char gravis_modify=0;
+struct adb_ids gravis_ids;	       
+static char gravis_lastkey = 0xff;
+
+inline void gravis_key(int key){
+  int i;
+  switch(gravis_keymap[key][0]){
+  case GRAVIS_UNSETKEYCODE:
+    return;
+  case GRAVIS_VOLUMEUP:
+    if(sound_addto_volume)
+    sound_addto_volume( 2, 7);
+    break;
+  case GRAVIS_VOLUMEDOWN:
+    if(sound_addto_volume)
+    sound_addto_volume( 2, -7);
+    break;
+  default:
+    if((key>=0) && (key<8)){
+      for(i=0;i<10;i++)
+	if(gravis_keymap[key][i]!=GRAVIS_UNSETKEYCODE)
+	  input_keycode((char)((gravis_keymap[key][i] & 0x7f) | ((gravis_lastkey & 1<<key)?0:0x80)),0);
+	else
+	  return;
+    }
+  }
+}
+
+static void gravis_setkeys(int newkey){
+  int i,j;
+  for(i=0;i<8;i++) /* check all 8 keys */
+    if(!(gravis_lastkey & 1<<i)){ /* if this key is down */
+      if(newkey!=GRAVIS_UNSETKEYCODE){ /* if the new key isn't blank */
+	if(!(newkey & 0x80)){ /* and is not down */
+	  for(j=0;j<10;j++) /* loop */
+	    if(gravis_keymap[i][j] == GRAVIS_UNSETKEYCODE){ /* until its blank */
+	      gravis_keymap[i][j]=newkey; /* save it here */
+	      //printk("%i%i - 0x%x\n",i,j,gravis_keymap[i][j]);
+              return; /* and exit */
+	    }
+	}
+	//else{ /* if its not down, we're done */
+	//  gravis_lastkey=0xff; /* reset lastkey */
+	//  printk("Gravis Gamepad: key %i mapped to",i);
+	//  for(j=0;j<10;j++) /* output this key's macro */
+	//    if(gravis_keymap[i][j] != GRAVIS_UNSETKEYCODE)
+	//      printk(" 0x%x",gravis_keymap[i][j]);
+	//  printk("\n");
+	//  return;
+	//}
+      }else{ /* if it is blank */
+	for(j=0;j<10;j++) /* blank this key */
+	  gravis_keymap[i][j]=GRAVIS_UNSETKEYCODE;
+      }
+    }
+}
+
+static void gravis_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll){
+  int i;
+  if((gravis_modify = (~data[2]))){ /*if modify */
+    gravis_lastkey = data[1]; /* save keys */
+    gravis_setkeys(GRAVIS_UNSETKEYCODE); /* clear the selected keys */
+  }else{
+    for(i=0;i<8;i++)
+      if(((data[1] & 1<<i)) != (gravis_lastkey & 1<<i))
+	gravis_key(i);
+    gravis_lastkey = data[1];
+  }
+}
+#endif
+
 static int adb_mouse_kinds[16];
 
 __openfirmware
@@ -531,9 +649,17 @@
 	if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
 		return;		/* ignore it */
 	kbd_pt_regs = regs;
+#ifdef GRAVIS_GAMEPAD
+	if(gravis_modify && (~gravis_lastkey))
+	  gravis_setkeys((int)(data[1]));
+	else{
+#endif
 	input_keycode(data[0]>>4, data[1], 0);
 	if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
 		input_keycode(data[0]>>4, data[2], 0);
+#ifdef GRAVIS_GAMEPAD
+	}
+#endif
 }
 
 static void
@@ -569,6 +695,12 @@
 	}
 #endif
 
+       /* buttons_handler() needs to know state of shift and option keys */
+       if (keycode == 0x38)
+               shift_down = !up_flag;
+       if (keycode == 0x3a)
+               option_down = !up_flag;
+
 //#if !defined(CONFIG_INPUT_MOUSEDEV) && defined(CONFIG_ADBMOUSE)
 #if  defined(CONFIG_ADBMOUSE)
 	if (mouse_emulate_buttons
@@ -872,11 +1004,30 @@
 }
 #endif /* CONFIG_ADBMOUSE */
 
+/* Autorepeat delays for ADB buttons */
+#define BUTTON_DELAY0  (HZ/2)
+#define BUTTON_DELAY1  (HZ/6)
+
+/* Timer for buttons autorepeat */
+static struct timer_list button_timer;
+/* Store buttons data here between each interrupt */
+static unsigned char button_data[4];
+
+/* Interrupt handler for ADB button autorepeat */
 static void
-buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+buttons_repeat(unsigned long x)
 {
-	int backlight = get_backlight_level();
+       unsigned long flags;
+
+       save_flags(flags);
+       cli();
+       buttons_handler(button_data, BUTTON_DELAY1);
+       restore_flags(flags);
+}
 
+static void
+buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
 	/*
 	 * XXX: Where is the contrast control for the passive?
 	 *  -- Cort
@@ -886,51 +1037,98 @@
 	if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
 		return;
 
-	switch (data[1]&0xf )
-	{
-		/* mute */
-		case 0x8:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* contrast decrease */
-		case 0x7:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* contrast increase */
-		case 0x6:
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-			}
-			break;
-		/* brightness decrease */
-		case 0xa:
-			if (backlight < 0)
-				break;
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-				if (backlight > BACKLIGHT_OFF)
-					set_backlight_level(backlight-1);
-				else
-					set_backlight_level(BACKLIGHT_OFF);
-			}
-			break;
-		/* brightness increase */
-		case 0x9:
-			if (backlight < 0)
-				break;
-			/* down event */
-			if ( data[1] == (data[1]&0xf) ) {
-				if (backlight < BACKLIGHT_MAX)
-					set_backlight_level(backlight+1);
-				else
-					set_backlight_level(BACKLIGHT_MAX);
-			}
-			break;
-	}
+        buttons_handler(data, BUTTON_DELAY0);
+}
+  
+static void
+buttons_handler(unsigned char *data, int repeat_delay)
+{
+#ifdef CONFIG_PMAC_PBOOK
+       int down_flag;
+       int repeat_flag = 0;
+       int backlight_level = get_backlight_level();
+	
+
+       del_timer(&button_timer);
+
+       down_flag = data[1] == (data[1] & 0xf);
+       switch (data[1]&0xf)
+       {
+  		/* mute */
+  		case 0x8:
+  			/* down event */
+                        if (down_flag) {
+			    if (pmu_get_model() == PMU_HEATHROW_BASED)
+			      if(sound_togglemute)
+				sound_togglemute(shift_down? 2:4);
+  			}
+  			break;
+                /* contrast decrease (volume decrease on PowerBook G3) */
+  		case 0x7:
+  			/* down event */
+                        if (down_flag) {
+                                if (pmu_get_model() == PMU_HEATHROW_BASED)
+				  if(sound_addto_volume)
+                                        sound_addto_volume(shift_down? 2:4, option_down? -1000:-7);
+#ifdef GRAVIS_GAMEPAD
+				  if(gravis_modify && (~gravis_lastkey))
+				    gravis_setkeys(GRAVIS_VOLUMEDOWN);
+#endif
+                                repeat_flag = !option_down;
+  			}
+  			break;
+                /* contrast increase (volume increase on PowerBook G3) */
+  		case 0x6:
+  			/* down event */
+                        if (down_flag) {
+                                if (pmu_get_model() == PMU_HEATHROW_BASED)
+				  if(sound_addto_volume)
+                                        sound_addto_volume(shift_down? 2:4, option_down? 1000:7);
+#ifdef GRAVIS_GAMEPAD
+				  if(gravis_modify && (~gravis_lastkey))
+				    gravis_setkeys(GRAVIS_VOLUMEUP);
+#endif
+                                repeat_flag = !option_down;
+  			}
+  			break;
+  		/* brightness decrease */
+  		case 0xa:
+  			/* down event */
+                        if (down_flag) {
+                                if (!option_down && backlight_level > 2)
+  					set_backlight_level(backlight_level-2);
+  				else
+                                        set_backlight_level(option_down? 1:0);
+                                repeat_flag = !option_down;
+  			}
+  			break;
+  		/* brightness increase */
+  		case 0x9:
+  			/* down event */
+                        if (down_flag) {
+                                if (!option_down && backlight_level < 0x1e)
+  					set_backlight_level(backlight_level+2);
+  				else 
+  					set_backlight_level(0x1f);
+                                repeat_flag = !option_down;
+  			}
+  			break;
+                default:
+                        /* another button */
+                        break;
+        }
+ 
+        if (repeat_flag) {
+                button_data[0] = data[0];
+                button_data[1] = data[1];
+                button_data[2] = data[2];
+                button_data[3] = data[3];
+                button_timer.expires = repeat_delay + jiffies;
+                button_timer.data = 0;
+                button_timer.function = buttons_repeat;
+                add_timer(&button_timer);
+  	}
+#endif		
 }
 
 /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
@@ -1398,7 +1596,14 @@
 #ifdef CONFIG_ADBMOUSE
 	adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
 #endif /* CONFIG_ADBMOUSE */
-
+#ifdef GRAVIS_GAMEPAD
+	if(adb_register(ADB_KEYBOARD,GRAVIS_GAMEPAD, &gravis_ids, gravis_input))
+	  for (i = 0; i < gravis_ids.nids; i++) {
+	    printk("ADB Gravis GamePad at %d, handler set to 0x%x\n", 
+		   gravis_ids.id[i], GRAVIS_GAMEPAD);
+	  }
+#endif
+	
 	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
 	adb_register(ADB_MISC, 0x1F, &buttons_ids, buttons_input);
 
diff -ruX ignorediff linux-2.2.17pre15-ben1-dmasound/drivers/net/bmac.c linux-2.2.17pre15-ben1/drivers/net/bmac.c
--- linux-2.2.17pre15-ben1-dmasound/drivers/net/bmac.c	Thu Jul 20 04:06:59 2000
+++ linux-2.2.17pre15-ben1/drivers/net/bmac.c	Wed Aug  2 15:53:08 2000
@@ -127,6 +127,9 @@
 static struct pmu_sleep_notifier bmac_sleep_notifier = {
 	bmac_sleep_notify, SLEEP_LEVEL_NET,
 };
+#ifndef MODULE
+static int bmac_uses=0;
+#endif
 #endif
 
 #if 0
@@ -501,6 +504,8 @@
 		break;
 	case PBOOK_WAKE:
 		/* see if this is enough */
+	  if(!bmac_uses)
+	    return PBOOK_SLEEP_OK;
 		bmac_reset_and_enable(bmac_devs, 1);
 		enable_irq(bmac_devs->irq);
 		enable_irq(bp->tx_dma_intr);
@@ -1386,6 +1391,10 @@
 			bmac_proc_info
 			});
 #endif
+#if defined(CONFIG_PMAC_PBOOK) && !defined(MODULE)
+	if(bmac_uses==0)
+	  bmac_sleep_notify(0,PBOOK_SLEEP_NOW);	
+#endif
 
 	return 0;
 }
@@ -1394,8 +1403,12 @@
 {
 	/* XXDEBUG(("bmac: enter open\n")); */
 	/* reset the chip */
+#if defined(CONFIG_PMAC_PBOOK) && !defined(MODULE)
+        bmac_uses++;
+        bmac_sleep_notify(0,PBOOK_WAKE);
+#else
 	bmac_reset_and_enable(dev, 1);
-
+#endif
 	dev->flags |= IFF_UP | IFF_RUNNING;
 
 	MOD_INC_USE_COUNT;
@@ -1444,6 +1457,10 @@
 	bp->reset_and_enabled = 0;
 	XXDEBUG(("bmac: all bufs freed\n"));
 
+#if defined(CONFIG_PMAC_PBOOK) && !defined(MODULE)
+	if(--bmac_uses==0)
+	  bmac_sleep_notify(0,PBOOK_SLEEP_NOW);	
+#endif
 	MOD_DEC_USE_COUNT;
 
 	return 0;
diff -ruX ignorediff linux-2.2.17pre15-ben1-dmasound/drivers/sound/dmasound/dmasound_awacs.c linux-2.2.17pre15-ben1/drivers/sound/dmasound/dmasound_awacs.c
--- linux-2.2.17pre15-ben1-dmasound/drivers/sound/dmasound/dmasound_awacs.c	Fri Aug  4 15:38:11 2000
+++ linux-2.2.17pre15-ben1/drivers/sound/dmasound/dmasound_awacs.c	Wed Aug  2 16:07:11 2000
@@ -144,6 +144,9 @@
 static int is_pbook_G3;
 static unsigned char *macio_base;
 
+/* Mute/unmute status */
+static int is_mute;
+
 /* Burgundy functions */
 static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
 static unsigned awacs_burgundy_rcw(unsigned addr);
@@ -160,6 +163,7 @@
 struct pmu_sleep_notifier awacs_sleep_notifier = {
 	awacs_sleep_notify, SLEEP_LEVEL_SOUND,
 };
+extern int set_soundcontrols(int (*togglemute)(int),int (*volume)(int,int));
 #endif /* CONFIG_PMAC_PBOOK */
 
 static int expand_bal;	/* Balance factor for expanding (not volume!) */
@@ -877,6 +881,10 @@
 #endif
 }
 #endif /* MODULE */
+int
+pmac_addto_volume(int n, int incr);
+int
+pmac_togglemute(int n);
 
 static void PMacSilence(void)
 {
@@ -944,6 +952,9 @@
 	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
 
 	expand_bal = -dmasound.soft.speed;
+#ifdef CONFIG_PMAC_PBOOK
+	set_soundcontrols(pmac_togglemute,pmac_addto_volume);
+#endif
 }
 
 static int PMacSetFormat(int format)
@@ -1011,6 +1022,7 @@
 		awacs_write((n << 12) | rn);
 		volume = awacs_get_volume(rn, lshift);
 	}
+        r1 |= is_mute;
 	if (r1 != awacs_reg[1]) {
 		awacs_reg[1] = r1;
 		awacs_write(r1 | MASK_ADDR1);
@@ -1083,6 +1095,69 @@
 	restore_flags(flags);
 }
 
+#ifdef CONFIG_PMAC_PBOOK
+/* Toggle muting of headphones (n==2) or speakers (n==4) */
+int
+pmac_togglemute(int n)
+{
+       int mask;
+
+       if (n == 2)
+               mask = MASK_AMUTE;
+       else if (n == 4)
+               mask = MASK_CMUTE;
+       else
+               return 0;
+
+       is_mute ^= mask;
+       awacs_reg[1] ^= mask;
+       awacs_write(awacs_reg[1] | MASK_ADDR1);
+
+       return is_mute & mask;
+}
+
+/* Adjust volume of headphones (n==2) or speakers (n==4) */
+int
+pmac_addto_volume(int n, int incr)
+{
+       int volume, v1, v2, mask;
+
+       if (n == 2)
+               mask = MASK_AMUTE;
+       else if (n == 4)
+               mask = MASK_CMUTE;
+       else
+               return 0;
+               
+       if (is_mute & mask)
+               is_mute &= ~mask;
+       if (incr > 100)
+               volume = 0x6464;
+       else if (incr < -100)
+               volume = 0x0101;
+       else {
+               volume = awacs_get_volume(awacs_reg[n], 6);
+               v1 = ((volume >> 8) & 0x0ff) + incr;
+               v2 = (volume & 0x0ff) + incr;
+               if (v1 > 100)
+                       v1 = 100;
+               if (v2 > 100)
+                       v2 = 100;
+               if (v1 <= 0 && v2 <= 0) {
+                       volume = 0;
+               } else {
+                       if (v1 < 1)
+                               v1 = 1;
+                       if (v2 < 1)
+                               v2 = 1;
+                       volume = (v1 << 8) | v2;
+               }
+       }
+       awacs_volume_setter(volume, n, mask, 6);
+
+       return volume;
+}
+#endif
 
 static void
 pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
@@ -2249,6 +2324,7 @@
 int cleanup_module(void)
 {
 	dmasound_deinit() ;
+	set_soundcontrols(0,0);
 	return 0 ;
 }
 #endif
diff -ruX ignorediff linux-2.2.17pre15-ben1-dmasound/kernel/ksyms.c linux-2.2.17pre15-ben1/kernel/ksyms.c
--- linux-2.2.17pre15-ben1-dmasound/kernel/ksyms.c	Sun Jul 23 05:24:56 2000
+++ linux-2.2.17pre15-ben1/kernel/ksyms.c	Wed Aug  2 15:53:47 2000
@@ -47,6 +47,10 @@
 #include <linux/kmod.h>
 #endif
 
+#ifdef CONFIG_PMAC_PBOOK
+extern int set_soundcontrols(int (*togglemute)(int),int (*volume)(int,int));
+EXPORT_SYMBOL(set_soundcontrols);
+#endif
 extern char *get_options(char *str, int *ints);
 extern void set_device_ro(kdev_t dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
