Arctic-2 touchscreen driver
David Gibson
david at gibson.dropbear.id.au
Wed Dec 18 13:35:48 EST 2002
Below is a patch against linuxppc_2_4_devel which adds support for the
touchscreen controller on the Arctic-2: this is a Semtech device
attached to the 405LP's second serial port.
This driver is *not* ready to be committed to the tree - if nothing
else, it arbitrarily allocates a new constant in
include/linux/serio.h. Still, I'm sending this patch out so people
can look at it, and so the (very few, so far) people outside IBM with
Arctic-2s can start to play with it.
diff -urN /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/Config.in linux-bartholomew/drivers/char/Config.in
--- /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/Config.in 2002-12-16 15:09:46.000000000 +1100
+++ linux-bartholomew/drivers/char/Config.in 2002-12-17 16:24:31.000000000 +1100
@@ -361,4 +361,9 @@
tristate 'Xilinx on-chip GPIO' CONFIG_XILINX_GPIO
fi
+# FIXME: depend on SERIO/SERPORT too?
+if [ "$CONFIG_ARCTIC2" = "y" ]; then
+ tristate 'Arctic II Semtech Touchscreen controller' CONFIG_IBMTS_SEMTECH
+fi
+
endmenu
diff -urN /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/Makefile linux-bartholomew/drivers/char/Makefile
--- /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/Makefile 2002-12-16 15:09:46.000000000 +1100
+++ linux-bartholomew/drivers/char/Makefile 2002-12-17 16:24:59.000000000 +1100
@@ -290,6 +290,7 @@
obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
obj-$(CONFIG_PPC405_WDT) += ppc405_wdt.o
obj-$(CONFIG_IBM_OCP_GPIO) += ibm_ocp_gpio.o
+obj-$(CONFIG_IBMTS_SEMTECH) += ibmts_semtech.o
mod-subdirs += xilinx_gpio
subdir-$(CONFIG_XILINX_GPIO) += xilinx_gpio
diff -urN /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/ibmts_semtech.c linux-bartholomew/drivers/char/ibmts_semtech.c
--- /home/dgibson/kernel/linuxppc_2_4_devel/drivers/char/ibmts_semtech.c Thu Jan 01 10:00:00 1970
+++ linux-bartholomew/drivers/char/ibmts_semtech.c Wed Dec 18 13:32:31 2002
@@ -0,0 +1,380 @@
+/* IBM Arctic-2 Semtech touch panel controller driver for /dev/ibmts interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2002 IBM Corporation.
+ *
+ * Ken Inoue
+ * IBM Thomas J. Watson Research Center
+ * <keninoue at us.ibm.com>
+ *
+ * David Gibson
+ * IBM OzLabs, Canberra, Australia.
+ * <arctic at gibson.dropbear.id.au>
+ */
+
+#include <linux/module.h> /* Get my module mojo */
+#include <linux/types.h> /* int16_t ... */
+#include <linux/poll.h> /* polling macros */
+#include <linux/interrupt.h> /* Tasklets */
+#include <linux/sched.h> /* wait_on, etc */
+#include <linux/wait.h> /* wait queues */
+#include <linux/init.h> /* module_init() macro */
+#include <linux/spinlock.h> /* mutex structures/code */
+#include <linux/fs.h> /* struct file, struct inode */
+#include <linux/serio.h>
+
+#define IBMTS_DEVICE_NAME "ibmts"
+#define IBMTS_MAJOR 254
+
+#define IBMTS_SAMPLES 128
+#define IBMTS_TIMEOUT_INTERVAL 10
+
+#define PEN_RELEASE 0
+#define PEN_GLIDE 2
+#define PEN_PRESS 1
+
+struct ts_event {
+ short pressure; /* Pressure of stylus - 0 for release, positive otherwise */
+ int x; /* X coordinate stylus - -1 for PEN_RELEASE */
+ int y; /* Y coordinate stylus - -1 for PEN_RELEASE */
+ int millisecs; /* A timestamp */
+ unsigned int flags; /* kind of event, and reserved bits */
+};
+
+typedef struct ibmts_semtech_event {
+ struct ibmts_semtech_event *pNext;
+ struct ts_event event;
+} ibmts_semtech_event;
+
+// HACK: FIXME: put the following in a dynamically allocated struct
+
+static int IsOpenForRead = 0;
+
+static unsigned char pen_down = 0;
+
+static wait_queue_head_t ibmts_semtech_proc_list;
+
+static spinlock_t ibmts_semtech_lock = SPIN_LOCK_UNLOCKED;
+
+#define SEMTECH_FSM_RESET 0
+#define SEMTECH_FSM_DATA_READY 4
+
+#define SEMTECH_SYNC_FLAG 0x80
+
+static unsigned char semtech_FSM = SEMTECH_FSM_RESET;
+static unsigned char semtech_data_index = 0;
+static unsigned char semtech_data[4];
+static unsigned char semtech_FSM_next[] = {
+ (SEMTECH_FSM_RESET + 1), (SEMTECH_FSM_RESET + 2),
+ (SEMTECH_FSM_RESET + 3), SEMTECH_FSM_DATA_READY
+};
+
+static ibmts_semtech_event events[IBMTS_SAMPLES];
+
+static ibmts_semtech_event *ibmts_semtech_rdp = NULL;
+static ibmts_semtech_event *ibmts_semtech_wrp = NULL;
+
+static int queue_empty(void)
+{
+ return (ibmts_semtech_rdp == ibmts_semtech_wrp);
+}
+
+struct ts_event *ibmts_semtech_get_event(void)
+{
+ unsigned long flags;
+ ibmts_semtech_event *result;
+
+ spin_lock_irqsave(&ibmts_semtech_lock, flags);
+
+ if ( (ibmts_semtech_rdp == NULL) || queue_empty() )
+ return NULL;
+
+ result = ibmts_semtech_rdp;
+ ibmts_semtech_rdp = ibmts_semtech_rdp->pNext;
+
+ spin_unlock_irqrestore(&ibmts_semtech_lock, flags);
+ return &(result->event);
+};
+
+static void ibmts_semtech_put_event(struct ts_event *pEvent)
+{
+ if ( ibmts_semtech_rdp == NULL)
+ return;
+
+ if (! IsOpenForRead)
+ return;
+
+ ibmts_semtech_wrp->event.pressure = pEvent->pressure;
+ ibmts_semtech_wrp->event.x = pEvent->x;
+ ibmts_semtech_wrp->event.y = pEvent->y;
+ ibmts_semtech_wrp->event.millisecs = pEvent->millisecs;
+ ibmts_semtech_wrp->event.flags = pEvent->flags;
+
+ ibmts_semtech_wrp = ibmts_semtech_wrp->pNext;
+ if (ibmts_semtech_wrp == ibmts_semtech_rdp) /* Wrap */
+ ibmts_semtech_rdp = ibmts_semtech_rdp->pNext; /* Write over */
+ else
+ if (waitqueue_active(&ibmts_semtech_proc_list))
+ wake_up_interruptible(&ibmts_semtech_proc_list);
+}
+
+static int ibmts_semtech_open(struct inode *inode, struct file *file)
+{
+ int i;
+
+ printk("ibmts: %d.%d\n",
+ inode->i_rdev >> 8, inode->i_rdev & 0xFF);
+ if (file->f_flags & O_NONBLOCK)
+ printk("ibmts: Non-blocked mode\n");
+ else
+ printk("ibmts: Blocked mode\n");
+
+ if ((file-> f_mode & FMODE_READ)) {
+ if (IsOpenForRead)
+ return -EBUSY;
+ IsOpenForRead++;
+ }
+
+
+ /* Initialize the structs. */
+ ibmts_semtech_rdp = &(events[0]);
+ ibmts_semtech_wrp = ibmts_semtech_rdp;
+ for (i=0; i<IBMTS_SAMPLES; i++)
+ events[i].pNext = &(events[i+1]);
+
+ events[IBMTS_SAMPLES-1].pNext = &(events[0]);
+ pen_down = 0;
+ semtech_FSM = SEMTECH_FSM_RESET;
+ semtech_data_index = 0;
+
+ MOD_INC_USE_COUNT;
+
+ return 0;
+}
+
+
+static int ibmts_semtech_release(struct inode *inode, struct file *file)
+{
+ if ((file-> f_mode & FMODE_READ))
+ IsOpenForRead--;
+
+ MOD_DEC_USE_COUNT;
+
+ return 0;
+}
+
+static ssize_t ibmts_semtech_read(struct file *pFile, char *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t bytes_read = 0;
+ struct ts_event *pWork;
+
+ while (queue_empty()) { /* wait for an event */
+ if (pFile->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ if (wait_event_interruptible(ibmts_semtech_proc_list, ! queue_empty()))
+ return -ERESTARTSYS;
+ }
+
+ while ( (bytes_read < count) && (! queue_empty()) ) {
+ pWork = ibmts_semtech_get_event();
+ if (pWork) {
+ if (copy_to_user (buffer + bytes_read, (void *) pWork,
+ sizeof(struct ts_event))) {
+ bytes_read = -EFAULT;
+ break;
+ }
+ bytes_read += sizeof(struct ts_event);
+ if (count - bytes_read < sizeof(struct ts_event)) break;
+ }
+ }
+
+ if (bytes_read > 0)
+ return bytes_read;
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ return bytes_read;
+}
+
+static ssize_t ibmts_semtech_write(struct file *file, const char *buffer,
+ size_t length, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static int ibmts_semtech_ioctl(struct inode * dev_inode, struct file *filep,
+ unsigned int cmd, unsigned long arg)
+{
+ return -EINVAL;
+}
+
+/*
+ Poll for input - return code indicating if there is input to read.
+ */
+
+static unsigned int
+ibmts_semtech_poll (struct file* filp, poll_table * wait)
+{
+ poll_wait(filp, &ibmts_semtech_proc_list, wait);
+ return queue_empty() ? 0 : (POLLIN | POLLRDNORM);
+}
+
+/* Module Declarations ***************************** */
+
+static struct file_operations ibmts_semtech_fops = {
+ .owner = THIS_MODULE,
+ .open = ibmts_semtech_open,
+ .read = ibmts_semtech_read,
+ .write = ibmts_semtech_write,
+ .ioctl = ibmts_semtech_ioctl,
+ .poll = ibmts_semtech_poll,
+ .release = ibmts_semtech_release
+};
+
+/*
+ * Serial I/O routines (requires drivers/char/joystick/serio and serport)
+ */
+
+static void semtech_parse_data(unsigned char *pData)
+{
+ struct ts_event event;
+ unsigned int dx, dy;
+
+/* #define IBMTS_SEMTECH_XYSWAP */
+
+#if defined(IBMTS_SEMTECH_XYSWAP)
+ dx = (((unsigned int)pData[1] & 0x70) << 3) | ((unsigned int)pData[3] & 0x7f);
+ dy = (((unsigned int)pData[1] & 0x07) << 7) | ((unsigned int)pData[2] & 0x7f);
+#else
+ dy = (((unsigned int)pData[1] & 0x70) << 3) | ((unsigned int)pData[3] & 0x7f);
+ dx = (((unsigned int)pData[1] & 0x07) << 7) | ((unsigned int)pData[2] & 0x7f);
+#endif
+
+ if (! pen_down) { /* Pen up until now */
+ if (( pData[0] & 0x1f)) { /* Pen still up */
+ return;
+ } else {
+ event.flags = PEN_PRESS; /* Press */
+ event.x = dx;
+ event.y = dy;
+ event.pressure = 500;
+ event.millisecs = jiffies*10;
+ pen_down = 1;
+ }
+
+ } else { /* Pen was down */
+ if (pData[0] & 0x07f) { /* Pen up */
+ event.flags = PEN_RELEASE; /* 0: Up */
+ event.x = -1;
+ event.y = -1;
+ event.pressure = 0;
+ event.millisecs = jiffies*10;
+ pen_down = 0;
+ } else {
+ event.flags = PEN_GLIDE;
+ event.x = dx;
+ event.y = dy;
+ event.pressure = 500;
+ event.millisecs = jiffies * 10;
+ }
+ }
+ ibmts_semtech_put_event(&event); /* Wakeup handled in put_event() */
+}
+
+static void semtechts_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ /* Between packets & sync flag on, or In packet & sync flag off */
+ if ( ( (semtech_FSM == SEMTECH_FSM_RESET) && (data & SEMTECH_SYNC_FLAG) ) ||
+ ( (semtech_FSM != SEMTECH_FSM_RESET) && !(data & SEMTECH_SYNC_FLAG) ) ) {
+ /* Record and proceed to next stage */
+ semtech_data[semtech_data_index++] = data;
+ semtech_FSM = semtech_FSM_next[semtech_FSM];
+ } else { /* Out of sync */
+ semtech_FSM = SEMTECH_FSM_RESET;
+ }
+
+ /* Full packet received, process it now */
+ if (semtech_FSM == SEMTECH_FSM_DATA_READY) {
+ semtech_parse_data(semtech_data);
+ semtech_FSM = SEMTECH_FSM_RESET;
+ semtech_data_index = 0;
+ }
+
+}
+
+static void semtechts_connect(struct serio *serio, struct serio_dev *dev)
+{
+ if (serio->type != (SERIO_RS232 | SERIO_SEMTECHTS)) { /* Must be in serio.h and inputattach.c */
+ printk("semtechts_connect(): serio has wrong type\n");
+ return;
+ }
+
+ if (serio_open(serio, dev)) {
+ printk("semtechts: serio_open failed\n");
+ return;
+ }
+}
+
+static void semtechts_disconnect(struct serio *serio)
+{
+ serio_close(serio);
+}
+
+static struct serio_dev semtechts_dev = {
+ .interrupt = semtechts_interrupt,
+ .connect = semtechts_connect,
+ .disconnect = semtechts_disconnect,
+};
+
+MODULE_AUTHOR("Ken Inoue");
+MODULE_DESCRIPTION("IBM Arctic-2 Semtech touch panel controller driver\n");
+
+int __init init_ibmts_semtech_module(void)
+{
+ int err;
+
+ init_waitqueue_head(&ibmts_semtech_proc_list);
+
+ err = register_chrdev(IBMTS_MAJOR, IBMTS_DEVICE_NAME, &ibmts_semtech_fops);
+
+ if (err < 0) {
+ printk("ibmts_semtech: register_chrdev failed with %d\n", err);
+ return err;
+ }
+
+ printk("ibmts_semtech: v0.02 e-8 device major %d \n", IBMTS_MAJOR);
+
+ serio_register_device(&semtechts_dev);
+
+ return 0;
+}
+
+void cleanup_ibmts_semtech_module(void)
+{
+ int ret;
+
+ ret = unregister_chrdev(IBMTS_MAJOR, IBMTS_DEVICE_NAME);
+ if (ret < 0)
+ printk("Error : unregister_chrdev: %d\n", ret);
+
+ serio_unregister_device(&semtechts_dev);
+}
+
+module_init(init_ibmts_semtech_module);
+module_exit(cleanup_ibmts_semtech_module);
--
David Gibson | For every complex problem there is a
david at gibson.dropbear.id.au | solution which is simple, neat and
| wrong.
http://www.ozlabs.org/people/dgibson
** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/
More information about the Linuxppc-embedded
mailing list