Commit f34d7a5b authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

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: default avatarAlan Cox <alan@redhat.com>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
Cc: Jason Wessel <jason.wessel@windriver.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 251b8dd7
...@@ -210,21 +210,23 @@ static void do_softint(struct work_struct *private_) ...@@ -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) ...@@ -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;
......
...@@ -143,7 +143,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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)
......
...@@ -169,7 +169,7 @@ static int Fip_firmware_size; ...@@ -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 ) ...@@ -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) ...@@ -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 ) ...@@ -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 );
} }
......
...@@ -1140,28 +1140,29 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, ...@@ -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 */
......
...@@ -1230,7 +1230,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) ...@@ -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
......
...@@ -342,12 +342,10 @@ static int n_hdlc_tty_open (struct tty_struct *tty) ...@@ -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) ...@@ -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, ...@@ -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)
......
...@@ -376,8 +376,9 @@ static void put_char(struct r3964_info *pInfo, unsigned char ch) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -149,8 +149,8 @@ static void check_unthrottle(struct tty_struct *tty) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
} }
......
This diff is collapsed.
...@@ -40,6 +40,34 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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))
......
...@@ -46,7 +46,7 @@ struct serport { ...@@ -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)
......
...@@ -68,10 +68,10 @@ static int write_modem(struct cardstate *cs) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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)
......
...@@ -148,13 +148,13 @@ static void sp_xmit_on_air(unsigned long channel) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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++)
......
...@@ -516,7 +516,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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;
......
...@@ -64,7 +64,7 @@ static int irtty_chars_in_buffer(struct sir_dev *dev) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -158,6 +158,9 @@ ppp_asynctty_open(struct tty_struct *tty) ...@@ -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, ...@@ -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) ...@@ -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;
......
...@@ -207,6 +207,9 @@ ppp_sync_open(struct tty_struct *tty) ...@@ -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, ...@@ -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) ...@@ -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) {
......
...@@ -396,14 +396,14 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
This diff is collapsed.
...@@ -96,12 +96,14 @@ static void cleanup_kgdboc(void) ...@@ -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)
......
...@@ -532,15 +532,25 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -1421,8 +1421,7 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) ...@@ -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) {
......
...@@ -296,16 +296,14 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int ...@@ -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 ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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;
} }
......
...@@ -673,15 +673,13 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) ...@@ -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);
......
...@@ -1053,7 +1053,7 @@ static int vt_check(struct file *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;
......
...@@ -192,16 +192,14 @@ void proc_tty_register_driver(struct tty_driver *driver) ...@@ -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;
......
...@@ -177,9 +177,13 @@ struct signal_struct; ...@@ -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); ...@@ -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);
......
...@@ -12,11 +12,15 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 methods
* 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
const struct tty_operations *ops;
struct list_head tty_drivers; struct list_head tty_drivers;
}; };
......
...@@ -1272,8 +1272,8 @@ late_initcall(disable_boot_consoles); ...@@ -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;
} }
......
...@@ -555,10 +555,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment