patch-2.2.8 linux/drivers/macintosh/mac_keyb.c

Next file: linux/drivers/macintosh/macio-adb.c
Previous file: linux/drivers/macintosh/adb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
@@ -7,6 +7,27 @@
  * (see that file for its authors and contributors).
  *
  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ *
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ *   mice & trackballs
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ *
+ * To do:
+ *
+ * Improve Kensignton support, add MacX support as a dynamic
+ * option (not a compile-time option).
  */
 
 #include <linux/sched.h>
@@ -32,6 +53,41 @@
 #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
 
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block mackeyb_adb_notifier = {
+	adb_message_handler,
+	NULL,
+	0
+};
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
+	0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+							/* 0x30 - 0x3f */
+	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+							/* 0x40 - 0x4f */
+	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
+	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+							/* 0x60 - 0x6f */
+#endif
+
 static u_short macplain_map[NR_KEYS] __initdata = {
 	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
 	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
@@ -170,6 +226,8 @@
 static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
 static int last_keycode;
 
+static void mackeyb_probe(void);
+
 static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
 static void input_keycode(int, int);
 static void leds_done(struct adb_request *);
@@ -180,6 +238,7 @@
 static void init_trackpad(int id);
 static void init_trackball(int id);
 static void init_turbomouse(int id);
+static void init_microspeed(int id);
 
 #ifdef CONFIG_ADBMOUSE
 /* XXX: Hook for mouse driver */
@@ -207,21 +266,11 @@
 #define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
 #define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
 #define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
 
 static int adb_mouse_kinds[16];
 
-/* this map indicates which keys shouldn't autorepeat. */
-static unsigned char dont_repeat[128] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
-	0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
 __openfirmware
 
 int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -281,6 +330,10 @@
 	/* on the powerbook 3400, the power key gives code 0x7e */
 	if (keycode == 0x7e)
 		keycode = 0x7f;
+	/* remap the "Fn" key of the PowerBook G3 Series to 0x48
+	   to avoid conflict with button emulation */
+	if (keycode == 0x3f)
+		keycode = 0x48;
 
 	if (!repeat)
 		del_timer(&repeat_timer);
@@ -441,9 +494,24 @@
 	         the first (the real) button is released. We could do
 		 this here using async flush requests.
 	*/
-	if (adb_mouse_kinds[(data[0]>>4) & 0xf] == ADBMOUSE_TRACKPAD) {
+	switch (adb_mouse_kinds[(data[0]>>4) & 0xf])
+	{
+	    case ADBMOUSE_TRACKPAD:
 		data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
-		data[2] = (data[2] & 0x7f) | 0x80;
+		data[2] = data[2] | 0x80;
+		break;
+	    case ADBMOUSE_MICROSPEED:
+		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+			| (data[3] & 0x08);
+		break;
+	    case ADBMOUSE_TRACKBALLPRO:
+		data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+			& ((data[3] & 0x08) << 4));
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+		break;
 	}
 
 	if (adb_mouse_interrupt_hook)
@@ -473,7 +541,7 @@
 		}
 
 		/* Macintosh 3-button mouse (handler 4). */
-		if (nb == 4) {
+		if (nb >= 4) {
 			static unsigned char uch_ButtonStateThird = 0x80;
 			unsigned char uchButtonThird;
 
@@ -608,9 +676,6 @@
 
 __initfunc(void mackbd_init_hw(void))
 {
-	struct adb_request req;
-	int i;
-
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 	    return;
 
@@ -626,71 +691,127 @@
 #ifdef CONFIG_ADBMOUSE
 	/* initialize mouse interrupt hook */
 	adb_mouse_interrupt_hook = NULL;
+#endif
+
+	led_request.complete = 1;
+
+	mackeyb_probe();
+	
+	notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
+}
+
+static int
+adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
+{
+	switch (code) {
+	case ADB_MSG_PRE_RESET:
+	case ADB_MSG_POWERDOWN:
+		/* Add unregister_keyboard when merging with Paul Mackerras */
+		while(!led_request.complete)
+			adb_poll();
+		break;
+			
+	case ADB_MSG_POST_RESET:
+		mackeyb_probe();
+		break;
+	}
+	return NOTIFY_DONE;
+}
 
+static void
+mackeyb_probe(void)
+{
+	struct adb_request req;
+	int i;
+
+#ifdef CONFIG_ADBMOUSE
 	adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
 #endif /* CONFIG_ADBMOUSE */
 
 	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
 	adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
 
-	for(i = 0; i < keyboard_ids.nids; i++) {
-	    /* turn off all leds */
-	    adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff);
-	}
+	for (i = 0; i < keyboard_ids.nids; i++) {
+		int id = keyboard_ids.id[i];
 
-	/* Enable full feature set of the keyboard
-	   ->get it to send separate codes for left and right shift,
-	   control, option keys */
-	for(i = 0;i < keyboard_ids.nids; i++) {
-	    if (adb_try_handler_change(keyboard_ids.id[i], 5))
-	    	printk("ADB keyboard at %d, handler set to 5\n", keyboard_ids.id[i]);
-	    else if (adb_try_handler_change(keyboard_ids.id[i], 3))
-	    	printk("ADB keyboard at %d, handler set to 3\n", keyboard_ids.id[i]);
-	    else
-	    	printk("ADB keyboard at %d, handler 1\n", keyboard_ids.id[i]);
+		/* turn off all leds */
+		adb_request(&req, NULL, ADBREQ_SYNC, 3,
+			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+		/* Enable full feature set of the keyboard
+		   ->get it to send separate codes for left and right shift,
+		   control, option keys */
+		if (adb_try_handler_change(id, 5))
+			printk("ADB keyboard at %d, handler set to 5\n", id);
+		else if (adb_try_handler_change(id, 3))
+			printk("ADB keyboard at %d, handler set to 3\n", id);
+		else
+			printk("ADB keyboard at %d, handler 1\n", id);
 	}
 
-	led_request.complete = 1;
-
 	/* Try to switch all mice to handler 4, or 2 for three-button
 	   mode and full resolution. */
-	for(i = 0; i < mouse_ids.nids; i++) {
-            if (adb_try_handler_change(mouse_ids.id[i], 4)) {
-                printk("ADB mouse at %d, handler set to 4", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_EXTENDED;
-            }
-	    else if (adb_try_handler_change(mouse_ids.id[i], 2)) {
-	        printk("ADB mouse at %d, handler set to 2", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_200;
-	    }
-	    else {
-                printk("ADB mouse at %d, handler 1", mouse_ids.id[i]);
-                adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_100;
-            }
-
-	    /* Register 1 is usually used for device identification.
-	       Here, we try to identify a known device and call the
-	       appropriate init function */
-	    adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-			ADB_READREG(mouse_ids.id[i], 1));
-
-            if ((req.reply_len) &&
-                (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
-                init_trackball(mouse_ids.id[i]);
-            else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
-		(req.reply[3] == 0x61) && (req.reply[4] == 0x64))
-		init_trackpad(mouse_ids.id[i]);
-	    else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
-		(req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
-		init_turbomouse(mouse_ids.id[i]);
-            printk("\n");
+	for (i = 0; i < mouse_ids.nids; i++) {
+		int id = mouse_ids.id[i];
+		if (adb_try_handler_change(id, 4)) {
+			printk("ADB mouse at %d, handler set to 4", id);
+			adb_mouse_kinds[id] = ADBMOUSE_EXTENDED;
+		}
+		else if (adb_try_handler_change(id, 2)) {
+			printk("ADB mouse at %d, handler set to 2", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200;
+		}
+		else if (adb_try_handler_change(id, 0x2F)) {
+			printk("ADB mouse at %d, handler set to 0x2F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x42)) {
+			printk("ADB mouse at %d, handler set to 0x42", id);
+			adb_mouse_kinds[id] = ADBMOUSE_TRACKBALLPRO;
+		}
+		else if (adb_try_handler_change(id, 0x66)) {
+			printk("ADB mouse at %d, handler set to 0x66", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x5F)) {
+			printk("ADB mouse at %d, handler set to 0x5F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else {
+			printk("ADB mouse at %d, handler 1", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100;
+		}
+
+		if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO)
+		    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
+			init_microspeed(id);
+		}  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
+			/*
+			 * Register 1 is usually used for device
+			 * identification.  Here, we try to identify
+			 * a known device and call the appropriate
+			 * init function.
+			 */
+			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+				    ADB_READREG(id, 1));
+
+			if ((req.reply_len) &&
+			    (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
+				init_trackball(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64))
+				init_trackpad(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
+				init_turbomouse(id);
+		}
+		printk("\n");
         }
 }
 
-__init static void 
+static void 
 init_trackpad(int id)
 {
 	struct adb_request req;	
@@ -716,7 +837,7 @@
 	            r1_buffer[4],
 	            r1_buffer[5],
 	            0x0d, /*r1_buffer[6],*/
-	           r1_buffer[7]);
+	            r1_buffer[7]);
 
             adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	        ADB_WRITEREG(id,2),
@@ -742,7 +863,7 @@
         }
 }
 
-__init static void 
+static void 
 init_trackball(int id)
 {
 	struct adb_request req;
@@ -776,7 +897,7 @@
 	ADB_WRITEREG(id,1), 03,0x38);
 }
 
-__init static void
+static void
 init_turbomouse(int id)
 {
 	struct adb_request req;
@@ -785,6 +906,13 @@
 
 	adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
 	
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+		ADB_WRITEREG(id,3), 0x20 | id, 4);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
 	adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	ADB_WRITEREG(id,2),
 	    0xe7,
@@ -809,3 +937,44 @@
 	    0xff,
 	    0x27);
 }
+
+static void
+init_microspeed(int id)
+{
+	struct adb_request req;
+
+        printk(" (Microspeed/MacPoint or compatible)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	/* This will initialize mice using the Microspeed, MacPoint and
+	   other compatible firmware. Bit 12 enables extended protocol.
+	   
+	   Register 1 Listen (4 Bytes)
+            0 -  3     Button is mouse (set also for double clicking!!!)
+            4 -  7     Button is locking (affects change speed also)
+            8 - 11     Button changes speed
+           12          1 = Extended mouse mode, 0 = normal mouse mode
+           13 - 15     unused 0
+           16 - 23     normal speed
+           24 - 31     changed speed
+
+       Register 1 talk holds version and product identification information.
+       Register 1 Talk (4 Bytes):
+            0 -  7     Product code
+            8 - 23     undefined, reserved
+           24 - 31     Version number
+        
+       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+	adb_request(&req, NULL, ADBREQ_SYNC, 5,
+	ADB_WRITEREG(id,1),
+	    0x20,	/* alt speed = 0x20 (rather slow) */
+	    0x00,	/* norm speed = 0x00 (fastest) */
+	    0x10,	/* extended protocol, no speed change */
+	    0x07);	/* all buttons enabled as mouse buttons, no locking */
+
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)