diff --git a/include/ectty.h b/include/ectty.h new file mode 100644 index 0000000000000000000000000000000000000000..3bf34b49a8c0b49bca0dfe9535ae23f29f6f3a01 --- /dev/null +++ b/include/ectty.h @@ -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 diff --git a/tty/module.c b/tty/module.c index ac9c73ad4d59d6b5dd90ec910d950e8cdb53fa33..e2036d0e52aafdaf6a50d1b2b2be90bfe4ceab75 100644 --- a/tty/module.c +++ b/tty/module.c @@ -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" +#include "../include/ectty.h" /*****************************************************************************/ -int __init ec_tty_init_module(void); -void __exit ec_tty_cleanup_module(void); +#define EC_TTY_MAX_DEVICES 10 + +/*****************************************************************************/ -unsigned int debug_level = 0; 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_DESCRIPTION("EtherCAT TTY driver module"); 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 @@ static struct ktermios ec_tty_std_termios = { .c_cc = INIT_C_CC, }; -/** \endcond */ +struct ec_tty { + int minor; + struct device *dev; +}; /*****************************************************************************/ @@ -92,11 +101,17 @@ static struct ktermios ec_tty_std_termios = { */ 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 @@ int __init ec_tty_init_module(void) 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 @@ out_return: */ 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 @@ void __exit ec_tty_cleanup_module(void) /*****************************************************************************/ +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 @@ static int ec_tty_write( 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 @@ static int ec_tty_write( module_init(ec_tty_init_module); module_exit(ec_tty_cleanup_module); +EXPORT_SYMBOL(ectty_create); +EXPORT_SYMBOL(ectty_free); + /** \endcond */ /*****************************************************************************/