patch-2.4.20 linux-2.4.20/drivers/char/hp_psaux.c

Next file: linux-2.4.20/drivers/char/hvc_console.c
Previous file: linux-2.4.20/drivers/char/hp_keyb.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/char/hp_psaux.c linux-2.4.20/drivers/char/hp_psaux.c
@@ -6,18 +6,16 @@
  *	Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org>
  *
  *	2000/10/26	Debacker Xavier (debackex@esiee.fr)
+ *	implemented the psaux and controlled the mouse scancode based on pc_keyb.c
  *			Marteau Thomas (marteaut@esiee.fr)
- * 			Djoudi Malek (djoudim@esiee.fr)
  *	fixed leds control
- *	implemented the psaux and controlled the mouse scancode based on pc_keyb.c
+ *
+ *	2001/12/17	Marteau Thomas (marteaut@esiee.fr)
+ *	get nice initialisation procedure
  */
 
 #include <linux/config.h>
 
-#include <asm/hardware.h>
-#include <asm/keyboard.h>
-#include <asm/gsc.h>
-
 #include <linux/types.h>
 #include <linux/ptrace.h>	/* interrupt.h wants struct pt_regs defined */
 #include <linux/interrupt.h>
@@ -28,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <linux/pc_keyb.h>
 #include <linux/kbd_kern.h>
 
@@ -37,11 +36,16 @@
 #include <linux/random.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
-#include <asm/uaccess.h>
 #include <linux/poll.h>
 
+#include <asm/hardware.h>
+#include <asm/keyboard.h>
+#include <asm/gsc.h>
+#include <asm/uaccess.h>
+
 /* HP specific LASI PS/2 keyboard and psaux constants */
 #define	AUX_REPLY_ACK	0xFA	/* Command byte ACK. */
+#define	AUX_RESEND	0xFE	/* Sent by the keyb. Asking for resending the last command. */
 #define	AUX_RECONNECT	0xAA	/* scancode when ps2 device is plugged (back) in */
 
 #define	LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */
@@ -69,50 +73,63 @@
 #define LASI_STAT_DATSHD 0x40
 #define LASI_STAT_CLKSHD 0x80
 
-static void *lasikbd_hpa;
-static void *lasips2_hpa;
+static spinlock_t	kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long lasikbd_hpa;
 
+static volatile int cmd_status;
 
-static inline u8 read_input(void *hpa)
+static inline u8 read_input(unsigned long hpa)
 {
 	return gsc_readb(hpa+LASI_RCVDATA);
 }
 
-static inline u8 read_control(void *hpa)
+static inline u8 read_control(unsigned long hpa)
 {
         return gsc_readb(hpa+LASI_CONTROL);
 }
 
-static inline void write_control(u8 val, void *hpa)
+static inline void write_control(u8 val, unsigned long hpa)
 {
 	gsc_writeb(val, hpa+LASI_CONTROL);
 }
 
-static inline u8 read_status(void *hpa)
+static inline u8 read_status(unsigned long hpa)
 {
         return gsc_readb(hpa+LASI_STATUS);
 }
 
-static int write_output(u8 val, void *hpa)
+/* XXX should this grab the spinlock? */
+
+static int write_output(u8 val, unsigned long hpa)
 {
-	int wait = 0;
+	int wait = 250;
 
 	while (read_status(hpa) & LASI_STAT_TBNE) {
-		wait++;
-		if (wait>10000) {
-			/* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */
+		if (!--wait) {
 			return 0;
 		}
+		mdelay(1);
 	}
-
-	if (wait)
-		printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait);
-	
 	gsc_writeb(val, hpa+LASI_XMTDATA);
 
 	return 1;
 }
 
+/* XXX should this grab the spinlock? */
+
+static u8 wait_input(unsigned long hpa)
+{
+	int wait = 250;
+
+	while (!(read_status(hpa) & LASI_STAT_RBNE)) {
+		if (!--wait) {
+			return 0;
+		}
+		mdelay(1);
+	}
+	return read_input(hpa);      
+}
+
 /* This function is the PA-RISC adaptation of i386 source */
 
 static inline int aux_write_ack(u8 val)
@@ -120,11 +137,37 @@
       return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);
 }
 
+/* This is wrong, should do something like the pc driver, which sends
+ * the command up to 3 times at 1 second intervals, checking once
+ * per millisecond for an acknowledge.
+ */
+
 static void lasikbd_leds(unsigned char leds)
 {
-	write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
-	write_output(leds, lasikbd_hpa);
-	write_output(KBD_CMD_ENABLE, lasikbd_hpa);
+	int loop = 1000;
+
+	if (!lasikbd_hpa)
+		return;
+
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+		write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
+		mdelay(5); 
+	}
+   
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+		write_output(leds, lasikbd_hpa);
+		mdelay(5);
+	}
+
+	cmd_status=2;
+	while (cmd_status!=0 && --loop > 0) {
+	   write_output(KBD_CMD_ENABLE, lasikbd_hpa);   
+	   mdelay(5);
+	}
+	if (loop <= 0)
+		printk("lasikbd_leds: timeout\n");
 }
 
 #if 0
@@ -154,10 +197,30 @@
 }
 #endif 
 
-static int __init lasi_ps2_reset(void *hpa, int id)
+static int init_keyb(unsigned long hpa)
+{
+	int res = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+
+	if (write_output(KBD_CMD_SET_LEDS, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK &&
+			write_output(0, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK &&
+			write_output(KBD_CMD_ENABLE, hpa) &&
+			wait_input(hpa) == AUX_REPLY_ACK)
+		res = 1;
+
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+
+	return res;
+}
+
+
+static void __init lasi_ps2_reset(unsigned long hpa)
 {
 	u8 control;
-	int ret = 1;
 
 	/* reset the interface */
 	gsc_writeb(0xff, hpa+LASI_RESET);
@@ -166,25 +229,8 @@
 	/* enable it */
 	control = read_control(hpa);
 	write_control(control | LASI_CTRL_ENBL, hpa);
-
-        /* initializes the leds at the default state */
-        if (id==0) {
-           write_output(KBD_CMD_SET_LEDS, hpa);
-	   write_output(0, hpa);
-	   ret = write_output(KBD_CMD_ENABLE, hpa);
-	}
-
-	return ret;
-}
-
-static int inited;
-
-static void lasi_ps2_init_hw(void)
-{
-	++inited;
 }
 
-
 /* Greatly inspired by pc_keyb.c */
 
 /*
@@ -202,7 +248,6 @@
 #ifdef CONFIG_PSMOUSE
 
 static struct aux_queue	*queue;
-static spinlock_t	kbd_controller_lock = SPIN_LOCK_UNLOCKED;
 static unsigned char	mouse_reply_expected;
 static int 		aux_count;
 
@@ -315,7 +360,7 @@
 			schedule();
 			goto repeat;
 		}
-		set_current_state(TASK_RUNNING);
+		current->state = TASK_RUNNING;
 		remove_wait_queue(&queue->proc_list, &wait);
 	}
 	while (i > 0 && !queue_empty()) {
@@ -362,7 +407,7 @@
 	lock_kernel();
 	fasync_aux(-1, file, 0);
 	if (--aux_count) {
-	   unlock_kernel();
+		unlock_kernel();
 		return 0;
 	}
 	unlock_kernel();
@@ -389,7 +434,7 @@
 
 /* This function is looking at the PS2 controller and empty the two buffers */
 
-static u8 handle_lasikbd_event(void *hpa)
+static u8 handle_lasikbd_event(unsigned long hpa)
 {
         u8 status_keyb,status_mouse,scancode,id;
         extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
@@ -398,62 +443,64 @@
         id = gsc_readb(hpa+LASI_ID) & 0x0f;
         
         if (id==1) 
-           hpa -= LASI_PSAUX_OFFSET; 
-        lasikbd_hpa = hpa;
-        
-
+		hpa -= LASI_PSAUX_OFFSET; 
+	
         status_keyb = read_status(hpa);
         status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 
         while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
            
-           while (status_keyb & LASI_STAT_RBNE) {
+		while (status_keyb & LASI_STAT_RBNE) {
 	      
-              scancode = read_input(hpa);
+		scancode = read_input(hpa);
 
-	      /* XXX don't know if this is a valid fix, but filtering
-	       * 0xfa avoids 'unknown scancode' errors on, eg, capslock
-	       * on some keyboards.
-	       */
-	      if (inited && scancode != 0xfa)
-		 handle_at_scancode(scancode); 
+	        /* XXX don't know if this is a valid fix, but filtering
+	         * 0xfa avoids 'unknown scancode' errors on, eg, capslock
+	         * on some keyboards.
+	         */
+	      	      
+		if (scancode == AUX_REPLY_ACK) 
+			cmd_status=0;
+			
+		else if (scancode == AUX_RESEND)
+			cmd_status=1;
+		else 
+			handle_at_scancode(scancode); 
 	      
-	      status_keyb =read_status(hpa);
-           }
+		status_keyb =read_status(hpa);
+		}
 	   
 #ifdef CONFIG_PSMOUSE
-           while (status_mouse & LASI_STAT_RBNE) {
-	      scancode = read_input(hpa+LASI_PSAUX_OFFSET);
-	      handle_mouse_scancode(scancode);
-              status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
-	   }
-           status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
+		while (status_mouse & LASI_STAT_RBNE) {
+			scancode = read_input(hpa+LASI_PSAUX_OFFSET);
+			handle_mouse_scancode(scancode);
+			status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
+		}
+		status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
 #endif /* CONFIG_PSMOUSE */
-           status_keyb = read_status(hpa);
+		status_keyb = read_status(hpa);
         }
 
         tasklet_schedule(&keyboard_tasklet);
         return (status_keyb|status_mouse);
 }
-
-
-
 	
 extern struct pt_regs *kbd_pt_regs;
 
 static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
-	lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */
 	kbd_pt_regs = regs;
-	handle_lasikbd_event(lasips2_hpa);
+	handle_lasikbd_event((unsigned long) dev);
 }
 
-
 extern int pckbd_translate(unsigned char, unsigned char *, char);
+extern int pckbd_setkeycode(unsigned int, unsigned int);
+extern int pckbd_getkeycode(unsigned int);
 
 static struct kbd_ops gsc_ps2_kbd_ops = {
-	translate:	pckbd_translate,
-	init_hw:	lasi_ps2_init_hw,
+	setkeycode:     pckbd_setkeycode,
+        getkeycode:     pckbd_getkeycode,
+        translate:	pckbd_translate,
 	leds:		lasikbd_leds,
 #ifdef CONFIG_MAGIC_SYSRQ
 	sysrq_key:	0x54,
@@ -461,13 +508,27 @@
 #endif
 };
 
+
+
+#if 1
+/* XXX: HACK !!!
+ * remove this function and the call in hil_kbd.c 
+ * if hp_psaux.c/hp_keyb.c is converted to the input layer... */
+int register_ps2_keybfuncs(void)
+{
+	gsc_ps2_kbd_ops.leds = NULL;
+	register_kbd_ops(&gsc_ps2_kbd_ops);
+}
+EXPORT_SYMBOL(register_ps2_keybfuncs);
+#endif
+
+
 static int __init
-lasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri)
+lasi_ps2_register(struct parisc_device *dev)
 {
-	void *hpa = (void *) d->hpa;
-	unsigned int irq;
+	unsigned long hpa = dev->hpa;
 	char *name;
-	int device_found;
+	int device_found = 0;
 	u8 id;
 
 	id = gsc_readb(hpa+LASI_ID) & 0x0f;
@@ -475,7 +536,7 @@
 	switch (id) {
 	case 0:
 		name = "keyboard";
-		lasikbd_hpa = hpa;
+		lasikbd_hpa = hpa;	/* save "hpa" for lasikbd_leds() */
 		break;
 	case 1:
 		name = "psaux";
@@ -487,21 +548,12 @@
 	}
 	
 	/* reset the PS/2 port */
-	device_found = lasi_ps2_reset(hpa,id);
-
-	/* allocate the irq and memory region for that device */
-	if (!(irq = busdevice_alloc_irq(d)))
-		return -ENODEV;
-		    
-	if (request_irq(irq, lasikbd_interrupt, 0, name, hpa))
-		return -ENODEV;
-	
-	if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name))
-		return -ENODEV;
+	lasi_ps2_reset(hpa);
 
 	switch (id) {
 	case 0:	
-		register_kbd_ops(&gsc_ps2_kbd_ops);
+	        device_found = init_keyb(hpa);
+		if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
 		break;
 	case 1:
 #ifdef CONFIG_PSMOUSE
@@ -526,26 +578,42 @@
 #endif
 	} /* of case */
 	
-	printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, "
+	if (device_found) {
+	/* Here we claim only if we have a device attached */   
+		/* allocate the irq and memory region for that device */
+		if (!dev->irq)
+	 	return -ENODEV;
+	   
+	  	if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
+	  	return -ENODEV;
+	   
+	  	if (!request_mem_region(hpa, LASI_STATUS + 4, name))
+	  	return -ENODEV;
+	}
+	
+	printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
 			 "%sdevice attached.\n",
-			name, (unsigned long)hpa, irq,
-			device_found ? "":"no ");
+			name, hpa, dev->irq, device_found ? "":"no ");
 
 	return 0;
 }
 
+static struct parisc_device_id lasi_psaux_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 },
+	{ 0, } /* 0 terminated list */
+};
+
+MODULE_DEVICE_TABLE(parisc, lasi_psaux_tbl);
 
-static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = {
-	{HPHW_FIO, 0x0, 0,0x00084, 0, 0,
-		DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION,
-		"Lasi psaux", "generic", (void *) lasi_ps2_register},
-	{ 0, }
+static struct parisc_driver lasi_psaux_driver = {
+	name:		"Lasi psaux",
+	id_table:	lasi_psaux_tbl,
+	probe:		lasi_ps2_register,
 };
 
 static int __init gsc_ps2_init(void) 
 {
-	return pdc_register_driver(lasi_psaux_drivers_for);
+	return register_parisc_driver(&lasi_psaux_driver);
 }
 
 module_init(gsc_ps2_init);
-

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