patch-2.4.9 linux/drivers/char/pc_keyb.c

Next file: linux/drivers/char/pcmcia/serial_cs.c
Previous file: linux/drivers/char/n_r3964.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.8/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
@@ -63,6 +63,7 @@
 #ifdef CONFIG_PSMOUSE
 static void aux_write_ack(int val);
 static void __aux_write_ack(int val);
+static int aux_reconnect = 0;
 #endif
 
 static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
@@ -81,7 +82,8 @@
 
 static int __init psaux_init(void);
 
-#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
+#define AUX_RECONNECT1 0xaa	/* scancode1 when ps2 device is plugged (back) in */
+#define AUX_RECONNECT2 0x00	/* scancode2 when ps2 device is plugged (back) in */
  
 static struct aux_queue *queue;	/* Mouse data buffer. */
 static int aux_count;
@@ -396,6 +398,7 @@
 static inline void handle_mouse_event(unsigned char scancode)
 {
 #ifdef CONFIG_PSMOUSE
+	static unsigned char prev_code;
 	if (mouse_reply_expected) {
 		if (scancode == AUX_ACK) {
 			mouse_reply_expected--;
@@ -403,12 +406,15 @@
 		}
 		mouse_reply_expected = 0;
 	}
-	else if(scancode == AUX_RECONNECT){
-		queue->head = queue->tail = 0;  /* Flush input queue */
+	else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1
+		&& aux_reconnect) {
+		printk (KERN_INFO "PS/2 mouse reconnect detected\n");
+		queue->head = queue->tail = 0;	/* Flush input queue */
 		__aux_write_ack(AUX_ENABLE_DEV);  /* ping the mouse :) */
 		return;
 	}
 
+	prev_code = scancode;
 	add_mouse_randomness(scancode);
 	if (aux_count) {
 		int head = queue->head;
@@ -533,6 +539,86 @@
 	}
 }
 
+#define DEFAULT_KEYB_REP_DELAY	250
+#define DEFAULT_KEYB_REP_RATE	30	/* cps */
+
+static struct kbd_repeat kbdrate={
+	DEFAULT_KEYB_REP_DELAY,
+	DEFAULT_KEYB_REP_RATE
+};
+
+static unsigned char parse_kbd_rate(struct kbd_repeat *r)
+{
+	static struct r2v{
+		int rate;
+		unsigned char val;
+	} kbd_rates[]={	{5,0x14},
+			{7,0x10},
+			{10,0x0c},
+			{15,0x08},
+			{20,0x04},
+			{25,0x02},
+			{30,0x00}
+	};
+	static struct d2v{
+		int delay;
+		unsigned char val;
+	} kbd_delays[]={{250,0},
+			{500,1},
+			{750,2},
+			{1000,3}
+	};
+	int rate=0,delay=0;
+	if (r != NULL){
+		int i,new_rate=30,new_delay=250;
+		if (r->rate <= 0)
+			r->rate=kbdrate.rate;
+		if (r->delay <= 0)
+			r->delay=kbdrate.delay;
+		for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++)
+			if (kbd_rates[i].rate == r->rate){
+				new_rate=kbd_rates[i].rate;
+				rate=kbd_rates[i].val;
+				break;
+			}
+		for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++)
+			if (kbd_delays[i].delay == r->delay){
+				new_delay=kbd_delays[i].delay;
+				delay=kbd_delays[i].val;
+				break;
+			}
+		r->rate=new_rate;
+		r->delay=new_delay;
+	}
+	return (delay << 5) | rate;
+}
+
+static int write_kbd_rate(unsigned char r)
+{
+	if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){
+		send_data(KBD_CMD_ENABLE); 	/* re-enable kbd if any errors */
+		return 0;
+	}else
+		return 1;
+}
+
+int pckbd_rate(struct kbd_repeat *rep)
+{
+	if (rep == NULL)
+		return -EINVAL;
+	else{
+		unsigned char r=parse_kbd_rate(rep);
+		struct kbd_repeat old_rep;
+		memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat));
+		if (write_kbd_rate(r)){
+			memcpy(&kbdrate,rep,sizeof(struct kbd_repeat));
+			memcpy(rep,&old_rep,sizeof(struct kbd_repeat));
+			return 0;
+		}
+	}
+	return -EIO;
+}
+
 /*
  * In case we run on a non-x86 hardware we need to initialize both the
  * keyboard controller and the keyboard.  On a x86, the BIOS will
@@ -754,6 +840,14 @@
 }
 
 #if defined CONFIG_PSMOUSE
+
+static int __init aux_reconnect_setup (char *str)
+{
+	aux_reconnect = 1;
+	return 1;
+}
+
+__setup("psaux-reconnect", aux_reconnect_setup);
 
 /*
  * Check if this is a dual port controller.

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