All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vojtech Pavlik <vojtech@suse.cz>
To: torvalds@osdl.org, vojtech@suse.cz, linux-kernel@vger.kernel.org
Subject: [PATCH 40/47] Add serio_raw driver
Date: Thu, 29 Jul 2004 16:09:56 +0200	[thread overview]
Message-ID: <1091110196869@twilight.ucw.cz> (raw)
In-Reply-To: <10911101963350@twilight.ucw.cz>

You can pull this changeset from:
	bk://kernel.bkbits.net/vojtech/input

===================================================================

ChangeSet@1.1757.15.35, 2004-06-29 01:31:03-05:00, dtor_core@ameritech.net
  Input: Add serio_raw driver that binds to serio ports and provides
         unobstructed access to the underlying serio port via a char
         device. The driver tries to register char device 10,1
         (/dev/psaux) first and if it fails goes for dynamically
         allocated minor. To bind use sysfs interface:
  
         echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
  
  Signed-off-by: Dmitry Torokhov <dtor@mail.ru>


 Kconfig     |   16 ++
 Makefile    |    1 
 serio_raw.c |  390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 407 insertions(+)

===================================================================

diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	Thu Jul 29 14:39:02 2004
+++ b/drivers/input/serio/Kconfig	Thu Jul 29 14:39:02 2004
@@ -130,3 +130,19 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called maceps2.
+
+config SERIO_RAW
+	tristate "Raw access to serio ports"
+	depends on SERIO
+	help
+	  Say Y here if you want to have raw access to serio ports, such as
+	  AUX ports on i8042 keyboard controller. Each serio port that is
+	  bound to this driver will be accessible via a char device with
+	  major 10 and dynamically allocated minor. The driver will try
+	  allocating minor 1 (that historically corresponds to /dev/psaux)
+	  first. To bind this driver to a serio port use sysfs interface:
+
+	      echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called serio_raw.
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	Thu Jul 29 14:39:02 2004
+++ b/drivers/input/serio/Makefile	Thu Jul 29 14:39:02 2004
@@ -17,3 +17,4 @@
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
+obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
diff -Nru a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/serio_raw.c	Thu Jul 29 14:39:02 2004
@@ -0,0 +1,390 @@
+/*
+ * Raw serio device providing access to a raw byte stream from underlying
+ * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
+ *
+ * Copyright (c) 2004 Dmitry Torokhov
+ *
+ * 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/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/device.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+#define DRIVER_DESC	"Raw serio driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define SERIO_RAW_QUEUE_LEN	64
+struct serio_raw {
+	unsigned char queue[SERIO_RAW_QUEUE_LEN];
+	unsigned int tail, head;
+
+	char name[16];
+	unsigned int refcnt;
+	struct serio *serio;
+	struct miscdevice dev;
+	wait_queue_head_t wait;
+	struct list_head list;
+	struct list_head node;
+};
+
+struct serio_raw_list {
+	struct fasync_struct *fasync;
+	struct serio_raw *serio_raw;
+	struct list_head node;
+};
+
+static DECLARE_MUTEX(serio_raw_sem);
+static LIST_HEAD(serio_raw_list);
+static unsigned int serio_raw_no;
+
+/*********************************************************************
+ *             Interface with userspace (file operations)            *
+ *********************************************************************/
+
+static int serio_raw_fasync(int fd, struct file *file, int on)
+{
+	struct serio_raw_list *list = file->private_data;
+	int retval;
+
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static struct serio_raw *serio_raw_locate(int minor)
+{
+	struct serio_raw *serio_raw;
+
+	list_for_each_entry(serio_raw, &serio_raw_list, node) {
+		if (serio_raw->dev.minor == minor)
+			return serio_raw;
+	}
+
+	return NULL;
+}
+
+static int serio_raw_open(struct inode *inode, struct file *file)
+{
+	struct serio_raw *serio_raw;
+	struct serio_raw_list *list;
+	int retval = 0;
+
+	retval = down_interruptible(&serio_raw_sem);
+	if (retval)
+		return retval;
+
+	if (!(serio_raw = serio_raw_locate(iminor(inode)))) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (!serio_raw->serio) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	memset(list, 0, sizeof(struct serio_raw_list));
+	list->serio_raw = serio_raw;
+	file->private_data = list;
+
+	serio_raw->refcnt++;
+	list_add_tail(&list->node, &serio_raw->list);
+
+out:
+	up(&serio_raw_sem);
+	return retval;
+}
+
+static int serio_raw_cleanup(struct serio_raw *serio_raw)
+{
+	if (--serio_raw->refcnt == 0) {
+		misc_deregister(&serio_raw->dev);
+		list_del_init(&serio_raw->node);
+		kfree(serio_raw);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int serio_raw_release(struct inode *inode, struct file *file)
+{
+	struct serio_raw_list *list = file->private_data;
+	struct serio_raw *serio_raw = list->serio_raw;
+
+	down(&serio_raw_sem);
+
+	serio_raw_fasync(-1, file, 0);
+	serio_raw_cleanup(serio_raw);
+
+	up(&serio_raw_sem);
+	return 0;
+}
+
+static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&serio_raw->serio->lock, flags);
+
+	empty = serio_raw->head == serio_raw->tail;
+	if (!empty) {
+		*c = serio_raw->queue[serio_raw->tail];
+		serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
+	}
+
+	spin_unlock_irqrestore(&serio_raw->serio->lock, flags);
+
+	return !empty;
+}
+
+static ssize_t serio_raw_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct serio_raw_list *list = file->private_data;
+	struct serio_raw *serio_raw = list->serio_raw;
+	char c;
+	ssize_t retval = 0;
+
+	if (!serio_raw->serio)
+		return -ENODEV;
+
+	if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(list->serio_raw->wait,
+					  serio_raw->head != serio_raw->tail || !serio_raw->serio);
+	if (retval)
+		return retval;
+
+	if (!serio_raw->serio)
+		return -ENODEV;
+
+	while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
+		if (put_user(c, buffer++))
+			return -EFAULT;
+		retval++;
+	}
+
+	return retval;
+}
+
+static ssize_t serio_raw_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct serio_raw_list *list = file->private_data;
+	ssize_t written = 0;
+	int retval;
+	unsigned char c;
+
+	retval = down_interruptible(&serio_raw_sem);
+	if (retval)
+		return retval;
+
+	if (!list->serio_raw->serio) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (count > 32)
+		count = 32;
+
+	while (count--) {
+		if (get_user(c, buffer++)) {
+			retval = -EFAULT;
+			goto out;
+		}
+		if (serio_write(list->serio_raw->serio, c)) {
+			retval = -EIO;
+			goto out;
+		}
+		written++;
+	};
+
+out:
+	up(&serio_raw_sem);
+	return written;
+}
+
+static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
+{
+	struct serio_raw_list *list = file->private_data;
+
+	poll_wait(file, &list->serio_raw->wait, wait);
+
+	if (list->serio_raw->head != list->serio_raw->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+struct file_operations serio_raw_fops = {
+	.owner =	THIS_MODULE,
+	.open =		serio_raw_open,
+	.release =	serio_raw_release,
+	.read =		serio_raw_read,
+	.write =	serio_raw_write,
+	.poll =		serio_raw_poll,
+	.fasync =	serio_raw_fasync,
+};
+
+
+/*********************************************************************
+ *                   Interface with serio port   	             *
+ *********************************************************************/
+
+static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
+					unsigned int dfl, struct pt_regs *regs)
+{
+	struct serio_raw *serio_raw = serio->private;
+	struct serio_raw_list *list;
+	unsigned int head = serio_raw->head;
+
+	/* we are holding serio->lock here so we are prootected */
+	serio_raw->queue[head] = data;
+	head = (head + 1) % SERIO_RAW_QUEUE_LEN;
+	if (likely(head != serio_raw->tail)) {
+		serio_raw->head = head;
+		list_for_each_entry(list, &serio_raw->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		wake_up_interruptible(&serio_raw->wait);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void serio_raw_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct serio_raw *serio_raw;
+	int err;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_8042)
+		return;
+
+	if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
+		printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
+		return;
+	}
+
+	down(&serio_raw_sem);
+
+	memset(serio_raw, 0, sizeof(struct serio_raw));
+	snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
+	serio_raw->refcnt = 1;
+	serio_raw->serio = serio;
+	INIT_LIST_HEAD(&serio_raw->list);
+	init_waitqueue_head(&serio_raw->wait);
+
+	serio->private = serio_raw;
+	if (serio_open(serio, drv))
+		goto out_free;
+
+	list_add_tail(&serio_raw->node, &serio_raw_list);
+
+	serio_raw->dev.minor = PSMOUSE_MINOR;
+	serio_raw->dev.name = serio_raw->name;
+	serio_raw->dev.fops = &serio_raw_fops;
+
+	err = misc_register(&serio_raw->dev);
+	if (err) {
+		serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
+		err = misc_register(&serio_raw->dev);
+	}
+
+	if (err) {
+		printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
+			serio->phys);
+		goto out_close;
+	}
+
+	printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
+		serio->phys, serio_raw->name, serio_raw->dev.minor);
+	goto out;
+
+out_close:
+	serio_close(serio);
+	list_del_init(&serio_raw->node);
+out_free:
+	serio->private = NULL;
+	kfree(serio_raw);
+out:
+	up(&serio_raw_sem);
+}
+
+static int serio_raw_reconnect(struct serio *serio)
+{
+	struct serio_raw *serio_raw = serio->private;
+	struct serio_driver *drv = serio->drv;
+
+	if (!drv || !serio_raw) {
+		printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
+		return -1;
+	}
+
+	/*
+	 * Nothing needs to be done here, we just need this method to
+	 * keep the same device.
+	 */
+	return 0;
+}
+
+static void serio_raw_disconnect(struct serio *serio)
+{
+	struct serio_raw *serio_raw;
+
+	down(&serio_raw_sem);
+
+	serio_raw = serio->private;
+
+	serio_close(serio);
+	serio->private = NULL;
+
+	serio_raw->serio = NULL;
+	if (!serio_raw_cleanup(serio_raw))
+		wake_up_interruptible(&serio_raw->wait);
+
+	up(&serio_raw_sem);
+}
+
+static struct serio_driver serio_raw_drv = {
+	.driver		= {
+		.name	= "serio_raw",
+	},
+	.description	= DRIVER_DESC,
+	.interrupt	= serio_raw_interrupt,
+	.connect	= serio_raw_connect,
+	.reconnect	= serio_raw_reconnect,
+	.disconnect	= serio_raw_disconnect,
+	.manual_bind	= 1,
+};
+
+int __init serio_raw_init(void)
+{
+	serio_register_driver(&serio_raw_drv);
+	return 0;
+}
+
+void __exit serio_raw_exit(void)
+{
+	serio_unregister_driver(&serio_raw_drv);
+}
+
+module_init(serio_raw_init);
+module_exit(serio_raw_exit);


  reply	other threads:[~2004-07-29 14:17 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-07-29 14:07 [patches] Input updates Vojtech Pavlik
2004-07-29 14:09 ` [PATCH 1/47] Add 64-bit compatible ioctls for hiddev Vojtech Pavlik
2004-07-29 14:09   ` [PATCH 2/47] Fix locking in i8042.c and serio.c Vojtech Pavlik
2004-07-29 14:09     ` [PATCH 3/47] Fix an oops in poll() on uinput Vojtech Pavlik
2004-07-29 14:09       ` [PATCH 4/47] Ensure exclusive access to variables in atkbd.c Vojtech Pavlik
2004-07-29 14:09         ` [PATCH 5/47] Return 0 from uinput poll if device isn't yet created Vojtech Pavlik
2004-07-29 14:09           ` [PATCH 6/47] Explicit variable access rules for psmouse.c Vojtech Pavlik
2004-07-29 14:09             ` [PATCH 7/47] Add reporting of raw scancodes to atkbd.c Vojtech Pavlik
2004-07-29 14:09               ` [PATCH 8/47] Use raw events generated by atkbd in keyboard.c to implement true rawmode for PS/2 keyboards Vojtech Pavlik
2004-07-29 14:09                 ` [PATCH 9/47] Fixes in serio locking Vojtech Pavlik
2004-07-29 14:09                   ` [PATCH 10/47] Disable the AUX LoopBack command in i8042.c on Compaq ProLiant Vojtech Pavlik
2004-07-29 14:09                     ` [PATCH 11/47] Make atkbd.c's atkbd_command() function immune to keys being pressed while running Vojtech Pavlik
2004-07-29 14:09                       ` [PATCH 12/47] More locking improvements (and a fix) for serio Vojtech Pavlik
2004-07-29 14:09                         ` [PATCH 13/47] Add a missing dmi_noloop declaration in i8042.c Vojtech Pavlik
2004-07-29 14:09                           ` [PATCH 14/47] logips2pp - do not call get_model_info 2 times Vojtech Pavlik
2004-07-29 14:09                             ` [PATCH 15/47] Fix compilation breakage when CONFIG_USB_HIDDEV not defined Vojtech Pavlik
2004-07-29 14:09                               ` [PATCH 16/47] Make hardware rawmode optional for AT-keyboards Vojtech Pavlik
2004-07-29 14:09                                 ` [PATCH 17/47] Fix boundary checks for GUSAGE/SUSAGE in hiddev Vojtech Pavlik
2004-07-29 14:09                                   ` [PATCH 18/47] Updates to the tsdev driver (raw protocol, calib ioctls, ...) Vojtech Pavlik
2004-07-29 14:09                                     ` [PATCH 19/47] mousedev - better handle button presses when under load Vojtech Pavlik
2004-07-29 14:09                                       ` [PATCH 20/47] mousedev - implement tapping for touchpads Vojtech Pavlik
2004-07-29 14:09                                         ` [PATCH 21/47] Remove OSB4/Profusion hack in i8042 Vojtech Pavlik
2004-07-29 14:09                                           ` [PATCH 22/47] rearrangements and cleanups in serio.c Vojtech Pavlik
2004-07-29 14:09                                             ` [PATCH 23/47] Fix bad struct hidinput initialization in hid-tmff.c Vojtech Pavlik
2004-07-29 14:09                                               ` [PATCH 24/47] Remove an extra dmi_noloop declaration in i8042.c Vojtech Pavlik
2004-07-29 14:09                                                 ` [PATCH 25/47] Enhancements/fixes for PSX pad support Vojtech Pavlik
2004-07-29 14:09                                                   ` [PATCH 26/47] when probing for ImExPS/2 mice, the ImPS/2 sequence needs to be sent first Vojtech Pavlik
2004-07-29 14:09                                                     ` [PATCH 27/47] Fix array overflows in keyboard.c when KEY_MAX > keycode > NR_KEYS > 128 Vojtech Pavlik
2004-07-29 14:09                                                       ` [PATCH 28/47] Add Dell SB Live! PCI ID to the emu10k1-gp driver Vojtech Pavlik
2004-07-29 14:09                                                         ` [PATCH 29/47] Add Audigy LS PCI ID to emu10k1-gp Vojtech Pavlik
2004-07-29 14:09                                                           ` [PATCH 30/47] Add CodeMercs IOWarrior to hid-core device blacklist Vojtech Pavlik
2004-07-29 14:09                                                             ` [PATCH 31/47] Fix Peter Nelson's e-mail address in gamecon.c Vojtech Pavlik
2004-07-29 14:09                                                               ` [PATCH 32/47] make connect and disconnect methods mandatory for serio Vojtech Pavlik
2004-07-29 14:09                                                                 ` [PATCH 33/47] rename serio->driver to serio->port_data Vojtech Pavlik
2004-07-29 14:09                                                                   ` [PATCH 34/47] more renames in serio in preparation for sysfs integration Vojtech Pavlik
2004-07-29 14:09                                                                     ` [PATCH 35/47] switch to dynamic (heap) serio port allocation Vojtech Pavlik
2004-07-29 14:09                                                                       ` [PATCH 36/47] allow serio drivers to create children ports Vojtech Pavlik
2004-07-29 14:09                                                                         ` [PATCH 37/47] serio sysfs integration Vojtech Pavlik
2004-07-29 14:09                                                                           ` [PATCH 38/47] allow users to manually rebind serio ports Vojtech Pavlik
2004-07-29 14:09                                                                             ` [PATCH 39/47] allow marking some drivers as manual bind only Vojtech Pavlik
2004-07-29 14:09                                                                               ` Vojtech Pavlik [this message]
2004-07-29 14:09                                                                                 ` [PATCH 41/47] link (some) serio ports to their parent devices Vojtech Pavlik
2004-07-29 14:09                                                                                   ` [PATCH 42/47] Fix Kconfig so that the joydump module can be compiled Vojtech Pavlik
2004-07-29 14:09                                                                                     ` [PATCH 43/47] Move Compaq ProLiant DMI handling to i8042.c Vojtech Pavlik
2004-07-29 14:09                                                                                       ` [PATCH 44/47] This patch fixes another disconnect oops in hiddev Vojtech Pavlik
2004-07-29 14:09                                                                                         ` [PATCH 45/47] Re-add PC Speaker support for PPC Vojtech Pavlik
2004-07-29 14:09                                                                                           ` [PATCH 46/47] Fix a missing index in tmdc.c Vojtech Pavlik
2004-07-29 14:09                                                                                             ` [PATCH 47/47] Check the range for HIDIOC?USAGES num_values Vojtech Pavlik
2004-07-29 16:59 ` [patches] Input updates Vojtech Pavlik
2004-07-29 16:59   ` [PATCH 1/2] move input/serio closer to the top of drivers/Makefile so serio_bus is available early Vojtech Pavlik
2004-07-29 16:59     ` [PATCH 2/2] rearrange code in sunzilog to prevent deadlock Vojtech Pavlik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1091110196869@twilight.ucw.cz \
    --to=vojtech@suse.cz \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.