Re: Merging Skylark's IOC3 patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* Martin Michlmayr <tbm@xxxxxxxxxx> [2006-02-19 21:15]:
> Can you please review and/or merge Skylark's IOC3 patch from
> ftp://ftp.linux-mips.org/pub/linux/mips/people/skylark/linux-mips-2.6.14-ioc3-r26.patch.bz2
> 
> From my basic understanding I believe that this patch needs to be split up
> and submitted to different sub-system maintainers.

(Dmitry, this is only a RFC for now since the main support patch
for IOC3 has not been merged yet.)


From: Stanislaw Skowronek <skylark@xxxxxxxxxxxxxx>

[PATCH 2/5] serio: SGI IOC3 PS/2 controller driver

Add a PS/2 driver based on the SGI IOC3.  This is useful for SGI Octane
machines (IP27).

Signed-off-by: Stanislaw Skowronek <skylark@xxxxxxxxxxxxxx>
Signed-off-by: Martin Michlmayr <tbm@xxxxxxxxxx>

---

 Kconfig   |    7 ++
 Makefile  |    1 
 ioc3kbd.c |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 180 insertions(+)

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 98acf17..7dedec0 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -18,6 +18,13 @@ config SERIO
 
 if SERIO
 
+config SERIO_SGI_IOC3
+	tristate "SGI IOC3 keyboard controller"
+	default y
+	depends on SGI_IOC3
+	---help---
+	  If you have an Octane and you want to use its keyboard, select this.
+
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 4155197..14cb41b 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -18,5 +18,6 @@ obj-$(CONFIG_HP_SDC)		+= hp_sdc.o
 obj-$(CONFIG_HIL_MLC)		+= hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
+obj-$(CONFIG_SERIO_SGI_IOC3)	+= ioc3kbd.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
 obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
--- /dev/null	2006-02-13 15:11:07.474148640 +0000
+++ b/drivers/input/serio/ioc3kbd.c	2006-02-19 21:26:55.000000000 +0000
@@ -0,0 +1,172 @@
+/*
+ * SGI IOC3 PS/2 controller driver for Linux
+ *
+ * Copyright (C) 2005 Stanislaw Skowronek <skylark@xxxxxxxxxxxxxx>
+ */
+#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 <linux/err.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <linux/ioc3.h>
+
+MODULE_AUTHOR("Stanislaw Skowronek <skylark@xxxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("SGI IOC3 serio driver");
+MODULE_LICENSE("GPL");
+
+struct ioc3kbd_data {
+	struct ioc3_driver_data *idd;
+	struct serio *kbd,*aux;
+};
+
+static int ioc3kbd_write(struct serio *dev, unsigned char val)
+{
+	struct ioc3kbd_data *d = (struct ioc3kbd_data *)(dev->port_data);
+	unsigned mask;
+	unsigned long timeout=0;
+
+	mask = (dev==d->aux) ? KM_CSR_M_WRT_PEND : KM_CSR_K_WRT_PEND;
+	while((d->idd->vma->km_csr & mask) && (timeout<1000)) {
+		udelay(100);
+		timeout++;
+	}
+
+	if(dev==d->aux)
+		d->idd->vma->m_wd=((unsigned)val)&0x000000ff;
+	else
+		d->idd->vma->k_wd=((unsigned)val)&0x000000ff;
+
+	if(timeout>=1000)
+		return -1;
+	return 0;
+}
+
+static int ioc3kbd_intr(struct ioc3_submodule *is, struct ioc3_driver_data *idd, unsigned int irq, struct pt_regs *regs)
+{
+	struct ioc3kbd_data *d = (struct ioc3kbd_data *)(idd->data[is->id]);
+	unsigned int data_k, data_m;
+
+	ioc3_ack(is,idd,irq);
+	data_k=d->idd->vma->k_rd;
+	data_m=d->idd->vma->m_rd;
+
+	if(data_k & KM_RD_VALID_0)
+		serio_interrupt(d->kbd, (data_k >> KM_RD_DATA_0_SHIFT) & 0xFF, 0, regs);
+	if(data_k & KM_RD_VALID_1)
+		serio_interrupt(d->kbd, (data_k >> KM_RD_DATA_1_SHIFT) & 0xFF, 0, regs);
+	if(data_k & KM_RD_VALID_2)
+		serio_interrupt(d->kbd, (data_k >> KM_RD_DATA_2_SHIFT) & 0xFF, 0, regs);
+	if(data_m & KM_RD_VALID_0)
+		serio_interrupt(d->aux, (data_m >> KM_RD_DATA_0_SHIFT) & 0xFF, 0, regs);
+	if(data_m & KM_RD_VALID_1)
+		serio_interrupt(d->aux, (data_m >> KM_RD_DATA_1_SHIFT) & 0xFF, 0, regs);
+	if(data_m & KM_RD_VALID_2)
+		serio_interrupt(d->aux, (data_m >> KM_RD_DATA_2_SHIFT) & 0xFF, 0, regs);
+
+	return 0;
+}
+
+static int ioc3kbd_open(struct serio *dev)
+{
+	return 0;
+}
+
+static void ioc3kbd_close(struct serio *dev)
+{
+}
+
+static struct ioc3kbd_data * __init ioc3kbd_allocate_port(int idx, struct ioc3_driver_data *idd)
+{
+	struct serio *sk, *sa;
+	struct ioc3kbd_data *d;
+
+	sk = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	sa = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	d = kmalloc(sizeof(struct ioc3kbd_data), GFP_KERNEL);
+	if (sk && sa && d) {
+		memset(sk, 0, sizeof(struct serio));
+		sk->id.type = SERIO_8042;
+		sk->write = ioc3kbd_write;
+		sk->open = ioc3kbd_open;
+		sk->close = ioc3kbd_close;
+		snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", idx);
+		snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", idx);
+		sk->port_data = d;
+		sk->dev.parent = &(idd->pdev->dev);
+		memset(sa, 0, sizeof(struct serio));
+		sa->id.type = SERIO_8042;
+		sa->write = ioc3kbd_write;
+		sa->open = ioc3kbd_open;
+		sa->close = ioc3kbd_close;
+		snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", idx);
+		snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", idx);
+		sa->port_data = d;
+		sa->dev.parent = &(idd->pdev->dev);
+		d->idd = idd;
+		d->kbd = sk;
+		d->aux = sa;
+		return d;
+	}
+	return NULL;
+}
+
+static int ioc3kbd_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+	struct ioc3kbd_data *d;
+	if(idd->class != IOC3_CLASS_BASE_IP30 && idd->class != IOC3_CLASS_CADDUO)
+		return 1;
+	d = ioc3kbd_allocate_port(idd->id, idd);
+	idd->data[is->id] = d;
+	if(!d)
+		return 1;
+	ioc3_enable(is, idd);
+	serio_register_port(d->kbd);
+	serio_register_port(d->aux);
+	return 0;
+}
+
+static int ioc3kbd_remove(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+	struct ioc3kbd_data *d = (struct ioc3kbd_data *)(idd->data[is->id]);
+	serio_unregister_port(d->kbd);
+	serio_unregister_port(d->aux);
+	kfree(d->kbd);
+	kfree(d->aux);
+	kfree(d);
+	idd->data[is->id] = NULL;
+	return 0;
+}
+
+static struct ioc3_submodule ioc3kbd_submodule = {
+	.name = "serio",
+	.probe = ioc3kbd_probe,
+	.remove = ioc3kbd_remove,
+	.irq_mask = SIO_IR_KBD_INT,
+	.intr = ioc3kbd_intr,
+	.owner = THIS_MODULE,
+};
+
+static int __init ioc3kbd_init(void)
+{
+	ioc3_register_submodule(&ioc3kbd_submodule);
+	return 0;
+}
+
+static void __exit ioc3kbd_exit(void)
+{
+	ioc3_unregister_submodule(&ioc3kbd_submodule);
+}
+
+module_init(ioc3kbd_init);
+module_exit(ioc3kbd_exit);


-- 
Martin Michlmayr
http://www.cyrius.com/


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux