Interface management.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/include/ectty.h Tue Dec 01 21:45:45 2009 +0100
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ * $Id$
+ *
+ * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
+ *
+ * This file is part of the IgH EtherCAT master userspace library.
+ *
+ * The IgH EtherCAT master userspace library is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the IgH EtherCAT master userspace library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * ---
+ *
+ * The license mentioned above concerns the source code only. Using the
+ * EtherCAT technology and brand is only permitted in compliance with the
+ * industrial property and similar rights of Beckhoff Automation GmbH.
+ *
+ *****************************************************************************/
+
+/** \file
+ *
+ * EtherCAT virtual TTY interface.
+ *
+ * \defgroup TTYInterface EtherCAT Virtual TTY Interface
+ *
+ * @{
+ */
+
+/*****************************************************************************/
+
+#ifndef __ECTTY_H__
+#define __ECTTY_H__
+
+/******************************************************************************
+ * Data types
+ *****************************************************************************/
+
+struct ec_tty;
+typedef struct ec_tty ec_tty_t; /**< \see ec_tty */
+
+/******************************************************************************
+ * Global functions
+ *****************************************************************************/
+
+/** Create a virtual TTY interface.
+ *
+ * \return Pointer to the interface object, otherwise an ERR_PTR value.
+ */
+ec_tty_t *ectty_create(void);
+
+/******************************************************************************
+ * TTY interface methods
+ *****************************************************************************/
+
+/** Releases a virtual TTY interface.
+ */
+void ectty_free(
+ ec_tty_t *tty /**< TTY interface. */
+ );
+
+/*****************************************************************************/
+
+/** @} */
+
+#endif
--- a/tty/module.c Tue Dec 01 17:35:33 2009 +0100
+++ b/tty/module.c Tue Dec 01 21:45:45 2009 +0100
@@ -38,17 +38,23 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/termios.h>
+#include <linux/semaphore.h>
#include "../master/globals.h"
-
-/*****************************************************************************/
-
-int __init ec_tty_init_module(void);
-void __exit ec_tty_cleanup_module(void);
-
-unsigned int debug_level = 0;
+#include "../include/ectty.h"
+
+/*****************************************************************************/
+
+#define EC_TTY_MAX_DEVICES 10
+
+/*****************************************************************************/
+
char *ec_master_version_str = EC_MASTER_VERSION; /**< Version string. */
+static struct tty_driver *tty_driver = NULL;
+ec_tty_t *ttys[EC_TTY_MAX_DEVICES];
+struct semaphore tty_sem;
+
/*****************************************************************************/
/** \cond */
@@ -58,11 +64,11 @@
MODULE_LICENSE("GPL");
MODULE_VERSION(EC_MASTER_VERSION);
+unsigned int debug_level = 0;
module_param_named(debug_level, debug_level, uint, S_IRUGO);
MODULE_PARM_DESC(debug_level, "Debug level");
-struct tty_driver *tty_driver = NULL;
-struct device *tty_device = NULL;
+/** \endcond */
static int ec_tty_open(struct tty_struct *, struct file *);
static void ec_tty_close(struct tty_struct *, struct file *);
@@ -82,7 +88,10 @@
.c_cc = INIT_C_CC,
};
-/** \endcond */
+struct ec_tty {
+ int minor;
+ struct device *dev;
+};
/*****************************************************************************/
@@ -92,11 +101,17 @@
*/
int __init ec_tty_init_module(void)
{
- int ret = 0;
+ int i, ret = 0;
EC_INFO("TTY driver %s\n", EC_MASTER_VERSION);
- tty_driver = alloc_tty_driver(1);
+ init_MUTEX(&tty_sem);
+
+ for (i = 0; i < EC_TTY_MAX_DEVICES; i++) {
+ ttys[i] = NULL;
+ }
+
+ tty_driver = alloc_tty_driver(EC_TTY_MAX_DEVICES);
if (!tty_driver) {
EC_ERR("Failed to allocate tty driver.\n");
ret = -ENOMEM;
@@ -121,17 +136,8 @@
goto out_put;
}
- tty_device = tty_register_device(tty_driver, 0, NULL);
- if (IS_ERR(tty_device)) {
- EC_ERR("Failed to register tty device.\n");
- ret = PTR_ERR(tty_device);
- goto out_unreg;
- }
-
return ret;
-out_unreg:
- tty_unregister_driver(tty_driver);
out_put:
put_tty_driver(tty_driver);
out_return:
@@ -146,7 +152,6 @@
*/
void __exit ec_tty_cleanup_module(void)
{
- tty_unregister_device(tty_driver, 0);
tty_unregister_driver(tty_driver);
put_tty_driver(tty_driver);
EC_INFO("TTY module cleaned up.\n");
@@ -154,6 +159,30 @@
/*****************************************************************************/
+int ec_tty_init(ec_tty_t *tty, int minor)
+{
+ tty->minor = minor;
+
+ tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
+ if (IS_ERR(tty->dev)) {
+ EC_ERR("Failed to register tty device.\n");
+ return PTR_ERR(tty->dev);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+void ec_tty_clear(ec_tty_t *tty)
+{
+ tty_unregister_device(tty_driver, tty->minor);
+}
+
+/******************************************************************************
+ * Device callbacks
+ *****************************************************************************/
+
static int ec_tty_open(struct tty_struct *tty, struct file *file)
{
return -EBUSY;
@@ -177,6 +206,55 @@
return -EIO;
}
+/******************************************************************************
+ * Public functions and methods
+ *****************************************************************************/
+
+ec_tty_t *ectty_create(void)
+{
+ ec_tty_t *tty;
+ int minor, ret;
+
+ if (down_interruptible(&tty_sem)) {
+ return ERR_PTR(-EINTR);
+ }
+
+ for (minor = 0; minor < EC_TTY_MAX_DEVICES; minor++) {
+ if (!ttys[minor]) {
+ tty = kmalloc(sizeof(ec_tty_t), GFP_KERNEL);
+ if (!tty) {
+ up(&tty_sem);
+ EC_ERR("Failed to allocate memory for tty device.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = ec_tty_init(tty, minor);
+ if (ret) {
+ up(&tty_sem);
+ kfree(tty);
+ return ERR_PTR(ret);
+ }
+
+ ttys[minor] = tty;
+ up(&tty_sem);
+ return tty;
+ }
+ }
+
+ up(&tty_sem);
+ return ERR_PTR(-EBUSY);
+}
+
+/*****************************************************************************/
+
+void ectty_free(ec_tty_t *tty)
+{
+ int minor = tty->minor;
+ ec_tty_clear(tty);
+ ttys[minor] = NULL;
+ kfree(tty);
+}
+
/*****************************************************************************/
/** \cond */
@@ -184,6 +262,9 @@
module_init(ec_tty_init_module);
module_exit(ec_tty_cleanup_module);
+EXPORT_SYMBOL(ectty_create);
+EXPORT_SYMBOL(ectty_free);
+
/** \endcond */
/*****************************************************************************/