Passing tty cflag to serial implementation.
This commit is contained in:
parent
f6c0de7723
commit
a98da94149
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/termios.h>
|
||||||
|
|
||||||
#include "../../include/ecrt.h" // EtherCAT realtime interface
|
#include "../../include/ecrt.h" // EtherCAT realtime interface
|
||||||
#include "../../include/ectty.h" // EtherCAT TTY interface
|
#include "../../include/ectty.h" // EtherCAT TTY interface
|
||||||
|
|
@ -200,12 +201,45 @@ ec_sync_info_t el6002_syncs[] = {
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
int el6002_cflag_changed(void *data, unsigned short cflag)
|
||||||
|
{
|
||||||
|
el6002_t *ser = (el6002_t *) data;
|
||||||
|
int cs = 0, stop, par;
|
||||||
|
|
||||||
|
printk(KERN_INFO PFX "%s(data=%p, cflag=%x).\n", __func__, ser, cflag);
|
||||||
|
|
||||||
|
switch (cflag & CSIZE) {
|
||||||
|
case CS7:
|
||||||
|
cs = 7;
|
||||||
|
break;
|
||||||
|
case CS8:
|
||||||
|
cs = 8;
|
||||||
|
break;
|
||||||
|
default: /* CS5 or CS6 */
|
||||||
|
return -EINVAL; // not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = (cflag & CSTOPB) ? 2 : 1;
|
||||||
|
|
||||||
|
if (cflag & PARENB) {
|
||||||
|
par = (cflag & PARODD) ? 1 : 2;
|
||||||
|
} else {
|
||||||
|
par = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(KERN_INFO PFX "CS%u stopb=%u par=%i.\n", cs, stop, par);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
int el6002_init(el6002_t *ser, ec_master_t *master, u16 position,
|
int el6002_init(el6002_t *ser, ec_master_t *master, u16 position,
|
||||||
ec_domain_t *domain)
|
ec_domain_t *domain)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ser->tty = ectty_create();
|
ser->tty = ectty_create(el6002_cflag_changed, ser);
|
||||||
if (IS_ERR(ser->tty)) {
|
if (IS_ERR(ser->tty)) {
|
||||||
printk(KERN_ERR PFX "Failed to create tty.\n");
|
printk(KERN_ERR PFX "Failed to create tty.\n");
|
||||||
ret = PTR_ERR(ser->tty);
|
ret = PTR_ERR(ser->tty);
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,19 @@ typedef struct ec_tty ec_tty_t; /**< \see ec_tty */
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/** Create a virtual TTY interface.
|
/** Create a virtual TTY interface.
|
||||||
*
|
*
|
||||||
|
* \param cflag_cb This callback function is called when the serial settings
|
||||||
|
* shall be changed. The \a cb_data argument is the same as the \a cb_data
|
||||||
|
* given on device creation, while the \a cflag argument contains the new
|
||||||
|
* settings.
|
||||||
|
* \param cb_data Arbitrary data to pass to callbacks.
|
||||||
|
*
|
||||||
* \return Pointer to the interface object, otherwise an ERR_PTR value.
|
* \return Pointer to the interface object, otherwise an ERR_PTR value.
|
||||||
*/
|
*/
|
||||||
ec_tty_t *ectty_create(void);
|
ec_tty_t *ectty_create(
|
||||||
|
int (*cflag_cb)(void *cb_data, unsigned short cflag),
|
||||||
|
void *cb_data
|
||||||
|
);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* TTY interface methods
|
* TTY interface methods
|
||||||
|
|
|
||||||
82
tty/module.c
82
tty/module.c
|
|
@ -107,6 +107,9 @@ struct ec_tty {
|
||||||
|
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
|
|
||||||
|
int (*cflag_cb)(void *, unsigned short);
|
||||||
|
void *cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct tty_operations ec_tty_ops; // see below
|
static const struct tty_operations ec_tty_ops; // see below
|
||||||
|
|
@ -242,10 +245,10 @@ void ec_tty_wakeup(unsigned long data)
|
||||||
unsigned char *cbuf;
|
unsigned char *cbuf;
|
||||||
int space = tty_prepare_flip_string(tty->tty, &cbuf, to_recv);
|
int space = tty_prepare_flip_string(tty->tty, &cbuf, to_recv);
|
||||||
|
|
||||||
if (space < to_recv) {
|
if (space < to_recv) {
|
||||||
printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
|
printk(KERN_WARNING PFX "Insufficient space to_recv=%d space=%d\n",
|
||||||
to_recv, space);
|
to_recv, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (space < 0) {
|
if (space < 0) {
|
||||||
to_recv = 0;
|
to_recv = 0;
|
||||||
|
|
@ -266,7 +269,7 @@ void ec_tty_wakeup(unsigned long data)
|
||||||
}
|
}
|
||||||
tty_flip_buffer_push(tty->tty);
|
tty_flip_buffer_push(tty->tty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tty->timer.expires += 1;
|
tty->timer.expires += 1;
|
||||||
add_timer(&tty->timer);
|
add_timer(&tty->timer);
|
||||||
|
|
@ -274,7 +277,8 @@ void ec_tty_wakeup(unsigned long data)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
int ec_tty_init(ec_tty_t *tty, int minor)
|
int ec_tty_init(ec_tty_t *tty, int minor,
|
||||||
|
int (*cflag_cb)(void *, unsigned short), void *cb_data)
|
||||||
{
|
{
|
||||||
tty->minor = minor;
|
tty->minor = minor;
|
||||||
tty->tx_read_idx = 0;
|
tty->tx_read_idx = 0;
|
||||||
|
|
@ -284,6 +288,8 @@ int ec_tty_init(ec_tty_t *tty, int minor)
|
||||||
tty->rx_write_idx = 0;
|
tty->rx_write_idx = 0;
|
||||||
init_timer(&tty->timer);
|
init_timer(&tty->timer);
|
||||||
tty->tty = NULL;
|
tty->tty = NULL;
|
||||||
|
tty->cflag_cb = cflag_cb;
|
||||||
|
tty->cb_data = cb_data;
|
||||||
|
|
||||||
tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
|
tty->dev = tty_register_device(tty_driver, tty->minor, NULL);
|
||||||
if (IS_ERR(tty->dev)) {
|
if (IS_ERR(tty->dev)) {
|
||||||
|
|
@ -310,17 +316,17 @@ void ec_tty_clear(ec_tty_t *tty)
|
||||||
|
|
||||||
int ec_tty_get_serial_info(ec_tty_t *tty, struct serial_struct *data)
|
int ec_tty_get_serial_info(ec_tty_t *tty, struct serial_struct *data)
|
||||||
{
|
{
|
||||||
struct serial_struct tmp;
|
struct serial_struct tmp;
|
||||||
|
|
||||||
if (!data)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
if (!data)
|
||||||
|
return -EFAULT;
|
||||||
if (copy_to_user(data, &tmp, sizeof(*data))) {
|
|
||||||
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
|
|
||||||
|
if (copy_to_user(data, &tmp, sizeof(*data))) {
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
@ -336,8 +342,8 @@ static int ec_tty_open(struct tty_struct *tty, struct file *file)
|
||||||
printk(KERN_INFO PFX "Opening line %i.\n", line);
|
printk(KERN_INFO PFX "Opening line %i.\n", line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
|
if (line < 0 || line >= EC_TTY_MAX_DEVICES) {
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
t = ttys[line];
|
t = ttys[line];
|
||||||
|
|
@ -474,7 +480,7 @@ static void ec_tty_flush_buffer(struct tty_struct *tty)
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
|
static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
ec_tty_t *t = (ec_tty_t *) tty->driver_data;
|
ec_tty_t *t = (ec_tty_t *) tty->driver_data;
|
||||||
int ret = -ENOTTY;
|
int ret = -ENOTTY;
|
||||||
|
|
@ -487,8 +493,8 @@ static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TIOCGSERIAL:
|
case TIOCGSERIAL:
|
||||||
if (access_ok(VERIFY_WRITE,
|
if (access_ok(VERIFY_WRITE,
|
||||||
(void *) arg, sizeof(struct serial_struct))) {
|
(void *) arg, sizeof(struct serial_struct))) {
|
||||||
ret = ec_tty_get_serial_info(t, (struct serial_struct *) arg);
|
ret = ec_tty_get_serial_info(t, (struct serial_struct *) arg);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -513,9 +519,10 @@ static int ec_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void ec_tty_set_termios(struct tty_struct *tty,
|
static void ec_tty_set_termios(struct tty_struct *tty,
|
||||||
struct ktermios *old_termios)
|
struct ktermios *old_termios)
|
||||||
{
|
{
|
||||||
//ec_tty_t *t = (ec_tty_t *) tty->driver_data;
|
ec_tty_t *t = (ec_tty_t *) tty->driver_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
#if EC_TTY_DEBUG >= 2
|
#if EC_TTY_DEBUG >= 2
|
||||||
printk(KERN_INFO PFX "%s().\n", __func__);
|
printk(KERN_INFO PFX "%s().\n", __func__);
|
||||||
|
|
@ -528,6 +535,13 @@ static void ec_tty_set_termios(struct tty_struct *tty,
|
||||||
printk(KERN_INFO "cflag changed from %x to %x.\n",
|
printk(KERN_INFO "cflag changed from %x to %x.\n",
|
||||||
old_termios->c_cflag, tty->termios->c_cflag);
|
old_termios->c_cflag, tty->termios->c_cflag);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ret = t->cflag_cb(t->cb_data, tty->termios->c_cflag);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_ERR PFX "ERROR: cflag 0x%x not accepted.\n",
|
||||||
|
tty->termios->c_cflag);
|
||||||
|
tty->termios->c_cflag = old_termios->c_cflag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
@ -598,25 +612,25 @@ static const struct tty_operations ec_tty_ops = {
|
||||||
.open = ec_tty_open,
|
.open = ec_tty_open,
|
||||||
.close = ec_tty_close,
|
.close = ec_tty_close,
|
||||||
.write = ec_tty_write,
|
.write = ec_tty_write,
|
||||||
.put_char = ec_tty_put_char,
|
.put_char = ec_tty_put_char,
|
||||||
.write_room = ec_tty_write_room,
|
.write_room = ec_tty_write_room,
|
||||||
.chars_in_buffer = ec_tty_chars_in_buffer,
|
.chars_in_buffer = ec_tty_chars_in_buffer,
|
||||||
.flush_buffer = ec_tty_flush_buffer,
|
.flush_buffer = ec_tty_flush_buffer,
|
||||||
.ioctl = ec_tty_ioctl,
|
.ioctl = ec_tty_ioctl,
|
||||||
.set_termios = ec_tty_set_termios,
|
.set_termios = ec_tty_set_termios,
|
||||||
.stop = ec_tty_stop,
|
.stop = ec_tty_stop,
|
||||||
.start = ec_tty_start,
|
.start = ec_tty_start,
|
||||||
.hangup = ec_tty_hangup,
|
.hangup = ec_tty_hangup,
|
||||||
.break_ctl = ec_tty_break,
|
.break_ctl = ec_tty_break,
|
||||||
.send_xchar = ec_tty_send_xchar,
|
.send_xchar = ec_tty_send_xchar,
|
||||||
.wait_until_sent = ec_tty_wait_until_sent,
|
.wait_until_sent = ec_tty_wait_until_sent,
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Public functions and methods
|
* Public functions and methods
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
ec_tty_t *ectty_create(void)
|
ec_tty_t *ectty_create(int (*cflag_cb)(void *, unsigned short), void *cb_data)
|
||||||
{
|
{
|
||||||
ec_tty_t *tty;
|
ec_tty_t *tty;
|
||||||
int minor, ret;
|
int minor, ret;
|
||||||
|
|
@ -636,7 +650,7 @@ ec_tty_t *ectty_create(void)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ec_tty_init(tty, minor);
|
ret = ec_tty_init(tty, minor, cflag_cb, cb_data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
up(&tty_sem);
|
up(&tty_sem);
|
||||||
kfree(tty);
|
kfree(tty);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue