tty: The big operations rework

- Operations are now a shared const function block as with most other Linux
  objects

- Introduce wrappers for some optional functions to get consistent behaviour

- Wrap put_char which used to be patched by the tty layer

- Document which functions are needed/optional

- Make put_char report success/fail

- Cache the driver->ops pointer in the tty as tty->ops

- Remove various surplus lock calls we no longer need

- Remove proc_write method as noted by Alexey Dobriyan

- Introduce some missing sanity checks where certain driver/ldisc
  combinations would oops as they didn't check needed methods were present

[akpm@linux-foundation.org: fix fs/compat_ioctl.c build]
[akpm@linux-foundation.org: fix isicom]
[akpm@linux-foundation.org: fix arch/ia64/hp/sim/simserial.c build]
[akpm@linux-foundation.org: fix kgdb]
Signed-off-by: Alan Cox <alan@redhat.com>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Alan Cox 2008-04-30 00:54:13 -07:00 committed by Linus Torvalds
parent 251b8dd7ee
commit f34d7a5b70
30 changed files with 539 additions and 666 deletions

View File

@ -210,21 +210,23 @@ static void do_softint(struct work_struct *private_)
printk(KERN_ERR "simserial: do_softint called\n"); printk(KERN_ERR "simserial: do_softint called\n");
} }
static void rs_put_char(struct tty_struct *tty, unsigned char ch) static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{ {
struct async_struct *info = (struct async_struct *)tty->driver_data; struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags; unsigned long flags;
if (!tty || !info->xmit.buf) return; if (!tty || !info->xmit.buf)
return 0;
local_irq_save(flags); local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
local_irq_restore(flags); local_irq_restore(flags);
return; return 0;
} }
info->xmit.buf[info->xmit.head] = ch; info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
local_irq_restore(flags); local_irq_restore(flags);
return 1;
} }
static void transmit_chars(struct async_struct *info, int *intr_done) static void transmit_chars(struct async_struct *info, int *intr_done)
@ -621,7 +623,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* the line discipline to only process XON/XOFF characters. * the line discipline to only process XON/XOFF characters.
*/ */
shutdown(info); shutdown(info);
if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); if (tty->ops->flush_buffer)
tty->ops->flush_buffer(tty);
if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
info->event = 0; info->event = 0;
info->tty = NULL; info->tty = NULL;

View File

@ -143,7 +143,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
int len; int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
len = tty->driver->write(tty, skb->data, skb->len); len = tty->ops->write(tty, skb->data, skb->len);
hdev->stat.byte_tx += len; hdev->stat.byte_tx += len;
skb_pull(skb, len); skb_pull(skb, len);
@ -190,8 +190,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Flush any pending characters in the driver and discipline. */ /* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
if (tty->driver && tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
hu->proto->flush(hu); hu->proto->flush(hu);
@ -285,9 +284,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ldisc.flush_buffer) if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty); tty->ldisc.flush_buffer(tty);
tty_driver_flush_buffer(tty);
if (tty->driver && tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
return 0; return 0;
} }
@ -374,8 +371,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
spin_unlock(&hu->rx_lock); spin_unlock(&hu->rx_lock);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver->unthrottle) tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
static int hci_uart_register_dev(struct hci_uart *hu) static int hci_uart_register_dev(struct hci_uart *hu)

View File

@ -169,7 +169,7 @@ static int Fip_firmware_size;
static int ip2_open(PTTY, struct file *); static int ip2_open(PTTY, struct file *);
static void ip2_close(PTTY, struct file *); static void ip2_close(PTTY, struct file *);
static int ip2_write(PTTY, const unsigned char *, int); static int ip2_write(PTTY, const unsigned char *, int);
static void ip2_putchar(PTTY, unsigned char); static int ip2_putchar(PTTY, unsigned char);
static void ip2_flush_chars(PTTY); static void ip2_flush_chars(PTTY);
static int ip2_write_room(PTTY); static int ip2_write_room(PTTY);
static int ip2_chars_in_buf(PTTY); static int ip2_chars_in_buf(PTTY);
@ -1616,10 +1616,9 @@ ip2_close( PTTY tty, struct file *pFile )
serviceOutgoingFifo ( pCh->pMyBord ); serviceOutgoingFifo ( pCh->pMyBord );
if ( tty->driver->flush_buffer ) if ( tty->driver->ops->flush_buffer )
tty->driver->flush_buffer(tty); tty->driver->ops->flush_buffer(tty);
if ( tty->ldisc.flush_buffer ) tty_ldisc_flush(tty);
tty->ldisc.flush_buffer(tty);
tty->closing = 0; tty->closing = 0;
pCh->pTTY = NULL; pCh->pTTY = NULL;
@ -1738,7 +1737,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
/* */ /* */
/* */ /* */
/******************************************************************************/ /******************************************************************************/
static void static int
ip2_putchar( PTTY tty, unsigned char ch ) ip2_putchar( PTTY tty, unsigned char ch )
{ {
i2ChanStrPtr pCh = tty->driver_data; i2ChanStrPtr pCh = tty->driver_data;
@ -1753,6 +1752,7 @@ ip2_putchar( PTTY tty, unsigned char ch )
ip2_flush_chars( tty ); ip2_flush_chars( tty );
} else } else
write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
return 1;
// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch ); // ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
} }

View File

@ -1140,28 +1140,29 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
} }
/* put_char et all */ /* put_char et all */
static void isicom_put_char(struct tty_struct *tty, unsigned char ch) static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
{ {
struct isi_port *port = tty->driver_data; struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card; struct isi_board *card = port->card;
unsigned long flags; unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
return; return 0;
if (!port->xmit_buf) if (!port->xmit_buf)
return; return 0;
spin_lock_irqsave(&card->card_lock, flags); spin_lock_irqsave(&card->card_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
goto out; spin_unlock_irqrestore(&card->card_lock, flags);
return 0;
}
port->xmit_buf[port->xmit_head++] = ch; port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= (SERIAL_XMIT_SIZE - 1); port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt++; port->xmit_cnt++;
spin_unlock_irqrestore(&card->card_lock, flags); spin_unlock_irqrestore(&card->card_lock, flags);
out: return 1;
return;
} }
/* flush_chars et all */ /* flush_chars et all */

View File

@ -1230,7 +1230,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (rep && if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) || (!vc_kbd_mode(kbd, VC_REPEAT) ||
(tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
/* /*
* Don't repeat a key if the input buffers are not empty and the * Don't repeat a key if the input buffers are not empty and the
* characters get aren't echoed locally. This makes key repeat * characters get aren't echoed locally. This makes key repeat

View File

@ -342,12 +342,10 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
#endif #endif
/* Flush any pending characters in the driver and discipline. */ /* Flush any pending characters in the driver and discipline. */
if (tty->ldisc.flush_buffer) if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer (tty); tty->ldisc.flush_buffer(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer (tty);
if (debuglevel >= DEBUG_LEVEL_INFO) if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__); printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
@ -399,7 +397,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* Send the next block of data to device */ /* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
actual = tty->driver->write(tty, tbuf->buf, tbuf->count); actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
/* rollback was possible and has been done */ /* rollback was possible and has been done */
if (actual == -ERESTARTSYS) { if (actual == -ERESTARTSYS) {
@ -752,8 +750,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
case TIOCOUTQ: case TIOCOUTQ:
/* get the pending tx byte count in the driver */ /* get the pending tx byte count in the driver */
count = tty->driver->chars_in_buffer ? count = tty_chars_in_buffer(tty);
tty->driver->chars_in_buffer(tty) : 0;
/* add size of next output frame in queue */ /* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags); spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
if (n_hdlc->tx_buf_list.head) if (n_hdlc->tx_buf_list.head)

View File

@ -376,8 +376,9 @@ static void put_char(struct r3964_info *pInfo, unsigned char ch)
if (tty == NULL) if (tty == NULL)
return; return;
if (tty->driver->put_char) { /* FIXME: put_char should not be called from an IRQ */
tty->driver->put_char(tty, ch); if (tty->ops->put_char) {
tty->ops->put_char(tty, ch);
} }
pInfo->bcc ^= ch; pInfo->bcc ^= ch;
} }
@ -386,12 +387,9 @@ static void flush(struct r3964_info *pInfo)
{ {
struct tty_struct *tty = pInfo->tty; struct tty_struct *tty = pInfo->tty;
if (tty == NULL) if (tty == NULL || tty->ops->flush_chars == NULL)
return; return;
tty->ops->flush_chars(tty);
if (tty->driver->flush_chars) {
tty->driver->flush_chars(tty);
}
} }
static void trigger_transmit(struct r3964_info *pInfo) static void trigger_transmit(struct r3964_info *pInfo)
@ -449,12 +447,11 @@ static void transmit_block(struct r3964_info *pInfo)
struct r3964_block_header *pBlock = pInfo->tx_first; struct r3964_block_header *pBlock = pInfo->tx_first;
int room = 0; int room = 0;
if ((tty == NULL) || (pBlock == NULL)) { if (tty == NULL || pBlock == NULL) {
return; return;
} }
if (tty->driver->write_room) room = tty_write_room(tty);
room = tty->driver->write_room(tty);
TRACE_PS("transmit_block %p, room %d, length %d", TRACE_PS("transmit_block %p, room %d, length %d",
pBlock, room, pBlock->length); pBlock, room, pBlock->length);

View File

@ -149,8 +149,8 @@ static void check_unthrottle(struct tty_struct *tty)
{ {
if (tty->count && if (tty->count &&
test_and_clear_bit(TTY_THROTTLED, &tty->flags) && test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver->unthrottle) tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
/** /**
@ -273,7 +273,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
{ {
int space, spaces; int space, spaces;
space = tty->driver->write_room(tty); space = tty_write_room(tty);
if (!space) if (!space)
return -1; return -1;
@ -286,7 +286,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
if (O_ONLCR(tty)) { if (O_ONLCR(tty)) {
if (space < 2) if (space < 2)
return -1; return -1;
tty->driver->put_char(tty, '\r'); tty_put_char(tty, '\r');
tty->column = 0; tty->column = 0;
} }
tty->canon_column = tty->column; tty->canon_column = tty->column;
@ -308,7 +308,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
if (space < spaces) if (space < spaces)
return -1; return -1;
tty->column += spaces; tty->column += spaces;
tty->driver->write(tty, " ", spaces); tty->ops->write(tty, " ", spaces);
return 0; return 0;
} }
tty->column += spaces; tty->column += spaces;
@ -325,7 +325,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
break; break;
} }
} }
tty->driver->put_char(tty, c); tty_put_char(tty, c);
unlock_kernel(); unlock_kernel();
return 0; return 0;
} }
@ -352,7 +352,7 @@ static ssize_t opost_block(struct tty_struct *tty,
int i; int i;
const unsigned char *cp; const unsigned char *cp;
space = tty->driver->write_room(tty); space = tty_write_room(tty);
if (!space) if (!space)
return 0; return 0;
if (nr > space) if (nr > space)
@ -390,27 +390,14 @@ static ssize_t opost_block(struct tty_struct *tty,
} }
} }
break_out: break_out:
if (tty->driver->flush_chars) if (tty->ops->flush_chars)
tty->driver->flush_chars(tty); tty->ops->flush_chars(tty);
i = tty->driver->write(tty, buf, i); i = tty->ops->write(tty, buf, i);
unlock_kernel(); unlock_kernel();
return i; return i;
} }
/**
* put_char - write character to driver
* @c: character (or part of unicode symbol)
* @tty: terminal device
*
* Queue a byte to the driver layer for output
*/
static inline void put_char(unsigned char c, struct tty_struct *tty)
{
tty->driver->put_char(tty, c);
}
/** /**
* echo_char - echo characters * echo_char - echo characters
* @c: unicode byte to echo * @c: unicode byte to echo
@ -423,8 +410,8 @@ static inline void put_char(unsigned char c, struct tty_struct *tty)
static void echo_char(unsigned char c, struct tty_struct *tty) static void echo_char(unsigned char c, struct tty_struct *tty)
{ {
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
put_char('^', tty); tty_put_char(tty, '^');
put_char(c ^ 0100, tty); tty_put_char(tty, c ^ 0100);
tty->column += 2; tty->column += 2;
} else } else
opost(c, tty); opost(c, tty);
@ -433,7 +420,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty)
static inline void finish_erasing(struct tty_struct *tty) static inline void finish_erasing(struct tty_struct *tty)
{ {
if (tty->erasing) { if (tty->erasing) {
put_char('/', tty); tty_put_char(tty, '/');
tty->column++; tty->column++;
tty->erasing = 0; tty->erasing = 0;
} }
@ -517,7 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) { if (L_ECHOPRT(tty)) {
if (!tty->erasing) { if (!tty->erasing) {
put_char('\\', tty); tty_put_char(tty, '\\');
tty->column++; tty->column++;
tty->erasing = 1; tty->erasing = 1;
} }
@ -525,7 +512,7 @@ static void eraser(unsigned char c, struct tty_struct *tty)
echo_char(c, tty); echo_char(c, tty);
while (--cnt > 0) { while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1); head = (head+1) & (N_TTY_BUF_SIZE-1);
put_char(tty->read_buf[head], tty); tty_put_char(tty, tty->read_buf[head]);
} }
} else if (kill_type == ERASE && !L_ECHOE(tty)) { } else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty); echo_char(ERASE_CHAR(tty), tty);
@ -553,22 +540,22 @@ static void eraser(unsigned char c, struct tty_struct *tty)
/* Now backup to that column. */ /* Now backup to that column. */
while (tty->column > col) { while (tty->column > col) {
/* Can't use opost here. */ /* Can't use opost here. */
put_char('\b', tty); tty_put_char(tty, '\b');
if (tty->column > 0) if (tty->column > 0)
tty->column--; tty->column--;
} }
} else { } else {
if (iscntrl(c) && L_ECHOCTL(tty)) { if (iscntrl(c) && L_ECHOCTL(tty)) {
put_char('\b', tty); tty_put_char(tty, '\b');
put_char(' ', tty); tty_put_char(tty, ' ');
put_char('\b', tty); tty_put_char(tty, '\b');
if (tty->column > 0) if (tty->column > 0)
tty->column--; tty->column--;
} }
if (!iscntrl(c) || L_ECHOCTL(tty)) { if (!iscntrl(c) || L_ECHOCTL(tty)) {
put_char('\b', tty); tty_put_char(tty, '\b');
put_char(' ', tty); tty_put_char(tty, ' ');
put_char('\b', tty); tty_put_char(tty, '\b');
if (tty->column > 0) if (tty->column > 0)
tty->column--; tty->column--;
} }
@ -599,8 +586,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
kill_pgrp(tty->pgrp, sig, 1); kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) { if (flush || !L_NOFLSH(tty)) {
n_tty_flush_buffer(tty); n_tty_flush_buffer(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
} }
} }
@ -732,7 +718,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
tty->lnext = 0; tty->lnext = 0;
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
put_char('\a', tty); /* beep if no space */ tty_put_char(tty, '\a'); /* beep if no space */
return; return;
} }
/* Record the column of first canon char. */ /* Record the column of first canon char. */
@ -776,8 +762,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
*/ */
if (!L_NOFLSH(tty)) { if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty); n_tty_flush_buffer(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
} }
if (L_ECHO(tty)) if (L_ECHO(tty))
echo_char(c, tty); echo_char(c, tty);
@ -806,8 +791,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
finish_erasing(tty); finish_erasing(tty);
if (L_ECHOCTL(tty)) { if (L_ECHOCTL(tty)) {
put_char('^', tty); tty_put_char(tty, '^');
put_char('\b', tty); tty_put_char(tty, '\b');
} }
} }
return; return;
@ -828,7 +813,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
if (c == '\n') { if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) { if (L_ECHO(tty) || L_ECHONL(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty); tty_put_char(tty, '\a');
opost('\n', tty); opost('\n', tty);
} }
goto handle_newline; goto handle_newline;
@ -846,7 +831,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
*/ */
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty); tty_put_char(tty, '\a');
/* Record the column of first canon char. */ /* Record the column of first canon char. */
if (tty->canon_head == tty->read_head) if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column; tty->canon_column = tty->column;
@ -876,7 +861,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
finish_erasing(tty); finish_erasing(tty);
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
put_char('\a', tty); /* beep if no space */ tty_put_char(tty, '\a'); /* beep if no space */
return; return;
} }
if (c == '\n') if (c == '\n')
@ -980,8 +965,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
break; break;
} }
} }
if (tty->driver->flush_chars) if (tty->ops->flush_chars)
tty->driver->flush_chars(tty); tty->ops->flush_chars(tty);
} }
n_tty_set_room(tty); n_tty_set_room(tty);
@ -1000,8 +985,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { if (tty->receive_room < TTY_THRESHOLD_THROTTLE) {
/* check TTY_THROTTLED first so it indicates our state */ /* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver->throttle) tty->ops->throttle)
tty->driver->throttle(tty); tty->ops->throttle(tty);
} }
} }
@ -1086,6 +1071,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
tty->real_raw = 0; tty->real_raw = 0;
} }
n_tty_set_room(tty); n_tty_set_room(tty);
/* The termios change make the tty ready for I/O */
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
} }
/** /**
@ -1513,11 +1501,11 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file,
break; break;
b++; nr--; b++; nr--;
} }
if (tty->driver->flush_chars) if (tty->ops->flush_chars)
tty->driver->flush_chars(tty); tty->ops->flush_chars(tty);
} else { } else {
while (nr > 0) { while (nr > 0) {
c = tty->driver->write(tty, b, nr); c = tty->ops->write(tty, b, nr);
if (c < 0) { if (c < 0) {
retval = c; retval = c;
goto break_out; goto break_out;
@ -1554,11 +1542,6 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file,
* *
* This code must be sure never to sleep through a hangup. * This code must be sure never to sleep through a hangup.
* Called without the kernel lock held - fine * Called without the kernel lock held - fine
*
* FIXME: if someone changes the VMIN or discipline settings for the
* terminal while another process is in poll() the poll does not
* recompute the new limits. Possibly set_termios should issue
* a read wakeup to fix this bug.
*/ */
static unsigned int normal_poll(struct tty_struct *tty, struct file *file, static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
@ -1582,9 +1565,9 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
else else
tty->minimum_to_wake = 1; tty->minimum_to_wake = 1;
} }
if (!tty_is_writelocked(tty) && if (tty->ops->write && !tty_is_writelocked(tty) &&
tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
tty->driver->write_room(tty) > 0) tty_write_room(tty) > 0)
mask |= POLLOUT | POLLWRNORM; mask |= POLLOUT | POLLWRNORM;
return mask; return mask;
} }

View File

@ -1108,8 +1108,8 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
a reference to the old ldisc. If we ended up flipping back a reference to the old ldisc. If we ended up flipping back
to the existing ldisc we have two references to it */ to the existing ldisc we have two references to it */
if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
tty->driver->set_ldisc(tty); tty->ops->set_ldisc(tty);
tty_ldisc_put(o_ldisc.num); tty_ldisc_put(o_ldisc.num);
@ -1181,9 +1181,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (*str == '\0') if (*str == '\0')
str = NULL; str = NULL;
if (tty_line >= 0 && tty_line <= p->num && p->poll_init && if (tty_line >= 0 && tty_line <= p->num && p->ops &&
!p->poll_init(p, tty_line, str)) { p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
res = p; res = p;
*line = tty_line; *line = tty_line;
break; break;
@ -1452,8 +1451,7 @@ static void do_tty_hangup(struct work_struct *work)
/* We may have no line discipline at this point */ /* We may have no line discipline at this point */
if (ld->flush_buffer) if (ld->flush_buffer)
ld->flush_buffer(tty); ld->flush_buffer(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->write_wakeup) ld->write_wakeup)
ld->write_wakeup(tty); ld->write_wakeup(tty);
@ -1516,11 +1514,11 @@ static void do_tty_hangup(struct work_struct *work)
* So we just call close() the right number of times. * So we just call close() the right number of times.
*/ */
if (cons_filp) { if (cons_filp) {
if (tty->driver->close) if (tty->ops->close)
for (n = 0; n < closecount; n++) for (n = 0; n < closecount; n++)
tty->driver->close(tty, cons_filp); tty->ops->close(tty, cons_filp);
} else if (tty->driver->hangup) } else if (tty->ops->hangup)
(tty->driver->hangup)(tty); (tty->ops->hangup)(tty);
/* /*
* We don't want to have driver/ldisc interactions beyond * We don't want to have driver/ldisc interactions beyond
* the ones we did here. The driver layer expects no * the ones we did here. The driver layer expects no
@ -1752,8 +1750,8 @@ void stop_tty(struct tty_struct *tty)
wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->read_wait);
} }
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (tty->driver->stop) if (tty->ops->stop)
(tty->driver->stop)(tty); (tty->ops->stop)(tty);
} }
EXPORT_SYMBOL(stop_tty); EXPORT_SYMBOL(stop_tty);
@ -1786,8 +1784,8 @@ void start_tty(struct tty_struct *tty)
wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->read_wait);
} }
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
if (tty->driver->start) if (tty->ops->start)
(tty->driver->start)(tty); (tty->ops->start)(tty);
/* If we have a running line discipline it may need kicking */ /* If we have a running line discipline it may need kicking */
tty_wakeup(tty); tty_wakeup(tty);
} }
@ -1972,10 +1970,13 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
tty = (struct tty_struct *)file->private_data; tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write")) if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO; return -EIO;
if (!tty || !tty->driver->write || if (!tty || !tty->ops->write ||
(test_bit(TTY_IO_ERROR, &tty->flags))) (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO; return -EIO;
/* Short term debug to catch buggy drivers */
if (tty->ops->write_room == NULL)
printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
tty->driver->name);
ld = tty_ldisc_ref_wait(tty); ld = tty_ldisc_ref_wait(tty);
if (!ld->write) if (!ld->write)
ret = -EIO; ret = -EIO;
@ -2122,6 +2123,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto fail_no_mem; goto fail_no_mem;
initialize_tty_struct(tty); initialize_tty_struct(tty);
tty->driver = driver; tty->driver = driver;
tty->ops = driver->ops;
tty->index = idx; tty->index = idx;
tty_line_name(driver, idx, tty->name); tty_line_name(driver, idx, tty->name);
@ -2152,6 +2154,7 @@ static int init_dev(struct tty_driver *driver, int idx,
goto free_mem_out; goto free_mem_out;
initialize_tty_struct(o_tty); initialize_tty_struct(o_tty);
o_tty->driver = driver->other; o_tty->driver = driver->other;
o_tty->ops = driver->ops;
o_tty->index = idx; o_tty->index = idx;
tty_line_name(driver->other, idx, o_tty->name); tty_line_name(driver->other, idx, o_tty->name);
@ -2456,8 +2459,8 @@ static void release_dev(struct file *filp)
} }
} }
#endif #endif
if (tty->driver->close) if (tty->ops->close)
tty->driver->close(tty, filp); tty->ops->close(tty, filp);
/* /*
* Sanity check: if tty->count is going to zero, there shouldn't be * Sanity check: if tty->count is going to zero, there shouldn't be
@ -2740,8 +2743,8 @@ static int tty_open(struct inode *inode, struct file *filp)
printk(KERN_DEBUG "opening %s...", tty->name); printk(KERN_DEBUG "opening %s...", tty->name);
#endif #endif
if (!retval) { if (!retval) {
if (tty->driver->open) if (tty->ops->open)
retval = tty->driver->open(tty, filp); retval = tty->ops->open(tty, filp);
else else
retval = -ENODEV; retval = -ENODEV;
} }
@ -2840,7 +2843,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
goto out1; goto out1;
check_tty_count(tty, "tty_open"); check_tty_count(tty, "tty_open");
retval = ptm_driver->open(tty, filp); retval = ptm_driver->ops->open(tty, filp);
if (!retval) if (!retval)
return 0; return 0;
out1: out1:
@ -3336,25 +3339,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
static int send_break(struct tty_struct *tty, unsigned int duration) static int send_break(struct tty_struct *tty, unsigned int duration)
{ {
int retval = -EINTR;
lock_kernel();
if (tty_write_lock(tty, 0) < 0) if (tty_write_lock(tty, 0) < 0)
goto out; return -EINTR;
tty->driver->break_ctl(tty, -1); tty->ops->break_ctl(tty, -1);
if (!signal_pending(current)) if (!signal_pending(current))
msleep_interruptible(duration); msleep_interruptible(duration);
tty->driver->break_ctl(tty, 0); tty->ops->break_ctl(tty, 0);
tty_write_unlock(tty); tty_write_unlock(tty);
if (!signal_pending(current)) if (!signal_pending(current))
retval = 0; return -EINTR;
out: return 0;
unlock_kernel();
return retval;
} }
/** /**
* tiocmget - get modem status * tty_tiocmget - get modem status
* @tty: tty device * @tty: tty device
* @file: user file pointer * @file: user file pointer
* @p: pointer to result * @p: pointer to result
@ -3369,10 +3367,8 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
{ {
int retval = -EINVAL; int retval = -EINVAL;
if (tty->driver->tiocmget) { if (tty->ops->tiocmget) {
lock_kernel(); retval = tty->ops->tiocmget(tty, file);
retval = tty->driver->tiocmget(tty, file);
unlock_kernel();
if (retval >= 0) if (retval >= 0)
retval = put_user(retval, p); retval = put_user(retval, p);
@ -3381,7 +3377,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p
} }
/** /**
* tiocmset - set modem status * tty_tiocmset - set modem status
* @tty: tty device * @tty: tty device
* @file: user file pointer * @file: user file pointer
* @cmd: command - clear bits, set bits or set all * @cmd: command - clear bits, set bits or set all
@ -3398,7 +3394,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
{ {
int retval = -EINVAL; int retval = -EINVAL;
if (tty->driver->tiocmset) { if (tty->ops->tiocmset) {
unsigned int set, clear, val; unsigned int set, clear, val;
retval = get_user(val, p); retval = get_user(val, p);
@ -3422,9 +3418,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
lock_kernel(); retval = tty->ops->tiocmset(tty, file, set, clear);
retval = tty->driver->tiocmset(tty, file, set, clear);
unlock_kernel();
} }
return retval; return retval;
} }
@ -3455,23 +3449,25 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EINVAL; retval = -EINVAL;
if (!tty->driver->break_ctl) { if (!tty->ops->break_ctl) {
switch (cmd) { switch (cmd) {
case TIOCSBRK: case TIOCSBRK:
case TIOCCBRK: case TIOCCBRK:
if (tty->driver->ioctl) if (tty->ops->ioctl)
retval = tty->driver->ioctl(tty, file, cmd, arg); retval = tty->ops->ioctl(tty, file, cmd, arg);
if (retval != -EINVAL && retval != -ENOIOCTLCMD)
printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
return retval; return retval;
/* These two ioctl's always return success; even if */ /* These two ioctl's always return success; even if */
/* the driver doesn't support them. */ /* the driver doesn't support them. */
case TCSBRK: case TCSBRK:
case TCSBRKP: case TCSBRKP:
if (!tty->driver->ioctl) if (!tty->ops->ioctl)
return 0; return 0;
lock_kernel(); retval = tty->ops->ioctl(tty, file, cmd, arg);
retval = tty->driver->ioctl(tty, file, cmd, arg); if (retval != -EINVAL && retval != -ENOIOCTLCMD)
unlock_kernel(); printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
if (retval == -ENOIOCTLCMD) if (retval == -ENOIOCTLCMD)
retval = 0; retval = 0;
return retval; return retval;
@ -3491,9 +3487,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (retval) if (retval)
return retval; return retval;
if (cmd != TIOCCBRK) { if (cmd != TIOCCBRK) {
lock_kernel();
tty_wait_until_sent(tty, 0); tty_wait_until_sent(tty, 0);
unlock_kernel();
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
} }
@ -3531,7 +3525,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID: case TIOCGSID:
return tiocgsid(tty, real_tty, p); return tiocgsid(tty, real_tty, p);
case TIOCGETD: case TIOCGETD:
/* FIXME: check this is ok */
return put_user(tty->ldisc.num, (int __user *)p); return put_user(tty->ldisc.num, (int __user *)p);
case TIOCSETD: case TIOCSETD:
return tiocsetd(tty, p); return tiocsetd(tty, p);
@ -3543,15 +3536,13 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* Break handling * Break handling
*/ */
case TIOCSBRK: /* Turn break on, unconditionally */ case TIOCSBRK: /* Turn break on, unconditionally */
lock_kernel(); if (tty->ops->break_ctl)
tty->driver->break_ctl(tty, -1); tty->ops->break_ctl(tty, -1);
unlock_kernel();
return 0; return 0;
case TIOCCBRK: /* Turn break off, unconditionally */ case TIOCCBRK: /* Turn break off, unconditionally */
lock_kernel(); if (tty->ops->break_ctl)
tty->driver->break_ctl(tty, 0); tty->ops->break_ctl(tty, 0);
unlock_kernel();
return 0; return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */ case TCSBRK: /* SVID version: non-zero arg --> no break */
/* non-zero arg means wait for all output data /* non-zero arg means wait for all output data
@ -3580,8 +3571,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} }
break; break;
} }
if (tty->driver->ioctl) { if (tty->ops->ioctl) {
retval = (tty->driver->ioctl)(tty, file, cmd, arg); retval = (tty->ops->ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD) if (retval != -ENOIOCTLCMD)
return retval; return retval;
} }
@ -3608,8 +3599,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
if (tty_paranoia_check(tty, inode, "tty_ioctl")) if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL; return -EINVAL;
if (tty->driver->compat_ioctl) { if (tty->ops->compat_ioctl) {
retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg); retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD) if (retval != -ENOIOCTLCMD)
return retval; return retval;
} }
@ -3659,8 +3650,7 @@ void __do_SAK(struct tty_struct *tty)
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
/* Kill the entire session */ /* Kill the entire session */
@ -3871,15 +3861,27 @@ static void initialize_tty_struct(struct tty_struct *tty)
INIT_WORK(&tty->SAK_work, do_SAK_work); INIT_WORK(&tty->SAK_work, do_SAK_work);
} }
/* /**
* The default put_char routine if the driver did not define one. * tty_put_char - write one character to a tty
* @tty: tty
* @ch: character
*
* Write one byte to the tty using the provided put_char method
* if present. Returns the number of characters successfully output.
*
* Note: the specific put_char operation in the driver layer may go
* away soon. Don't call it directly, use this method
*/ */
static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) int tty_put_char(struct tty_struct *tty, unsigned char ch)
{ {
tty->driver->write(tty, &ch, 1); if (tty->ops->put_char)
return tty->ops->put_char(tty, ch);
return tty->ops->write(tty, &ch, 1);
} }
EXPORT_SYMBOL_GPL(tty_put_char);
static struct class *tty_class; static struct class *tty_class;
/** /**
@ -3962,37 +3964,8 @@ void put_tty_driver(struct tty_driver *driver)
void tty_set_operations(struct tty_driver *driver, void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op) const struct tty_operations *op)
{ {
driver->open = op->open; driver->ops = op;
driver->close = op->close; };
driver->write = op->write;
driver->put_char = op->put_char;
driver->flush_chars = op->flush_chars;
driver->write_room = op->write_room;
driver->chars_in_buffer = op->chars_in_buffer;
driver->ioctl = op->ioctl;
driver->compat_ioctl = op->compat_ioctl;
driver->set_termios = op->set_termios;
driver->throttle = op->throttle;
driver->unthrottle = op->unthrottle;
driver->stop = op->stop;
driver->start = op->start;
driver->hangup = op->hangup;
driver->break_ctl = op->break_ctl;
driver->flush_buffer = op->flush_buffer;
driver->set_ldisc = op->set_ldisc;
driver->wait_until_sent = op->wait_until_sent;
driver->send_xchar = op->send_xchar;
driver->read_proc = op->read_proc;
driver->write_proc = op->write_proc;
driver->tiocmget = op->tiocmget;
driver->tiocmset = op->tiocmset;
#ifdef CONFIG_CONSOLE_POLL
driver->poll_init = op->poll_init;
driver->poll_get_char = op->poll_get_char;
driver->poll_put_char = op->poll_put_char;
#endif
}
EXPORT_SYMBOL(alloc_tty_driver); EXPORT_SYMBOL(alloc_tty_driver);
EXPORT_SYMBOL(put_tty_driver); EXPORT_SYMBOL(put_tty_driver);
@ -4055,9 +4028,6 @@ int tty_register_driver(struct tty_driver *driver)
return error; return error;
} }
if (!driver->put_char)
driver->put_char = tty_default_put_char;
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers); list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);

View File

@ -40,6 +40,34 @@
#define TERMIOS_OLD 8 #define TERMIOS_OLD 8
int tty_chars_in_buffer(struct tty_struct *tty)
{
if (tty->ops->chars_in_buffer)
return tty->ops->chars_in_buffer(tty);
else
return 0;
}
EXPORT_SYMBOL(tty_chars_in_buffer);
int tty_write_room(struct tty_struct *tty)
{
if (tty->ops->write_room)
return tty->ops->write_room(tty);
return 2048;
}
EXPORT_SYMBOL(tty_write_room);
void tty_driver_flush_buffer(struct tty_struct *tty)
{
if (tty->ops->flush_buffer)
tty->ops->flush_buffer(tty);
}
EXPORT_SYMBOL(tty_driver_flush_buffer);
/** /**
* tty_wait_until_sent - wait for I/O to finish * tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for * @tty: tty we are waiting for
@ -58,17 +86,13 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout)
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif #endif
if (!tty->driver->chars_in_buffer)
return;
if (!timeout) if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT; timeout = MAX_SCHEDULE_TIMEOUT;
lock_kernel();
if (wait_event_interruptible_timeout(tty->write_wait, if (wait_event_interruptible_timeout(tty->write_wait,
!tty->driver->chars_in_buffer(tty), timeout) >= 0) { !tty_chars_in_buffer(tty), timeout) >= 0) {
if (tty->driver->wait_until_sent) if (tty->ops->wait_until_sent)
tty->driver->wait_until_sent(tty, timeout); tty->ops->wait_until_sent(tty, timeout);
} }
unlock_kernel();
} }
EXPORT_SYMBOL(tty_wait_until_sent); EXPORT_SYMBOL(tty_wait_until_sent);
@ -444,8 +468,8 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
} }
} }
if (tty->driver->set_termios) if (tty->ops->set_termios)
(*tty->driver->set_termios)(tty, &old_termios); (*tty->ops->set_termios)(tty, &old_termios);
else else
tty_termios_copy_hw(tty->termios, &old_termios); tty_termios_copy_hw(tty->termios, &old_termios);
@ -748,8 +772,8 @@ static int send_prio_char(struct tty_struct *tty, char ch)
{ {
int was_stopped = tty->stopped; int was_stopped = tty->stopped;
if (tty->driver->send_xchar) { if (tty->ops->send_xchar) {
tty->driver->send_xchar(tty, ch); tty->ops->send_xchar(tty, ch);
return 0; return 0;
} }
@ -758,7 +782,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
if (was_stopped) if (was_stopped)
start_tty(tty); start_tty(tty);
tty->driver->write(tty, &ch, 1); tty->ops->write(tty, &ch, 1);
if (was_stopped) if (was_stopped)
stop_tty(tty); stop_tty(tty);
tty_write_unlock(tty); tty_write_unlock(tty);
@ -778,13 +802,14 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
{ {
int ret = 0; int ret = 0;
int bit = arg ? CLOCAL : 0; int bit = arg ? CLOCAL : 0;
struct ktermios old = *tty->termios; struct ktermios old;
mutex_lock(&tty->termios_mutex); mutex_lock(&tty->termios_mutex);
old = *tty->termios;
tty->termios->c_cflag &= ~CLOCAL; tty->termios->c_cflag &= ~CLOCAL;
tty->termios->c_cflag |= bit; tty->termios->c_cflag |= bit;
if (tty->driver->set_termios) if (tty->ops->set_termios)
tty->driver->set_termios(tty, &old); tty->ops->set_termios(tty, &old);
if ((tty->termios->c_cflag & CLOCAL) != bit) if ((tty->termios->c_cflag & CLOCAL) != bit)
ret = -EINVAL; ret = -EINVAL;
mutex_unlock(&tty->termios_mutex); mutex_unlock(&tty->termios_mutex);
@ -926,8 +951,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
ld->flush_buffer(tty); ld->flush_buffer(tty);
/* fall through */ /* fall through */
case TCOFLUSH: case TCOFLUSH:
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
break; break;
default: default:
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
@ -984,9 +1008,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file,
case TCFLSH: case TCFLSH:
return tty_perform_flush(tty, arg); return tty_perform_flush(tty, arg);
case TIOCOUTQ: case TIOCOUTQ:
return put_user(tty->driver->chars_in_buffer ? return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
tty->driver->chars_in_buffer(tty) : 0,
(int __user *) arg);
case TIOCINQ: case TIOCINQ:
retval = tty->read_cnt; retval = tty->read_cnt;
if (L_ICANON(tty)) if (L_ICANON(tty))

View File

@ -46,7 +46,7 @@ struct serport {
static int serport_serio_write(struct serio *serio, unsigned char data) static int serport_serio_write(struct serio *serio, unsigned char data)
{ {
struct serport *serport = serio->port_data; struct serport *serport = serio->port_data;
return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); return -(serport->tty->ops->write(serport->tty, &data, 1) != 1);
} }
static int serport_serio_open(struct serio *serio) static int serport_serio_open(struct serio *serio)

View File

@ -68,10 +68,10 @@ static int write_modem(struct cardstate *cs)
struct tty_struct *tty = cs->hw.ser->tty; struct tty_struct *tty = cs->hw.ser->tty;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct sk_buff *skb = bcs->tx_skb; struct sk_buff *skb = bcs->tx_skb;
int sent; int sent = -EOPNOTSUPP;
if (!tty || !tty->driver || !skb) if (!tty || !tty->driver || !skb)
return -EFAULT; return -EINVAL;
if (!skb->len) { if (!skb->len) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
@ -80,7 +80,8 @@ static int write_modem(struct cardstate *cs)
} }
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver->write(tty, skb->data, skb->len); if (tty->ops->write)
sent = tty->ops->write(tty, skb->data, skb->len);
gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent); gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
if (sent < 0) { if (sent < 0) {
/* error */ /* error */
@ -120,7 +121,7 @@ static int send_cb(struct cardstate *cs)
if (cb->len) { if (cb->len) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len); sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);
if (sent < 0) { if (sent < 0) {
/* error */ /* error */
gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent); gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
@ -440,14 +441,14 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsi
struct tty_struct *tty = cs->hw.ser->tty; struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear; unsigned int set, clear;
if (!tty || !tty->driver || !tty->driver->tiocmset) if (!tty || !tty->driver || !tty->ops->tiocmset)
return -EFAULT; return -EINVAL;
set = new_state & ~old_state; set = new_state & ~old_state;
clear = old_state & ~new_state; clear = old_state & ~new_state;
if (!set && !clear) if (!set && !clear)
return 0; return 0;
gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear); gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);
return tty->driver->tiocmset(tty, NULL, set, clear); return tty->ops->tiocmset(tty, NULL, set, clear);
} }
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)

View File

@ -148,13 +148,13 @@ static void sp_xmit_on_air(unsigned long channel)
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70; sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1; sp->tx_enable = 1;
actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual; sp->xleft -= actual;
sp->xhead += actual; sp->xhead += actual;
sp->led_state = 0x60; sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->status2 = 0; sp->status2 = 0;
} else } else
mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100); mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
@ -220,13 +220,13 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
*/ */
if (sp->duplex == 1) { if (sp->duplex == 1) {
sp->led_state = 0x70; sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1; sp->tx_enable = 1;
actual = sp->tty->driver->write(sp->tty, sp->xbuff, count); actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
sp->xleft = count - actual; sp->xleft = count - actual;
sp->xhead = sp->xbuff + actual; sp->xhead = sp->xbuff + actual;
sp->led_state = 0x60; sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} else { } else {
sp->xleft = count; sp->xleft = count;
sp->xhead = sp->xbuff; sp->xhead = sp->xbuff;
@ -444,7 +444,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
} }
if (sp->tx_enable) { if (sp->tx_enable) {
actual = tty->driver->write(tty, sp->xhead, sp->xleft); actual = tty->ops->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual; sp->xleft -= actual;
sp->xhead += actual; sp->xhead += actual;
} }
@ -492,8 +492,8 @@ static void sixpack_receive_buf(struct tty_struct *tty,
sp_put(sp); sp_put(sp);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver->unthrottle) && tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
/* /*
@ -554,8 +554,8 @@ static void resync_tnc(unsigned long channel)
/* resync the TNC */ /* resync the TNC */
sp->led_state = 0x60; sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tty->driver->write(sp->tty, &resync_cmd, 1); sp->tty->ops->write(sp->tty, &resync_cmd, 1);
/* Start resync timer again -- the TNC might be still absent */ /* Start resync timer again -- the TNC might be still absent */
@ -573,7 +573,7 @@ static inline int tnc_init(struct sixpack *sp)
tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP); tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
sp->tty->driver->write(sp->tty, &inbyte, 1); sp->tty->ops->write(sp->tty, &inbyte, 1);
del_timer(&sp->resync_t); del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp; sp->resync_t.data = (unsigned long) sp;
@ -601,6 +601,8 @@ static int sixpack_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
if (!dev) { if (!dev) {
@ -914,9 +916,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
} else { /* output watchdog char if idle */ } else { /* output watchdog char if idle */
if ((sp->status2 != 0) && (sp->duplex == 1)) { if ((sp->status2 != 0) && (sp->duplex == 1)) {
sp->led_state = 0x70; sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1; sp->tx_enable = 1;
actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual; sp->xleft -= actual;
sp->xhead += actual; sp->xhead += actual;
sp->led_state = 0x60; sp->led_state = 0x60;
@ -926,7 +928,7 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
} }
/* needed to trigger the TNC watchdog */ /* needed to trigger the TNC watchdog */
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
/* if the state byte has been received, the TNC is present, /* if the state byte has been received, the TNC is present,
so the resync timer can be reset. */ so the resync timer can be reset. */
@ -956,12 +958,12 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd)
if ((sp->status & SIXP_RX_DCD_MASK) == if ((sp->status & SIXP_RX_DCD_MASK) ==
SIXP_RX_DCD_MASK) { SIXP_RX_DCD_MASK) {
sp->led_state = 0x68; sp->led_state = 0x68;
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} }
} else { } else {
sp->led_state = 0x60; sp->led_state = 0x60;
/* fill trailing bytes with zeroes */ /* fill trailing bytes with zeroes */
sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tty->ops->write(sp->tty, &sp->led_state, 1);
rest = sp->rx_count; rest = sp->rx_count;
if (rest != 0) if (rest != 0)
for (i = rest; i <= 3; i++) for (i = rest; i <= 3; i++)

View File

@ -516,7 +516,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
spin_unlock_bh(&ax->buflock); spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
ax->stats.tx_packets++; ax->stats.tx_packets++;
ax->stats.tx_bytes += actual; ax->stats.tx_bytes += actual;
@ -546,7 +546,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
} }
printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
(ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ? (ax->tty->ops->chars_in_buffer(ax->tty) || ax->xleft) ?
"bad line quality" : "driver error"); "bad line quality" : "driver error");
ax->xleft = 0; ax->xleft = 0;
@ -736,6 +736,8 @@ static int mkiss_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
if (!dev) { if (!dev) {
@ -754,8 +756,7 @@ static int mkiss_open(struct tty_struct *tty)
tty->disc_data = ax; tty->disc_data = ax;
tty->receive_room = 65535; tty->receive_room = 65535;
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
/* Restore default settings */ /* Restore default settings */
dev->type = ARPHRD_AX25; dev->type = ARPHRD_AX25;
@ -936,8 +937,8 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
mkiss_put(ax); mkiss_put(ax);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver->unthrottle) && tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
/* /*
@ -962,7 +963,7 @@ static void mkiss_write_wakeup(struct tty_struct *tty)
goto out; goto out;
} }
actual = tty->driver->write(tty, ax->xhead, ax->xleft); actual = tty->ops->write(tty, ax->xhead, ax->xleft);
ax->xleft -= actual; ax->xleft -= actual;
ax->xhead += actual; ax->xhead += actual;

View File

@ -64,7 +64,7 @@ static int irtty_chars_in_buffer(struct sir_dev *dev)
IRDA_ASSERT(priv != NULL, return -1;); IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
return priv->tty->driver->chars_in_buffer(priv->tty); return tty_chars_in_buffer(priv->tty);
} }
/* Wait (sleep) until underlaying hardware finished transmission /* Wait (sleep) until underlaying hardware finished transmission
@ -93,10 +93,8 @@ static void irtty_wait_until_sent(struct sir_dev *dev)
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
tty = priv->tty; tty = priv->tty;
if (tty->driver->wait_until_sent) { if (tty->ops->wait_until_sent) {
lock_kernel(); tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));
unlock_kernel();
} }
else { else {
msleep(USBSERIAL_TX_DONE_DELAY); msleep(USBSERIAL_TX_DONE_DELAY);
@ -125,48 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
tty = priv->tty; tty = priv->tty;
lock_kernel(); mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios); old_termios = *(tty->termios);
cflag = tty->termios->c_cflag; cflag = tty->termios->c_cflag;
tty_encode_baud_rate(tty, speed, speed);
cflag &= ~CBAUD; if (tty->ops->set_termios)
tty->ops->set_termios(tty, &old_termios);
IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
switch (speed) {
case 1200:
cflag |= B1200;
break;
case 2400:
cflag |= B2400;
break;
case 4800:
cflag |= B4800;
break;
case 19200:
cflag |= B19200;
break;
case 38400:
cflag |= B38400;
break;
case 57600:
cflag |= B57600;
break;
case 115200:
cflag |= B115200;
break;
case 9600:
default:
cflag |= B9600;
break;
}
tty->termios->c_cflag = cflag;
if (tty->driver->set_termios)
tty->driver->set_termios(tty, &old_termios);
unlock_kernel();
priv->io.speed = speed; priv->io.speed = speed;
mutex_unlock(&tty->termios_mutex);
return 0; return 0;
} }
@ -202,8 +166,8 @@ static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
* This function is not yet defined for all tty driver, so * This function is not yet defined for all tty driver, so
* let's be careful... Jean II * let's be careful... Jean II
*/ */
IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;); IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
priv->tty->driver->tiocmset(priv->tty, NULL, set, clear); priv->tty->ops->tiocmset(priv->tty, NULL, set, clear);
return 0; return 0;
} }
@ -225,17 +189,13 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty; tty = priv->tty;
if (!tty->driver->write) if (!tty->ops->write)
return 0; return 0;
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
if (tty->driver->write_room) { writelen = tty_write_room(tty);
writelen = tty->driver->write_room(tty); if (writelen > len)
if (writelen > len)
writelen = len;
}
else
writelen = len; writelen = len;
return tty->driver->write(tty, ptr, writelen); return tty->ops->write(tty, ptr, writelen);
} }
/* ------------------------------------------------------- */ /* ------------------------------------------------------- */
@ -321,7 +281,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
struct ktermios old_termios; struct ktermios old_termios;
int cflag; int cflag;
lock_kernel(); mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios); old_termios = *(tty->termios);
cflag = tty->termios->c_cflag; cflag = tty->termios->c_cflag;
@ -331,9 +291,9 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
cflag |= CREAD; cflag |= CREAD;
tty->termios->c_cflag = cflag; tty->termios->c_cflag = cflag;
if (tty->driver->set_termios) if (tty->ops->set_termios)
tty->driver->set_termios(tty, &old_termios); tty->ops->set_termios(tty, &old_termios);
unlock_kernel(); mutex_unlock(&tty->termios_mutex);
} }
/*****************************************************************/ /*****************************************************************/
@ -359,8 +319,8 @@ static int irtty_start_dev(struct sir_dev *dev)
tty = priv->tty; tty = priv->tty;
if (tty->driver->start) if (tty->ops->start)
tty->driver->start(tty); tty->ops->start(tty);
/* Make sure we can receive more data */ /* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE); irtty_stop_receiver(tty, FALSE);
@ -388,8 +348,8 @@ static int irtty_stop_dev(struct sir_dev *dev)
/* Make sure we don't receive more data */ /* Make sure we don't receive more data */
irtty_stop_receiver(tty, TRUE); irtty_stop_receiver(tty, TRUE);
if (tty->driver->stop) if (tty->ops->stop)
tty->driver->stop(tty); tty->ops->stop(tty);
mutex_unlock(&irtty_mutex); mutex_unlock(&irtty_mutex);
@ -483,11 +443,10 @@ static int irtty_open(struct tty_struct *tty)
/* stop the underlying driver */ /* stop the underlying driver */
irtty_stop_receiver(tty, TRUE); irtty_stop_receiver(tty, TRUE);
if (tty->driver->stop) if (tty->ops->stop)
tty->driver->stop(tty); tty->ops->stop(tty);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
/* apply mtt override */ /* apply mtt override */
sir_tty_drv.qos_mtt_bits = qos_mtt_bits; sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
@ -564,8 +523,8 @@ static void irtty_close(struct tty_struct *tty)
/* Stop tty */ /* Stop tty */
irtty_stop_receiver(tty, TRUE); irtty_stop_receiver(tty, TRUE);
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
if (tty->driver->stop) if (tty->ops->stop)
tty->driver->stop(tty); tty->ops->stop(tty);
kfree(priv); kfree(priv);

View File

@ -158,6 +158,9 @@ ppp_asynctty_open(struct tty_struct *tty)
struct asyncppp *ap; struct asyncppp *ap;
int err; int err;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
err = -ENOMEM; err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL); ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap) if (!ap)
@ -359,8 +362,8 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk); tasklet_schedule(&ap->tsk);
ap_put(ap); ap_put(ap);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver->unthrottle) && tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
static void static void
@ -676,7 +679,7 @@ ppp_async_push(struct asyncppp *ap)
if (!tty_stuffed && ap->optr < ap->olim) { if (!tty_stuffed && ap->optr < ap->olim) {
avail = ap->olim - ap->optr; avail = ap->olim - ap->optr;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver->write(tty, ap->optr, avail); sent = tty->ops->write(tty, ap->optr, avail);
if (sent < 0) if (sent < 0)
goto flush; /* error, e.g. loss of CD */ goto flush; /* error, e.g. loss of CD */
ap->optr += sent; ap->optr += sent;

View File

@ -207,6 +207,9 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap; struct syncppp *ap;
int err; int err;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
ap = kzalloc(sizeof(*ap), GFP_KERNEL); ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM; err = -ENOMEM;
if (!ap) if (!ap)
@ -399,8 +402,8 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk); tasklet_schedule(&ap->tsk);
sp_put(ap); sp_put(ap);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver->unthrottle) && tty->ops->unthrottle)
tty->driver->unthrottle(tty); tty->ops->unthrottle(tty);
} }
static void static void
@ -653,7 +656,7 @@ ppp_sync_push(struct syncppp *ap)
tty_stuffed = 0; tty_stuffed = 0;
if (!tty_stuffed && ap->tpkt) { if (!tty_stuffed && ap->tpkt) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len); sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len);
if (sent < 0) if (sent < 0)
goto flush; /* error, e.g. loss of CD */ goto flush; /* error, e.g. loss of CD */
if (sent < ap->tpkt->len) { if (sent < ap->tpkt->len) {

View File

@ -396,14 +396,14 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
/* Order of next two lines is *very* important. /* Order of next two lines is *very* important.
* When we are sending a little amount of data, * When we are sending a little amount of data,
* the transfer may be completed inside driver.write() * the transfer may be completed inside the ops->write()
* routine, because it's running with interrupts enabled. * routine, because it's running with interrupts enabled.
* In this case we *never* got WRITE_WAKEUP event, * In this case we *never* got WRITE_WAKEUP event,
* if we did not request it before write operation. * if we did not request it before write operation.
* 14 Oct 1994 Dmitry Gorodchanin. * 14 Oct 1994 Dmitry Gorodchanin.
*/ */
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
actual = sl->tty->driver->write(sl->tty, sl->xbuff, count); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
#ifdef SL_CHECK_TRANSMIT #ifdef SL_CHECK_TRANSMIT
sl->dev->trans_start = jiffies; sl->dev->trans_start = jiffies;
#endif #endif
@ -437,7 +437,7 @@ static void slip_write_wakeup(struct tty_struct *tty)
return; return;
} }
actual = tty->driver->write(tty, sl->xhead, sl->xleft); actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual; sl->xleft -= actual;
sl->xhead += actual; sl->xhead += actual;
} }
@ -462,7 +462,7 @@ static void sl_tx_timeout(struct net_device *dev)
} }
printk(KERN_WARNING "%s: transmit timed out, %s?\n", printk(KERN_WARNING "%s: transmit timed out, %s?\n",
dev->name, dev->name,
(sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error"); "bad line quality" : "driver error");
sl->xleft = 0; sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@ -830,6 +830,9 @@ static int slip_open(struct tty_struct *tty)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
/* RTnetlink lock is misused here to serialize concurrent /* RTnetlink lock is misused here to serialize concurrent
opens of slip channels. There are better ways, but it is opens of slip channels. There are better ways, but it is
the simplest one. the simplest one.
@ -1432,7 +1435,7 @@ static void sl_outfill(unsigned long sls)
/* put END into tty queue. Is it right ??? */ /* put END into tty queue. Is it right ??? */
if (!netif_queue_stopped(sl->dev)) { if (!netif_queue_stopped(sl->dev)) {
/* if device busy no outfill */ /* if device busy no outfill */
sl->tty->driver->write(sl->tty, &s, 1); sl->tty->ops->write(sl->tty, &s, 1);
} }
} else } else
set_bit(SLF_OUTWAIT, &sl->flags); set_bit(SLF_OUTWAIT, &sl->flags);

View File

@ -17,7 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <linux/uaccess.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/mm.h> #include <linux/mm.h>
@ -95,7 +95,7 @@ static struct x25_asy *x25_asy_alloc(void)
x25_asy_devs[i] = dev; x25_asy_devs[i] = dev;
return sl; return sl;
} else { } else {
printk("x25_asy_alloc() - register_netdev() failure.\n"); printk(KERN_WARNING "x25_asy_alloc() - register_netdev() failure.\n");
free_netdev(dev); free_netdev(dev);
} }
} }
@ -112,23 +112,22 @@ static void x25_asy_free(struct x25_asy *sl)
kfree(sl->xbuff); kfree(sl->xbuff);
sl->xbuff = NULL; sl->xbuff = NULL;
if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { if (!test_and_clear_bit(SLF_INUSE, &sl->flags))
printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); printk(KERN_ERR "%s: x25_asy_free for already free unit.\n",
} sl->dev->name);
} }
static int x25_asy_change_mtu(struct net_device *dev, int newmtu) static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
{ {
struct x25_asy *sl = dev->priv; struct x25_asy *sl = dev->priv;
unsigned char *xbuff, *rbuff; unsigned char *xbuff, *rbuff;
int len = 2* newmtu; int len = 2 * newmtu;
xbuff = kmalloc(len + 4, GFP_ATOMIC); xbuff = kmalloc(len + 4, GFP_ATOMIC);
rbuff = kmalloc(len + 4, GFP_ATOMIC); rbuff = kmalloc(len + 4, GFP_ATOMIC);
if (xbuff == NULL || rbuff == NULL) if (xbuff == NULL || rbuff == NULL) {
{ printk(KERN_WARNING "%s: unable to grow X.25 buffers, MTU change cancelled.\n",
printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
dev->name); dev->name);
kfree(xbuff); kfree(xbuff);
kfree(rbuff); kfree(rbuff);
@ -193,25 +192,23 @@ static void x25_asy_bump(struct x25_asy *sl)
int err; int err;
count = sl->rcount; count = sl->rcount;
sl->stats.rx_bytes+=count; sl->stats.rx_bytes += count;
skb = dev_alloc_skb(count+1); skb = dev_alloc_skb(count+1);
if (skb == NULL) if (skb == NULL) {
{ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n",
printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); sl->dev->name);
sl->stats.rx_dropped++; sl->stats.rx_dropped++;
return; return;
} }
skb_push(skb,1); /* LAPB internal control */ skb_push(skb, 1); /* LAPB internal control */
memcpy(skb_put(skb,count), sl->rbuff, count); memcpy(skb_put(skb, count), sl->rbuff, count);
skb->protocol = x25_type_trans(skb, sl->dev); skb->protocol = x25_type_trans(skb, sl->dev);
if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK) err = lapb_data_received(skb->dev, skb);
{ if (err != LAPB_OK) {
kfree_skb(skb); kfree_skb(skb);
printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
} } else {
else
{
netif_rx(skb); netif_rx(skb);
sl->dev->last_rx = jiffies; sl->dev->last_rx = jiffies;
sl->stats.rx_packets++; sl->stats.rx_packets++;
@ -224,10 +221,11 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
unsigned char *p; unsigned char *p;
int actual, count, mtu = sl->dev->mtu; int actual, count, mtu = sl->dev->mtu;
if (len > mtu) if (len > mtu) {
{ /* Sigh, shouldn't occur BUT ... */ /* Sigh, shouldn't occur BUT ... */
len = mtu; len = mtu;
printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n",
sl->dev->name);
sl->stats.tx_dropped++; sl->stats.tx_dropped++;
x25_asy_unlock(sl); x25_asy_unlock(sl);
return; return;
@ -245,7 +243,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
* 14 Oct 1994 Dmitry Gorodchanin. * 14 Oct 1994 Dmitry Gorodchanin.
*/ */
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
actual = sl->tty->driver->write(sl->tty, sl->xbuff, count); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
sl->xleft = count - actual; sl->xleft = count - actual;
sl->xhead = sl->xbuff + actual; sl->xhead = sl->xbuff + actual;
/* VSV */ /* VSV */
@ -265,8 +263,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return; return;
if (sl->xleft <= 0) if (sl->xleft <= 0) {
{
/* Now serial buffer is almost free & we can start /* Now serial buffer is almost free & we can start
* transmission of another packet */ * transmission of another packet */
sl->stats.tx_packets++; sl->stats.tx_packets++;
@ -275,14 +272,14 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
return; return;
} }
actual = tty->driver->write(tty, sl->xhead, sl->xleft); actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual; sl->xleft -= actual;
sl->xhead += actual; sl->xhead += actual;
} }
static void x25_asy_timeout(struct net_device *dev) static void x25_asy_timeout(struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
spin_lock(&sl->lock); spin_lock(&sl->lock);
if (netif_queue_stopped(dev)) { if (netif_queue_stopped(dev)) {
@ -290,7 +287,7 @@ static void x25_asy_timeout(struct net_device *dev)
* 14 Oct 1994 Dmitry Gorodchanin. * 14 Oct 1994 Dmitry Gorodchanin.
*/ */
printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
(sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error"); "bad line quality" : "driver error");
sl->xleft = 0; sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@ -303,31 +300,34 @@ static void x25_asy_timeout(struct net_device *dev)
static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
int err; int err;
if (!netif_running(sl->dev)) { if (!netif_running(sl->dev)) {
printk("%s: xmit call when iface is down\n", dev->name); printk(KERN_ERR "%s: xmit call when iface is down\n",
dev->name);
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
switch(skb->data[0]) switch (skb->data[0]) {
{ case 0x00:
case 0x00:break; break;
case 0x01: /* Connection request .. do nothing */ case 0x01: /* Connection request .. do nothing */
if((err=lapb_connect_request(dev))!=LAPB_OK) err = lapb_connect_request(dev);
printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); if (err != LAPB_OK)
kfree_skb(skb); printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
return 0; kfree_skb(skb);
case 0x02: /* Disconnect request .. do nothing - hang up ?? */ return 0;
if((err=lapb_disconnect_request(dev))!=LAPB_OK) case 0x02: /* Disconnect request .. do nothing - hang up ?? */
printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); err = lapb_disconnect_request(dev);
default: if (err != LAPB_OK)
kfree_skb(skb); printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
return 0; default:
kfree_skb(skb);
return 0;
} }
skb_pull(skb,1); /* Remove control byte */ skb_pull(skb, 1); /* Remove control byte */
/* /*
* If we are busy already- too bad. We ought to be able * If we are busy already- too bad. We ought to be able
* to queue things at this point, to allow for a little * to queue things at this point, to allow for a little
@ -338,10 +338,10 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* So, no queues ! * So, no queues !
* 14 Oct 1994 Dmitry Gorodchanin. * 14 Oct 1994 Dmitry Gorodchanin.
*/ */
if((err=lapb_data_request(dev,skb))!=LAPB_OK) err = lapb_data_request(dev, skb);
{ if (err != LAPB_OK) {
printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
@ -357,7 +357,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
* Called when I frame data arrives. We did the work above - throw it * Called when I frame data arrives. We did the work above - throw it
* at the net layer. * at the net layer.
*/ */
static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
{ {
skb->dev->last_rx = jiffies; skb->dev->last_rx = jiffies;
@ -369,24 +369,22 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
* busy cases too well. Its tricky to see how to do this nicely - * busy cases too well. Its tricky to see how to do this nicely -
* perhaps lapb should allow us to bounce this ? * perhaps lapb should allow us to bounce this ?
*/ */
static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
{ {
struct x25_asy *sl=dev->priv; struct x25_asy *sl = dev->priv;
spin_lock(&sl->lock); spin_lock(&sl->lock);
if (netif_queue_stopped(sl->dev) || sl->tty == NULL) if (netif_queue_stopped(sl->dev) || sl->tty == NULL) {
{
spin_unlock(&sl->lock); spin_unlock(&sl->lock);
printk(KERN_ERR "x25_asy: tbusy drop\n"); printk(KERN_ERR "x25_asy: tbusy drop\n");
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
/* We were not busy, so we are now... :-) */ /* We were not busy, so we are now... :-) */
if (skb != NULL) if (skb != NULL) {
{
x25_asy_lock(sl); x25_asy_lock(sl);
sl->stats.tx_bytes+=skb->len; sl->stats.tx_bytes += skb->len;
x25_asy_encaps(sl, skb->data, skb->len); x25_asy_encaps(sl, skb->data, skb->len);
dev_kfree_skb(skb); dev_kfree_skb(skb);
} }
@ -396,15 +394,16 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
/* /*
* LAPB connection establish/down information. * LAPB connection establish/down information.
*/ */
static void x25_asy_connected(struct net_device *dev, int reason) static void x25_asy_connected(struct net_device *dev, int reason)
{ {
struct x25_asy *sl = dev->priv; struct x25_asy *sl = dev->priv;
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
if ((skb = dev_alloc_skb(1)) == NULL) { skb = dev_alloc_skb(1);
printk(KERN_ERR "lapbeth: out of memory\n"); if (skb == NULL) {
printk(KERN_ERR "x25_asy: out of memory\n");
return; return;
} }
@ -422,7 +421,8 @@ static void x25_asy_disconnected(struct net_device *dev, int reason)
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *ptr; unsigned char *ptr;
if ((skb = dev_alloc_skb(1)) == NULL) { skb = dev_alloc_skb(1);
if (skb == NULL) {
printk(KERN_ERR "x25_asy: out of memory\n"); printk(KERN_ERR "x25_asy: out of memory\n");
return; return;
} }
@ -449,7 +449,7 @@ static struct lapb_register_struct x25_asy_callbacks = {
/* Open the low-level part of the X.25 channel. Easy! */ /* Open the low-level part of the X.25 channel. Easy! */
static int x25_asy_open(struct net_device *dev) static int x25_asy_open(struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
unsigned long len; unsigned long len;
int err; int err;
@ -466,13 +466,11 @@ static int x25_asy_open(struct net_device *dev)
len = dev->mtu * 2; len = dev->mtu * 2;
sl->rbuff = kmalloc(len + 4, GFP_KERNEL); sl->rbuff = kmalloc(len + 4, GFP_KERNEL);
if (sl->rbuff == NULL) { if (sl->rbuff == NULL)
goto norbuff; goto norbuff;
}
sl->xbuff = kmalloc(len + 4, GFP_KERNEL); sl->xbuff = kmalloc(len + 4, GFP_KERNEL);
if (sl->xbuff == NULL) { if (sl->xbuff == NULL)
goto noxbuff; goto noxbuff;
}
sl->buffsize = len; sl->buffsize = len;
sl->rcount = 0; sl->rcount = 0;
@ -480,11 +478,12 @@ static int x25_asy_open(struct net_device *dev)
sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
netif_start_queue(dev); netif_start_queue(dev);
/* /*
* Now attach LAPB * Now attach LAPB
*/ */
if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK) err = lapb_register(dev, &x25_asy_callbacks);
if (err == LAPB_OK)
return 0; return 0;
/* Cleanup */ /* Cleanup */
@ -499,18 +498,20 @@ static int x25_asy_open(struct net_device *dev)
/* Close the low-level part of the X.25 channel. Easy! */ /* Close the low-level part of the X.25 channel. Easy! */
static int x25_asy_close(struct net_device *dev) static int x25_asy_close(struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
int err; int err;
spin_lock(&sl->lock); spin_lock(&sl->lock);
if (sl->tty) if (sl->tty)
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
netif_stop_queue(dev); netif_stop_queue(dev);
sl->rcount = 0; sl->rcount = 0;
sl->xleft = 0; sl->xleft = 0;
if((err=lapb_unregister(dev))!=LAPB_OK) err = lapb_unregister(dev);
printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); if (err != LAPB_OK)
printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
err);
spin_unlock(&sl->lock); spin_unlock(&sl->lock);
return 0; return 0;
} }
@ -521,8 +522,9 @@ static int x25_asy_close(struct net_device *dev)
* a block of X.25 data has been received, which can now be decapsulated * a block of X.25 data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing. * and sent on to some IP layer for further processing.
*/ */
static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) static void x25_asy_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{ {
struct x25_asy *sl = (struct x25_asy *) tty->disc_data; struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
@ -533,9 +535,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp,
/* Read the characters out of the buffer */ /* Read the characters out of the buffer */
while (count--) { while (count--) {
if (fp && *fp++) { if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->stats.rx_errors++; sl->stats.rx_errors++;
}
cp++; cp++;
continue; continue;
} }
@ -556,31 +557,31 @@ static int x25_asy_open_tty(struct tty_struct *tty)
struct x25_asy *sl = (struct x25_asy *) tty->disc_data; struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
int err; int err;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
/* First make sure we're not already connected. */ /* First make sure we're not already connected. */
if (sl && sl->magic == X25_ASY_MAGIC) { if (sl && sl->magic == X25_ASY_MAGIC)
return -EEXIST; return -EEXIST;
}
/* OK. Find a free X.25 channel to use. */ /* OK. Find a free X.25 channel to use. */
if ((sl = x25_asy_alloc()) == NULL) { sl = x25_asy_alloc();
if (sl == NULL)
return -ENFILE; return -ENFILE;
}
sl->tty = tty; sl->tty = tty;
tty->disc_data = sl; tty->disc_data = sl;
tty->receive_room = 65536; tty->receive_room = 65536;
if (tty->driver->flush_buffer) { tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
}
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
/* Restore default settings */ /* Restore default settings */
sl->dev->type = ARPHRD_X25; sl->dev->type = ARPHRD_X25;
/* Perform the low-level X.25 async init */
if ((err = x25_asy_open(sl->dev)))
return err;
/* Perform the low-level X.25 async init */
err = x25_asy_open(sl->dev);
if (err)
return err;
/* Done. We have linked the TTY line to a channel. */ /* Done. We have linked the TTY line to a channel. */
return sl->dev->base_addr; return sl->dev->base_addr;
} }
@ -601,9 +602,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
return; return;
if (sl->dev->flags & IFF_UP) if (sl->dev->flags & IFF_UP)
{ dev_close(sl->dev);
(void) dev_close(sl->dev);
}
tty->disc_data = NULL; tty->disc_data = NULL;
sl->tty = NULL; sl->tty = NULL;
@ -613,8 +612,7 @@ static void x25_asy_close_tty(struct tty_struct *tty)
static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
return &sl->stats; return &sl->stats;
} }
@ -641,21 +639,19 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
* character sequence, according to the X.25 protocol. * character sequence, according to the X.25 protocol.
*/ */
while (len-- > 0) while (len-- > 0) {
{ switch (c = *s++) {
switch(c = *s++) case X25_END:
{ *ptr++ = X25_ESC;
case X25_END: *ptr++ = X25_ESCAPE(X25_END);
*ptr++ = X25_ESC; break;
*ptr++ = X25_ESCAPE(X25_END); case X25_ESC:
break; *ptr++ = X25_ESC;
case X25_ESC: *ptr++ = X25_ESCAPE(X25_ESC);
*ptr++ = X25_ESC; break;
*ptr++ = X25_ESCAPE(X25_ESC); default:
break; *ptr++ = c;
default: break;
*ptr++ = c;
break;
} }
} }
*ptr++ = X25_END; *ptr++ = X25_END;
@ -665,31 +661,25 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len)
static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
{ {
switch(s) switch (s) {
{ case X25_END:
case X25_END: if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) && sl->rcount > 2)
{ x25_asy_bump(sl);
x25_asy_bump(sl); clear_bit(SLF_ESCAPE, &sl->flags);
} sl->rcount = 0;
clear_bit(SLF_ESCAPE, &sl->flags); return;
sl->rcount = 0; case X25_ESC:
return; set_bit(SLF_ESCAPE, &sl->flags);
return;
case X25_ESC: case X25_ESCAPE(X25_ESC):
set_bit(SLF_ESCAPE, &sl->flags); case X25_ESCAPE(X25_END):
return; if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
s = X25_UNESCAPE(s);
case X25_ESCAPE(X25_ESC): break;
case X25_ESCAPE(X25_END):
if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
s = X25_UNESCAPE(s);
break;
} }
if (!test_bit(SLF_ERROR, &sl->flags)) if (!test_bit(SLF_ERROR, &sl->flags)) {
{ if (sl->rcount < sl->buffsize) {
if (sl->rcount < sl->buffsize)
{
sl->rbuff[sl->rcount++] = s; sl->rbuff[sl->rcount++] = s;
return; return;
} }
@ -709,7 +699,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
if (!sl || sl->magic != X25_ASY_MAGIC) if (!sl || sl->magic != X25_ASY_MAGIC)
return -EINVAL; return -EINVAL;
switch(cmd) { switch (cmd) {
case SIOCGIFNAME: case SIOCGIFNAME:
if (copy_to_user((void __user *)arg, sl->dev->name, if (copy_to_user((void __user *)arg, sl->dev->name,
strlen(sl->dev->name) + 1)) strlen(sl->dev->name) + 1))
@ -724,8 +714,8 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
static int x25_asy_open_dev(struct net_device *dev) static int x25_asy_open_dev(struct net_device *dev)
{ {
struct x25_asy *sl = (struct x25_asy*)(dev->priv); struct x25_asy *sl = dev->priv;
if(sl->tty==NULL) if (sl->tty == NULL)
return -ENODEV; return -ENODEV;
return 0; return 0;
} }
@ -741,9 +731,9 @@ static void x25_asy_setup(struct net_device *dev)
set_bit(SLF_INUSE, &sl->flags); set_bit(SLF_INUSE, &sl->flags);
/* /*
* Finish setting up the DEVICE info. * Finish setting up the DEVICE info.
*/ */
dev->mtu = SL_MTU; dev->mtu = SL_MTU;
dev->hard_start_xmit = x25_asy_xmit; dev->hard_start_xmit = x25_asy_xmit;
dev->tx_timeout = x25_asy_timeout; dev->tx_timeout = x25_asy_timeout;
@ -778,9 +768,10 @@ static int __init init_x25_asy(void)
x25_asy_maxdev = 4; /* Sanity */ x25_asy_maxdev = 4; /* Sanity */
printk(KERN_INFO "X.25 async: version 0.00 ALPHA " printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
"(dynamic channels, max=%d).\n", x25_asy_maxdev ); "(dynamic channels, max=%d).\n", x25_asy_maxdev);
x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL); x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device *),
GFP_KERNEL);
if (!x25_asy_devs) { if (!x25_asy_devs) {
printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] " printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
"array! Uaargh! (-> No X.25 available)\n"); "array! Uaargh! (-> No X.25 available)\n");
@ -802,7 +793,7 @@ static void __exit exit_x25_asy(void)
struct x25_asy *sl = dev->priv; struct x25_asy *sl = dev->priv;
spin_lock_bh(&sl->lock); spin_lock_bh(&sl->lock);
if (sl->tty) if (sl->tty)
tty_hangup(sl->tty); tty_hangup(sl->tty);
spin_unlock_bh(&sl->lock); spin_unlock_bh(&sl->lock);

View File

@ -96,12 +96,14 @@ static void cleanup_kgdboc(void)
static int kgdboc_get_char(void) static int kgdboc_get_char(void)
{ {
return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line); return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
kgdb_tty_line);
} }
static void kgdboc_put_char(u8 chr) static void kgdboc_put_char(u8 chr)
{ {
kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
kgdb_tty_line, chr);
} }
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)

View File

@ -532,15 +532,25 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
static int uart_write_room(struct tty_struct *tty) static int uart_write_room(struct tty_struct *tty)
{ {
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
unsigned long flags;
int ret;
return uart_circ_chars_free(&state->info->xmit); spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_free(&state->info->xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
} }
static int uart_chars_in_buffer(struct tty_struct *tty) static int uart_chars_in_buffer(struct tty_struct *tty)
{ {
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
unsigned long flags;
int ret;
return uart_circ_chars_pending(&state->info->xmit); spin_lock_irqsave(&state->port->lock, flags);
ret = uart_circ_chars_pending(&state->info->xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
} }
static void uart_flush_buffer(struct tty_struct *tty) static void uart_flush_buffer(struct tty_struct *tty)
@ -622,6 +632,11 @@ static int uart_get_info(struct uart_state *state,
struct serial_struct tmp; struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
/* Ensure the state we copy is consistent and no hardware changes
occur as we go */
mutex_lock(&state->mutex);
tmp.type = port->type; tmp.type = port->type;
tmp.line = port->line; tmp.line = port->line;
tmp.port = port->iobase; tmp.port = port->iobase;
@ -641,6 +656,8 @@ static int uart_get_info(struct uart_state *state,
tmp.iomem_reg_shift = port->regshift; tmp.iomem_reg_shift = port->regshift;
tmp.iomem_base = (void *)(unsigned long)port->mapbase; tmp.iomem_base = (void *)(unsigned long)port->mapbase;
mutex_unlock(&state->mutex);
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;
return 0; return 0;
@ -918,14 +935,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port; struct uart_port *port = state->port;
lock_kernel();
mutex_lock(&state->mutex); mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN) if (port->type != PORT_UNKNOWN)
port->ops->break_ctl(port, break_state); port->ops->break_ctl(port, break_state);
mutex_unlock(&state->mutex); mutex_unlock(&state->mutex);
unlock_kernel();
} }
static int uart_do_autoconfig(struct uart_state *state) static int uart_do_autoconfig(struct uart_state *state)
@ -1074,7 +1089,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
int ret = -ENOIOCTLCMD; int ret = -ENOIOCTLCMD;
lock_kernel();
/* /*
* These ioctls don't rely on the hardware to be present. * These ioctls don't rely on the hardware to be present.
*/ */
@ -1144,10 +1158,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
break; break;
} }
} }
out_up: out_up:
mutex_unlock(&state->mutex); mutex_unlock(&state->mutex);
out: out:
unlock_kernel();
return ret; return ret;
} }
@ -1173,7 +1186,6 @@ static void uart_set_termios(struct tty_struct *tty,
return; return;
} }
lock_kernel();
uart_change_speed(state, old_termios); uart_change_speed(state, old_termios);
/* Handle transition to B0 status */ /* Handle transition to B0 status */
@ -1206,7 +1218,6 @@ static void uart_set_termios(struct tty_struct *tty,
} }
spin_unlock_irqrestore(&state->port->lock, flags); spin_unlock_irqrestore(&state->port->lock, flags);
} }
unlock_kernel();
#if 0 #if 0
/* /*
* No need to wake up processes in open wait, since they * No need to wake up processes in open wait, since they
@ -1322,11 +1333,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
struct uart_port *port = state->port; struct uart_port *port = state->port;
unsigned long char_time, expire; unsigned long char_time, expire;
BUG_ON(!kernel_locked());
if (port->type == PORT_UNKNOWN || port->fifosize == 0) if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return; return;
lock_kernel();
/* /*
* Set the check interval to be 1/5 of the estimated time to * Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check * send a single character, and make it at least 1. The check
@ -1372,6 +1383,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
break; break;
} }
set_current_state(TASK_RUNNING); /* might not be needed */ set_current_state(TASK_RUNNING); /* might not be needed */
unlock_kernel();
} }
/* /*
@ -2085,7 +2097,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
int ret; int ret;
uart_change_pm(state, 0); uart_change_pm(state, 0);
spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0); ops->set_mctrl(port, 0);
spin_unlock_irq(&port->lock);
ret = ops->startup(port); ret = ops->startup(port);
if (ret == 0) { if (ret == 0) {
uart_change_speed(state, NULL); uart_change_speed(state, NULL);

View File

@ -1421,8 +1421,7 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT); tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */ /* flush driver and line discipline buffers */
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
if (port->serial->dev) { if (port->serial->dev) {

View File

@ -296,16 +296,14 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV; int retval = -ENODEV;
if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit; goto exit;
dbg("%s - port %d, %d byte(s)", __func__, port->number, count); dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
if (!port->open_count) { /* open_count is managed under the mutex lock for the tty so cannot
retval = -EINVAL; drop to zero until after the last close completes */
dbg("%s - port not opened", __func__); WARN_ON(!port->open_count);
goto exit;
}
/* pass on to the driver specific version of this function */ /* pass on to the driver specific version of this function */
retval = port->serial->type->write(port, buf, count); retval = port->serial->type->write(port, buf, count);
@ -317,61 +315,28 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
static int serial_write_room (struct tty_struct *tty) static int serial_write_room (struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
if (!port)
goto exit;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
WARN_ON(!port->open_count);
if (!port->open_count) {
dbg("%s - port not open", __func__);
goto exit;
}
/* pass on to the driver specific version of this function */ /* pass on to the driver specific version of this function */
retval = port->serial->type->write_room(port); return port->serial->type->write_room(port);
exit:
return retval;
} }
static int serial_chars_in_buffer (struct tty_struct *tty) static int serial_chars_in_buffer (struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
if (!port)
goto exit;
dbg("%s = port %d", __func__, port->number); dbg("%s = port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
goto exit;
}
/* pass on to the driver specific version of this function */ /* pass on to the driver specific version of this function */
retval = port->serial->type->chars_in_buffer(port); return port->serial->type->chars_in_buffer(port);
exit:
return retval;
} }
static void serial_throttle (struct tty_struct * tty) static void serial_throttle (struct tty_struct * tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
if (!port)
return;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg ("%s - port not open", __func__);
return;
}
/* pass on to the driver specific version of this function */ /* pass on to the driver specific version of this function */
if (port->serial->type->throttle) if (port->serial->type->throttle)
port->serial->type->throttle(port); port->serial->type->throttle(port);
@ -380,17 +345,9 @@ static void serial_throttle (struct tty_struct * tty)
static void serial_unthrottle (struct tty_struct * tty) static void serial_unthrottle (struct tty_struct * tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
if (!port)
return;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
return;
}
/* pass on to the driver specific version of this function */ /* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle) if (port->serial->type->unthrottle)
port->serial->type->unthrottle(port); port->serial->type->unthrottle(port);
@ -401,42 +358,27 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV; int retval = -ENODEV;
lock_kernel();
if (!port)
goto exit;
dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
/* Caution - port->open_count is BKL protected */ WARN_ON(!port->open_count);
if (!port->open_count) {
dbg ("%s - port not open", __func__);
goto exit;
}
/* pass on to the driver specific version of this function if it is available */ /* pass on to the driver specific version of this function if it is available */
if (port->serial->type->ioctl) if (port->serial->type->ioctl) {
lock_kernel();
retval = port->serial->type->ioctl(port, file, cmd, arg); retval = port->serial->type->ioctl(port, file, cmd, arg);
unlock_kernel();
}
else else
retval = -ENOIOCTLCMD; retval = -ENOIOCTLCMD;
exit:
unlock_kernel();
return retval; return retval;
} }
static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
if (!port)
return;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
return;
}
/* pass on to the driver specific version of this function if it is available */ /* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios) if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old); port->serial->type->set_termios(port, old);
@ -448,24 +390,15 @@ static void serial_break (struct tty_struct *tty, int break_state)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
lock_kernel();
if (!port) {
unlock_kernel();
return;
}
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
unlock_kernel();
return;
}
/* pass on to the driver specific version of this function if it is available */ /* pass on to the driver specific version of this function if it is available */
if (port->serial->type->break_ctl) if (port->serial->type->break_ctl) {
lock_kernel();
port->serial->type->break_ctl(port, break_state); port->serial->type->break_ctl(port, break_state);
unlock_kernel(); unlock_kernel();
}
} }
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
@ -519,19 +452,11 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
if (!port)
return -ENODEV;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
return -ENODEV;
}
if (port->serial->type->tiocmget) if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file); return port->serial->type->tiocmget(port, file);
return -EINVAL; return -EINVAL;
} }
@ -540,19 +465,11 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file,
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
if (!port)
return -ENODEV;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
if (!port->open_count) { WARN_ON(!port->open_count);
dbg("%s - port not open", __func__);
return -ENODEV;
}
if (port->serial->type->tiocmset) if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear); return port->serial->type->tiocmset(port, file, set, clear);
return -EINVAL; return -EINVAL;
} }

View File

@ -673,15 +673,13 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
} }
*/ */
if (port->tty->driver->flush_buffer) tty_driver_flush_buffer(port->tty);
port->tty->driver->flush_buffer(port->tty);
tty_ldisc_flush(port->tty); tty_ldisc_flush(port->tty);
firm_report_tx_done(port); firm_report_tx_done(port);
firm_close(port); firm_close(port);
printk(KERN_ERR"Before processing rx_urbs_submitted.\n");
/* shutdown our bulk reads and writes */ /* shutdown our bulk reads and writes */
mutex_lock(&info->deathwarrant); mutex_lock(&info->deathwarrant);
spin_lock_irq(&info->lock); spin_lock_irq(&info->lock);

View File

@ -1053,7 +1053,7 @@ static int vt_check(struct file *file)
if (tty_paranoia_check(tty, inode, "tty_ioctl")) if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL; return -EINVAL;
if (tty->driver->ioctl != vt_ioctl) if (tty->ops->ioctl != vt_ioctl)
return -EINVAL; return -EINVAL;
vc = (struct vc_data *)tty->driver_data; vc = (struct vc_data *)tty->driver_data;

View File

@ -192,16 +192,14 @@ void proc_tty_register_driver(struct tty_driver *driver)
{ {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
if ((!driver->read_proc && !driver->write_proc) || if (!driver->ops->read_proc || !driver->driver_name ||
!driver->driver_name ||
driver->proc_entry) driver->proc_entry)
return; return;
ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver); ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver);
if (!ent) if (!ent)
return; return;
ent->read_proc = driver->read_proc; ent->read_proc = driver->ops->read_proc;
ent->write_proc = driver->write_proc;
ent->owner = driver->owner; ent->owner = driver->owner;
ent->data = driver; ent->data = driver;

View File

@ -177,9 +177,13 @@ struct signal_struct;
* size each time the window is created or resized anyway. * size each time the window is created or resized anyway.
* - TYT, 9/14/92 * - TYT, 9/14/92
*/ */
struct tty_operations;
struct tty_struct { struct tty_struct {
int magic; int magic;
struct tty_driver *driver; struct tty_driver *driver;
const struct tty_operations *ops;
int index; int index;
struct tty_ldisc ldisc; struct tty_ldisc ldisc;
struct mutex termios_mutex; struct mutex termios_mutex;
@ -295,6 +299,10 @@ extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen); int buflen);
extern void tty_write_message(struct tty_struct *tty, char *msg); extern void tty_write_message(struct tty_struct *tty, char *msg);
extern int tty_put_char(struct tty_struct *tty, unsigned char c);
extern int tty_chars_in_buffer(struct tty_struct *tty);
extern int tty_write_room(struct tty_struct *tty);
extern void tty_driver_flush_buffer(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void); extern int is_current_pgrp_orphaned(void);
extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern struct pid *tty_get_pgrp(struct tty_struct *tty);

View File

@ -12,11 +12,15 @@
* This routine is called when a particular tty device is opened. * This routine is called when a particular tty device is opened.
* This routine is mandatory; if this routine is not filled in, * This routine is mandatory; if this routine is not filled in,
* the attempted open will fail with ENODEV. * the attempted open will fail with ENODEV.
*
* Required method.
* *
* void (*close)(struct tty_struct * tty, struct file * filp); * void (*close)(struct tty_struct * tty, struct file * filp);
* *
* This routine is called when a particular tty device is closed. * This routine is called when a particular tty device is closed.
* *
* Required method.
*
* int (*write)(struct tty_struct * tty, * int (*write)(struct tty_struct * tty,
* const unsigned char *buf, int count); * const unsigned char *buf, int count);
* *
@ -26,7 +30,9 @@
* number of characters actually accepted for writing. This * number of characters actually accepted for writing. This
* routine is mandatory. * routine is mandatory.
* *
* void (*put_char)(struct tty_struct *tty, unsigned char ch); * Optional: Required for writable devices.
*
* int (*put_char)(struct tty_struct *tty, unsigned char ch);
* *
* This routine is called by the kernel to write a single * This routine is called by the kernel to write a single
* character to the tty device. If the kernel uses this routine, * character to the tty device. If the kernel uses this routine,
@ -34,10 +40,18 @@
* done stuffing characters into the driver. If there is no room * done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored. * in the queue, the character is ignored.
* *
* Optional: Kernel will use the write method if not provided.
*
* Note: Do not call this function directly, call tty_put_char
*
* void (*flush_chars)(struct tty_struct *tty); * void (*flush_chars)(struct tty_struct *tty);
* *
* This routine is called by the kernel after it has written a * This routine is called by the kernel after it has written a
* series of characters to the tty device using put_char(). * series of characters to the tty device using put_char().
*
* Optional:
*
* Note: Do not call this function directly, call tty_driver_flush_chars
* *
* int (*write_room)(struct tty_struct *tty); * int (*write_room)(struct tty_struct *tty);
* *
@ -45,6 +59,10 @@
* will accept for queuing to be written. This number is subject * will accept for queuing to be written. This number is subject
* to change as output buffers get emptied, or if the output flow * to change as output buffers get emptied, or if the output flow
* control is acted. * control is acted.
*
* Required if write method is provided else not needed.
*
* Note: Do not call this function directly, call tty_write_room
* *
* int (*ioctl)(struct tty_struct *tty, struct file * file, * int (*ioctl)(struct tty_struct *tty, struct file * file,
* unsigned int cmd, unsigned long arg); * unsigned int cmd, unsigned long arg);
@ -53,22 +71,29 @@
* device-specific ioctl's. If the ioctl number passed in cmd * device-specific ioctl's. If the ioctl number passed in cmd
* is not recognized by the driver, it should return ENOIOCTLCMD. * is not recognized by the driver, it should return ENOIOCTLCMD.
* *
* Optional
*
* long (*compat_ioctl)(struct tty_struct *tty, struct file * file, * long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
* unsigned int cmd, unsigned long arg); * unsigned int cmd, unsigned long arg);
* *
* implement ioctl processing for 32 bit process on 64 bit system * implement ioctl processing for 32 bit process on 64 bit system
*
* Optional
* *
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old); * void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
* *
* This routine allows the tty driver to be notified when * This routine allows the tty driver to be notified when
* device's termios settings have changed. Note that a * device's termios settings have changed.
* well-designed tty driver should be prepared to accept the case *
* where old == NULL, and try to do something rational. * Optional: Called under the termios lock
*
* *
* void (*set_ldisc)(struct tty_struct *tty); * void (*set_ldisc)(struct tty_struct *tty);
* *
* This routine allows the tty driver to be notified when the * This routine allows the tty driver to be notified when the
* device's termios settings have changed. * device's termios settings have changed.
*
* Optional: Called under BKL (currently)
* *
* void (*throttle)(struct tty_struct * tty); * void (*throttle)(struct tty_struct * tty);
* *
@ -86,17 +111,27 @@
* *
* This routine notifies the tty driver that it should stop * This routine notifies the tty driver that it should stop
* outputting characters to the tty device. * outputting characters to the tty device.
*
* Optional:
*
* Note: Call stop_tty not this method.
* *
* void (*start)(struct tty_struct *tty); * void (*start)(struct tty_struct *tty);
* *
* This routine notifies the tty driver that it resume sending * This routine notifies the tty driver that it resume sending
* characters to the tty device. * characters to the tty device.
*
* Optional:
*
* Note: Call start_tty not this method.
* *
* void (*hangup)(struct tty_struct *tty); * void (*hangup)(struct tty_struct *tty);
* *
* This routine notifies the tty driver that it should hangup the * This routine notifies the tty driver that it should hangup the
* tty device. * tty device.
* *
* Required:
*
* void (*break_ctl)(struct tty_stuct *tty, int state); * void (*break_ctl)(struct tty_stuct *tty, int state);
* *
* This optional routine requests the tty driver to turn on or * This optional routine requests the tty driver to turn on or
@ -106,18 +141,26 @@
* *
* If this routine is implemented, the high-level tty driver will * If this routine is implemented, the high-level tty driver will
* handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK, * handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK,
* TIOCCBRK. Otherwise, these ioctls will be passed down to the * TIOCCBRK.
* driver to handle. *
* Optional: Required for TCSBRK/BRKP/etc handling.
* *
* void (*wait_until_sent)(struct tty_struct *tty, int timeout); * void (*wait_until_sent)(struct tty_struct *tty, int timeout);
* *
* This routine waits until the device has written out all of the * This routine waits until the device has written out all of the
* characters in its transmitter FIFO. * characters in its transmitter FIFO.
* *
* Optional: If not provided the device is assumed to have no FIFO
*
* Note: Usually correct to call tty_wait_until_sent
*
* void (*send_xchar)(struct tty_struct *tty, char ch); * void (*send_xchar)(struct tty_struct *tty, char ch);
* *
* This routine is used to send a high-priority XON/XOFF * This routine is used to send a high-priority XON/XOFF
* character to the device. * character to the device.
*
* Optional: If not provided then the write method is called under
* the atomic write lock to keep it serialized with the ldisc.
*/ */
#include <linux/fs.h> #include <linux/fs.h>
@ -132,7 +175,7 @@ struct tty_operations {
void (*close)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp);
int (*write)(struct tty_struct * tty, int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count); const unsigned char *buf, int count);
void (*put_char)(struct tty_struct *tty, unsigned char ch); int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty); void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty); int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty); int (*chars_in_buffer)(struct tty_struct *tty);
@ -153,8 +196,6 @@ struct tty_operations {
void (*send_xchar)(struct tty_struct *tty, char ch); void (*send_xchar)(struct tty_struct *tty, char ch);
int (*read_proc)(char *page, char **start, off_t off, int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data); int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char __user *buffer,
unsigned long count, void *data);
int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file, int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
@ -190,48 +231,13 @@ struct tty_driver {
struct tty_struct **ttys; struct tty_struct **ttys;
struct ktermios **termios; struct ktermios **termios;
struct ktermios **termios_locked; struct ktermios **termios_locked;
void *driver_state; /* only used for the PTY driver */ void *driver_state;
/*
* Interface routines from the upper tty layer to the tty
* driver. Will be replaced with struct tty_operations.
*/
int (*open)(struct tty_struct * tty, struct file * filp);
void (*close)(struct tty_struct * tty, struct file * filp);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
void (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
void (*stop)(struct tty_struct *tty);
void (*start)(struct tty_struct *tty);
void (*hangup)(struct tty_struct *tty);
void (*break_ctl)(struct tty_struct *tty, int state);
void (*flush_buffer)(struct tty_struct *tty);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
int (*write_proc)(struct file *file, const char __user *buffer,
unsigned long count, void *data);
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line);
void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
/*
* Driver methods
*/
const struct tty_operations *ops;
struct list_head tty_drivers; struct list_head tty_drivers;
}; };

View File

@ -1272,8 +1272,8 @@ late_initcall(disable_boot_consoles);
*/ */
void tty_write_message(struct tty_struct *tty, char *msg) void tty_write_message(struct tty_struct *tty, char *msg)
{ {
if (tty && tty->driver->write) if (tty && tty->ops->write)
tty->driver->write(tty, msg, strlen(msg)); tty->ops->write(tty, msg, strlen(msg));
return; return;
} }

View File

@ -555,10 +555,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
ircomm_tty_shutdown(self); ircomm_tty_shutdown(self);
if (tty->driver->flush_buffer) tty_driver_flush_buffer(tty);
tty->driver->flush_buffer(tty); tty_ldisc_flush(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
tty->closing = 0; tty->closing = 0;
self->tty = NULL; self->tty = NULL;