Hi Dmitry, > > On Sat, Jan 25, 2014 at 11:01:54AM -0800, Raghu Gandham wrote: > > The standard IO regions are already reserved by the platform code on > > most MIPS devices(malta, cobalt, sni). The Commit > > 197a1e96c8be5b6005145af3a4c0e45e2d651444 > > ("Input: i8042-io - fix up region handling on MIPS") introduced a bug > > on these MIPS platforms causing i8042 driver to fail when trying to reserve > IO ports. > > Prior to the above mentioned commit request_region is skipped on MIPS > > but release_region is called. > > > > This patch reverts commit 197a1e96c8be5b6005145af3a4c0e45e2d651444 > and > > also avoids calling release_region for MIPS. > > The problem is that IO regions are reserved on _most_, but not _all_ devices. > MIPS should figure out what they want to do with i8042 registers and be > consistent on all devices. Please examine the attached patch which went upstream in April of 2004. Since then it had been a convention not to call request_region routine in i8042 for MIPS. The attached patch had a glitch that it guarded request_region in i8042-io.h but skipped guarding release_region in i8042-io.h. I believe that the issue Aaro saw was due to this glitch. Below is the error quoted in Aaro's commit message. [ 2.112000] Trying to free nonexistent resource <0000000000000060-000000000000006f> My patch reinstates the convention followed on MIPS devices along with fixing Aaro's issue. Thanks, Raghu
commit 2b7058b32c3f1706a80d54b06ad238f3c0bd09e9 Author: Andrew Morton <akpm@xxxxxxxx> Date: Wed Apr 21 23:37:12 2004 -0700 [PATCH] Merge missing MIPS i8042 bits From: Ralf Baechle <ralf@xxxxxxxxxxxxxx> - Add HPC3 PS/2 driver bits for SGI IP22 aka Indy - Add Mace PS/2 driver bits for SGI IP32 aka O2 - Add R4030 PS/2 driver bits for Jazz family - Don't register I/O ports where we're using the I/O port memory window to access the i8042 registers diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 10a54dd..cacd1f2 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -130,3 +130,13 @@ config SERIO_PCIPS2 To compile this driver as a module, choose M here: the module will be called pcips2. + +config SERIO_MACEPS2 + tristate "SGI O2 MACE PS/2 controller" + depends on SGI_IP32 && SERIO + help + Say Y here if you have SGI O2 workstation and want to use its + PS/2 ports. + + To compile this driver as a module, choose M here: the + module will be called maceps2. diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 2eb86eb..a47dec2 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o +obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 6b434f8..9b36485 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -69,7 +69,7 @@ static inline int i8042_platform_init(void) * On ix86 platforms touching the i8042 data register region can do really * bad things. Because of this the region is always reserved on ix86 boxes. */ -#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) +#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__) && !defined(__mips__) if (!request_region(I8042_DATA_REG, 16, "i8042")) return -1; #endif diff --git a/drivers/input/serio/i8042-ip22io.h b/drivers/input/serio/i8042-ip22io.h new file mode 100644 index 0000000..863b9c9 --- /dev/null +++ b/drivers/input/serio/i8042-ip22io.h @@ -0,0 +1,76 @@ +#ifndef _I8042_IP22_H +#define _I8042_IP22_H + +#include <asm/sgi/ioc.h> +#include <asm/sgi/ip22.h> + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "hpc3ps2/serio0" +#define I8042_AUX_PHYS_DESC "hpc3ps2/serio1" +#define I8042_MUX_PHYS_DESC "hpc3ps2/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ SGI_KEYBD_IRQ +#define I8042_AUX_IRQ SGI_KEYBD_IRQ + +/* + * Register numbers. + */ + +#define I8042_COMMAND_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_STATUS_REG ((unsigned long)&sgioc->kbdmouse.command) +#define I8042_DATA_REG ((unsigned long)&sgioc->kbdmouse.data) + +static inline int i8042_read_data(void) +{ + return sgioc->kbdmouse.data; +} + +static inline int i8042_read_status(void) +{ + return sgioc->kbdmouse.command; +} + +static inline void i8042_write_data(int val) +{ + sgioc->kbdmouse.data = val; +} + +static inline void i8042_write_command(int val) +{ + sgioc->kbdmouse.command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX sgi_kh is a virtual address */ + if (!request_mem_region(sgi_kh, sizeof(struct hpc_keyb), "i8042")) + return 1; +#endif + + i8042_reset = 1; + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, sizeof(struct hpc_keyb)); +#endif +} + +#endif /* _I8042_IP22_H */ diff --git a/drivers/input/serio/i8042-jazzio.h b/drivers/input/serio/i8042-jazzio.h new file mode 100644 index 0000000..5c20ab1 --- /dev/null +++ b/drivers/input/serio/i8042-jazzio.h @@ -0,0 +1,69 @@ +#ifndef _I8042_JAZZ_H +#define _I8042_JAZZ_H + +#include <asm/jazz.h> + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +/* + * Names. + */ + +#define I8042_KBD_PHYS_DESC "R4030/serio0" +#define I8042_AUX_PHYS_DESC "R4030/serio1" +#define I8042_MUX_PHYS_DESC "R4030/serio%d" + +/* + * IRQs. + */ + +#define I8042_KBD_IRQ JAZZ_KEYBOARD_IRQ +#define I8042_AUX_IRQ JAZZ_MOUSE_IRQ + +#define I8042_COMMAND_REG ((unsigned long)&jazz_kh->command) +#define I8042_STATUS_REG ((unsigned long)&jazz_kh->command) +#define I8042_DATA_REG ((unsigned long)&jazz_kh->data) + +static inline int i8042_read_data(void) +{ + return jazz_kh->data; +} + +static inline int i8042_read_status(void) +{ + return jazz_kh->command; +} + +static inline void i8042_write_data(int val) +{ + jazz_kh->data = val; +} + +static inline void i8042_write_command(int val) +{ + jazz_kh->command = val; +} + +static inline int i8042_platform_init(void) +{ +#if 0 + /* XXX JAZZ_KEYBOARD_ADDRESS is a virtual address */ + if (!request_mem_region(JAZZ_KEYBOARD_ADDRESS, 2, "i8042")) + return 1; +#endif + + return 0; +} + +static inline void i8042_platform_exit(void) +{ +#if 0 + release_mem_region(JAZZ_KEYBOARD_ADDRESS, 2); +#endif +} + +#endif /* _I8042_JAZZ_H */ diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index 3d59eb2..f0f6374 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -1,6 +1,8 @@ #ifndef _I8042_H #define _I8042_H +#include <linux/config.h> + /* * Copyright (c) 1999-2002 Vojtech Pavlik * @@ -13,7 +15,11 @@ * Arch-dependent inline functions and defines. */ -#if defined(CONFIG_PPC) +#if defined(CONFIG_MIPS_JAZZ) +#include "i8042-jazzio.h" +#elif defined(CONFIG_SGI_IP22) +#include "i8042-ip22io.h" +#elif defined(CONFIG_PPC) #include "i8042-ppcio.h" #elif defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) #include "i8042-sparcio.h" diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c new file mode 100644 index 0000000..c7db1de --- /dev/null +++ b/drivers/input/serio/maceps2.c @@ -0,0 +1,160 @@ +/* + * SGI O2 MACE PS2 controller driver for linux + * + * Copyright (C) 2002 Vivien Chappelier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/serio.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/ip32/mace.h> +#include <asm/ip32/ip32_ints.h> + +MODULE_AUTHOR("Vivien Chappelier <vivien.chappelier@xxxxxxxxxxxxxx"); +MODULE_DESCRIPTION("SGI O2 MACE PS2 controller driver"); +MODULE_LICENSE("GPL"); + +#define MACE_PS2_TIMEOUT 10000 /* in 50us unit */ + +#define PS2_STATUS_CLOCK_SIGNAL BIT(0) /* external clock signal */ +#define PS2_STATUS_CLOCK_INHIBIT BIT(1) /* clken output signal */ +#define PS2_STATUS_TX_INPROGRESS BIT(2) /* transmission in progress */ +#define PS2_STATUS_TX_EMPTY BIT(3) /* empty transmit buffer */ +#define PS2_STATUS_RX_FULL BIT(4) /* full receive buffer */ +#define PS2_STATUS_RX_INPROGRESS BIT(5) /* reception in progress */ +#define PS2_STATUS_ERROR_PARITY BIT(6) /* parity error */ +#define PS2_STATUS_ERROR_FRAMING BIT(7) /* framing error */ + +#define PS2_CONTROL_TX_CLOCK_DISABLE BIT(0) /* inhibit clock signal after TX */ +#define PS2_CONTROL_TX_ENABLE BIT(1) /* transmit enable */ +#define PS2_CONTROL_TX_INT_ENABLE BIT(2) /* enable transmit interrupt */ +#define PS2_CONTROL_RX_INT_ENABLE BIT(3) /* enable receive interrupt */ +#define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ +#define PS2_CONTROL_RESET BIT(5) /* reset */ + + +struct maceps2_data { + struct mace_ps2port *port; + int irq; +}; + +static int maceps2_write(struct serio *dev, unsigned char val) +{ + struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + unsigned int timeout = MACE_PS2_TIMEOUT; + + do { + if (mace_read(port->status) & PS2_STATUS_TX_EMPTY) { + mace_write(val, port->tx); + return 0; + } + udelay(50); + } while (timeout--); + + return -1; +} + +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct serio *dev = dev_id; + struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + unsigned int byte; + + if (mace_read(port->status) & PS2_STATUS_RX_FULL) { + byte = mace_read(port->rx); + serio_interrupt(dev, byte & 0xff, 0, regs); + } + + return IRQ_HANDLED; +} + +static int maceps2_open(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { + printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); + return -EBUSY; + } + + /* Reset port */ + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + + /* Enable interrupts */ + mace_write(PS2_CONTROL_RX_CLOCK_ENABLE | PS2_CONTROL_TX_ENABLE | + PS2_CONTROL_RX_INT_ENABLE, data->port->control); + + return 0; +} + +static void maceps2_close(struct serio *dev) +{ + struct maceps2_data *data = (struct maceps2_data *)dev->driver; + + mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, + data->port->control); + udelay(100); + free_irq(data->irq, dev); +} + +static struct maceps2_data port0_data, port1_data; + +static struct serio maceps2_port0 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port0", + .phys = "mace/serio0", + .driver = &port0_data, +}; + +static struct serio maceps2_port1 = +{ + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port1", + .phys = "mace/serio1", + .driver = &port1_data, +}; + +static int __init maceps2_init(void) +{ + port0_data.port = &mace->perif.ps2.keyb; + port0_data.irq = MACEISA_KEYB_IRQ; + port1_data.port = &mace->perif.ps2.mouse; + port1_data.irq = MACEISA_MOUSE_IRQ; + serio_register_port(&maceps2_port0); + serio_register_port(&maceps2_port1); + + return 0; +} + +static void __exit maceps2_exit(void) +{ + serio_unregister_port(&maceps2_port0); + serio_unregister_port(&maceps2_port1); +} + +module_init(maceps2_init); +module_exit(maceps2_exit);