*/
#undef ISDN_TTY_STAT_DEBUG
-#include <linux/config.h>
#include <linux/isdn.h>
+#include <linux/delay.h>
#include "isdn_common.h"
#include "isdn_tty.h"
#ifdef CONFIG_ISDN_AUDIO
/* Prototypes */
-static int isdn_tty_edit_at(const char *, int, modem_info *, int);
-static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *, int);
+static int isdn_tty_edit_at(const char *, int, modem_info *);
+static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
static void isdn_tty_modem_reset_regs(modem_info *, int);
static void isdn_tty_cmd_ATA(modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
int c;
int len;
struct tty_struct *tty;
+ char last;
if (info->online) {
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
- c = TTY_FLIPBUF_SIZE - tty->flip.count;
len = skb->len
#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif
;
+
+ c = tty_buffer_request_room(tty, len);
if (c >= len) {
#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb))
- while (skb->len--) {
- if (*skb->data == DLE)
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ int l = skb->len;
+ unsigned char *dp = skb->data;
+ while (--l) {
+ if (*dp == DLE)
tty_insert_flip_char(tty, DLE, 0);
- tty_insert_flip_char(tty, *skb->data++, 0);
+ tty_insert_flip_char(tty, *dp++, 0);
+ }
+ last = *dp;
} else {
#endif
- memcpy(tty->flip.char_buf_ptr,
- skb->data, len);
- tty->flip.count += len;
- tty->flip.char_buf_ptr += len;
- memset(tty->flip.flag_buf_ptr, 0, len);
- tty->flip.flag_buf_ptr += len;
+ if(len > 1)
+ tty_insert_flip_string(tty, skb->data, len - 1);
+ last = skb->data[len - 1];
#ifdef CONFIG_ISDN_AUDIO
}
#endif
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty->flip.flag_buf_ptr[len - 1] = 0xff;
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_insert_flip_char(tty, last, 0xFF);
+ else
+ tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_flip_buffer_push(tty);
kfree_skb(skb);
return 1;
}
int resched = 0;
int midx;
int i;
- int c;
int r;
struct tty_struct *tty;
modem_info *info;
#endif
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
- c = TTY_FLIPBUF_SIZE - tty->flip.count;
- if (c > 0) {
- r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
- tty->flip.char_buf_ptr,
- tty->flip.flag_buf_ptr, c, 0);
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- memset(tty->flip.flag_buf_ptr, 0, r);
- tty->flip.count += r;
- tty->flip.flag_buf_ptr += r;
- tty->flip.char_buf_ptr += r;
- if (r)
- schedule_delayed_work(&tty->flip.work, 1);
- }
+ /* CISCO AsyncPPP Hack */
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
+ else
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
+ if (r)
+ tty_flip_buffer_push(tty);
} else
r = 1;
} else
}
#endif
#endif
- /* Try to deliver directly via tty-flip-buf if queue is empty */
+ /* Try to deliver directly via tty-buf if queue is empty */
spin_lock_irqsave(&info->readlock, flags);
if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
if (isdn_tty_try_read(info, skb)) {
return 1;
}
-void
+static void
isdn_tty_cleanup_xmit(modem_info * info)
{
skb_queue_purge(&info->xmit_queue);
info->send_outstanding++;
info->msr &= ~UART_MSR_CTS;
info->lsr &= ~UART_LSR_TEMT;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
return;
}
if (slen < 0) {
* ^S or ^Q is sent.
*/
static int
-isdn_tty_end_vrx(const char *buf, int c, int from_user)
+isdn_tty_end_vrx(const char *buf, int c)
{
char ch;
while (c--) {
- if (from_user)
- get_user(ch, buf);
- else
- ch = *buf;
+ ch = *buf;
if ((ch != 0x11) && (ch != 0x13))
return 1;
buf++;
/* The next routine is called once from within timer-interrupt
* triggered within isdn_tty_modem_ncarrier(). It calls
* isdn_tty_modem_result() to stuff a "NO CARRIER" Message
- * into the tty's flip-buffer.
+ * into the tty's buffer.
*/
static void
isdn_tty_modem_do_ncarrier(unsigned long data)
/*
* return the usage calculated by si and layer 2 protocol
*/
-int
+static int
isdn_calc_usage(int si, int l2)
{
int usg = ISDN_USAGE_MODEM;
#endif
info->emu.vpar[4] = 0;
info->emu.vpar[5] = 8;
- if (info->dtmf_state) {
- kfree(info->dtmf_state);
- info->dtmf_state = NULL;
- }
- if (info->silence_state) {
- kfree(info->silence_state);
- info->silence_state = NULL;
- }
- if (info->adpcms) {
- kfree(info->adpcms);
- info->adpcms = NULL;
- }
- if (info->adpcmr) {
- kfree(info->adpcmr);
- info->adpcmr = NULL;
- }
+ kfree(info->dtmf_state);
+ info->dtmf_state = NULL;
+ kfree(info->silence_state);
+ info->silence_state = NULL;
+ kfree(info->adpcms);
+ info->adpcms = NULL;
+ kfree(info->adpcmr);
+ info->adpcmr = NULL;
#endif
if ((info->msr & UART_MSR_RI) &&
(info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
* - If dialing, abort dial.
*/
static int
-isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
+isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count)
{
int c;
int total = 0;
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
return 0;
- if (from_user)
- down(&info->write_sem);
/* See isdn_tty_senddown() */
atomic_inc(&info->xmit_lock);
while (1) {
#endif
isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
&(m->pluscount),
- &(m->lastplus),
- from_user);
- if (from_user)
- copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
- else
- memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+ &(m->lastplus));
+ memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline) {
int cc = isdn_tty_handleDLEdown(info, m, c);
/* If DLE decoding results in zero-transmit, but
* c originally was non-zero, do a wakeup.
*/
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
info->msr |= UART_MSR_CTS;
info->lsr |= UART_LSR_TEMT;
}
/* Do NOT handle Ctrl-Q or Ctrl-S
* when in full-duplex audio mode.
*/
- if (isdn_tty_end_vrx(buf, c, from_user)) {
+ if (isdn_tty_end_vrx(buf, c)) {
info->vonline &= ~1;
#ifdef ISDN_DEBUG_MODEM_VOICE
printk(KERN_DEBUG
isdn_tty_modem_result(RESULT_NO_CARRIER, info);
isdn_tty_modem_hup(info, 1);
} else
- c = isdn_tty_edit_at(buf, c, info, from_user);
+ c = isdn_tty_edit_at(buf, c, info);
}
buf += c;
count -= c;
total += c;
}
atomic_dec(&info->xmit_lock);
- if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
+ if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
isdn_tty_senddown(info);
isdn_tty_tint(info);
}
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
}
- if (from_user)
- up(&info->write_sem);
return total;
}
isdn_tty_cleanup_xmit(info);
info->xmit_count = 0;
wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
+ tty_wakeup(tty);
}
static void
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
return;
- if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
+ if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
}
* allows RS485 driver to be written in user space.
*/
static int
-isdn_tty_get_lsr_info(modem_info * info, uint * value)
+isdn_tty_get_lsr_info(modem_info * info, uint __user * value)
{
u_char status;
uint result;
status = info->lsr;
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, (uint *) value);
+ return put_user(result, value);
}
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
#endif
- return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
case TIOCSSOFTCAR:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
#endif
- if (get_user(arg, (ulong *) arg))
+ if (get_user(arg, (ulong __user *) arg))
return -EFAULT;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
#endif
- return isdn_tty_get_lsr_info(info, (uint *) arg);
+ return isdn_tty_get_lsr_info(info, (uint __user *) arg);
default:
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
}
static void
-isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
+isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
modem_info *info = (modem_info *) tty->driver_data;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
#endif
+ module_put(info->owner);
return;
}
info->flags |= ISDN_ASYNC_CLOSING;
*/
timeout = jiffies + HZ;
while (!(info->lsr & UART_LSR_TEMT)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(20);
+ schedule_timeout_interruptible(20);
if (time_after(jiffies,timeout))
break;
}
}
dev->modempoll--;
isdn_tty_shutdown(info);
+
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- info->tty = 0;
+ tty_ldisc_flush(tty);
+ info->tty = NULL;
info->ncarrier = 0;
tty->closing = 0;
module_put(info->owner);
if (info->blocked_open) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/2);
+ msleep_interruptible(500);
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
isdn_tty_shutdown(info);
info->count = 0;
info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
- info->tty = 0;
+ info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
send_sig(SIGIO, dev->profd, 1);
}
-static struct tty_operations modem_ops = {
+static const struct tty_operations modem_ops = {
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
if (!m->tty_modem)
return -ENOMEM;
m->tty_modem->name = "ttyI";
- m->tty_modem->devfs_name = "isdn/ttyI";
m->tty_modem->major = ISDN_TTY_MAJOR;
m->tty_modem->minor_start = 0;
m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);
isdn_tty_modem_reset_regs(info, 1);
info->magic = ISDN_ASYNC_MAGIC;
info->line = i;
- info->tty = 0;
+ info->tty = NULL;
info->x_char = 0;
info->count = 0;
info->blocked_open = 0;
char *p;
char c;
u_long flags;
- struct sk_buff *skb = 0;
- char *sp = 0;
+ struct sk_buff *skb = NULL;
+ char *sp = NULL;
+ int l;
if (!msg) {
printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
return;
}
+
+ l = strlen(msg);
+
spin_lock_irqsave(&info->readlock, flags);
tty = info->tty;
if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
return;
}
- /* use queue instead of direct flip, if online and */
- /* data is in queue or flip buffer is full */
- if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
- (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) {
- skb = alloc_skb(strlen(msg), GFP_ATOMIC);
+ /* use queue instead of direct, if online and */
+ /* data is in queue or buffer is full */
+ if (info->online && ((tty_buffer_request_room(tty, l) < l) ||
+ !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
+ skb = alloc_skb(l, GFP_ATOMIC);
if (!skb) {
spin_unlock_irqrestore(&info->readlock, flags);
return;
}
- sp = skb_put(skb, strlen(msg));
+ sp = skb_put(skb, l);
#ifdef CONFIG_ISDN_AUDIO
ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
ISDN_AUDIO_SKB_LOCK(skb) = 0;
if (skb) {
*sp++ = c;
} else {
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ if(tty_insert_flip_char(tty, c, TTY_NORMAL) == 0)
break;
- tty_insert_flip_char(tty, c, 0);
}
}
if (skb) {
dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
spin_unlock_irqrestore(&info->readlock, flags);
/* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
+ if (dev->modempoll && info->rcvsched)
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
} else {
spin_unlock_irqrestore(&info->readlock, flags);
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_flip_buffer_push(tty);
}
}
*/
static void
isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
- u_long *lastplus, int from_user)
+ u_long *lastplus)
{
- char cbuf[3];
-
if (plus > 127)
return;
if (count > 3) {
count = 3;
*pluscount = 0;
}
- if (from_user) {
- copy_from_user(cbuf, p, count);
- p = cbuf;
- }
while (count > 0) {
if (*(p++) == plus) {
if ((*pluscount)++) {
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
return;
}
- if (info->tty->ldisc.flush_buffer)
- info->tty->ldisc.flush_buffer(info->tty);
+ tty_ldisc_flush(info->tty);
if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
(!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
(info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
p[0]++;
i = 0;
while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
- (i < ISDN_LMSNLEN))
+ (i < ISDN_LMSNLEN - 1))
m->lmsn[i++] = *p[0]++;
m->lmsn[i] = '\0';
break;
* p inputbuffer
* count length of buffer
* channel index to line (minor-device)
- * user flag: buffer is in userspace
*/
static int
-isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
+isdn_tty_edit_at(const char *p, int count, modem_info * info)
{
atemu *m = &info->emu;
int total = 0;
int cnt;
for (cnt = count; cnt > 0; p++, cnt--) {
- if (user)
- get_user(c, p);
- else
- c = *p;
+ c = *p;
total++;
if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
/* Separator (CR or LF) */