diff options
Diffstat (limited to 'drivers/staging/dgnc/dgnc_tty.c')
-rw-r--r-- | drivers/staging/dgnc/dgnc_tty.c | 362 |
1 files changed, 130 insertions, 232 deletions
diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c index 953d931..1e10c0f 100644 --- a/drivers/staging/dgnc/dgnc_tty.c +++ b/drivers/staging/dgnc/dgnc_tty.c @@ -13,13 +13,9 @@ * PURPOSE. See the GNU General Public License for more details. */ -/************************************************************************ - * +/* * This file implements the tty driver functionality for the * Neo and ClassicBoard PCI based product lines. - * - ************************************************************************ - * */ #include <linux/kernel.h> @@ -39,27 +35,20 @@ #include "dgnc_tty.h" #include "dgnc_neo.h" #include "dgnc_cls.h" -#include "dgnc_sysfs.h" #include "dgnc_utils.h" -/* - * internal variables - */ -static unsigned char *dgnc_TmpWriteBuf; - -/* - * Default transparent print information. - */ -static struct digi_t dgnc_digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string ] */ - .digi_offstr = "\033[4i", /* ANSI printer off string ] */ - .digi_term = "ansi" /* default terminal type */ +/* Default transparent print information. */ + +static const struct digi_t dgnc_digi_init = { + .digi_flags = DIGI_COOK, /* Flags */ + .digi_maxcps = 100, /* Max CPS */ + .digi_maxchar = 50, /* Max chars in print queue */ + .digi_bufsize = 100, /* Printer buffer size */ + .digi_onlen = 4, /* size of printer on string */ + .digi_offlen = 4, /* size of printer off string */ + .digi_onstr = "\033[5i", /* ANSI printer on string ] */ + .digi_offstr = "\033[4i", /* ANSI printer off string ] */ + .digi_term = "ansi" /* default terminal type */ }; /* @@ -69,7 +58,7 @@ static struct digi_t dgnc_digi_init = { * This defines a raw port at 9600 baud, 8 data bits, no parity, * 1 stop bit. */ -static struct ktermios DgncDefaultTermios = { +static struct ktermios default_termios = { .c_iflag = (DEFAULT_IFLAGS), /* iflags */ .c_oflag = (DEFAULT_OFLAGS), /* oflags */ .c_cflag = (DEFAULT_CFLAGS), /* cflags */ @@ -113,6 +102,8 @@ static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf, static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios); static void dgnc_tty_send_xchar(struct tty_struct *tty, char ch); +static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char line); +static void dgnc_wake_up_unit(struct un_t *unit); static const struct tty_operations dgnc_tty_ops = { .open = dgnc_tty_open, @@ -137,36 +128,7 @@ static const struct tty_operations dgnc_tty_ops = { .send_xchar = dgnc_tty_send_xchar }; -/************************************************************************ - * - * TTY Initialization/Cleanup Functions - * - ************************************************************************/ - -/* - * dgnc_tty_preinit() - * - * Initialize any global tty related data before we download any boards. - */ -int dgnc_tty_preinit(void) -{ - /* - * Allocate a buffer for doing the copy from user space to - * kernel space in dgnc_write(). We only use one buffer and - * control access to it with a semaphore. If we are paging, we - * are already in trouble so one buffer won't hurt much anyway. - * - * We are okay to sleep in the malloc, as this routine - * is only called during module load, (not in interrupt context), - * and with no locks held. - */ - dgnc_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_KERNEL); - - if (!dgnc_TmpWriteBuf) - return -ENOMEM; - - return 0; -} +/* TTY Initialization/Cleanup Functions */ /* * dgnc_tty_register() @@ -194,7 +156,7 @@ int dgnc_tty_register(struct dgnc_board *brd) brd->serial_driver->minor_start = 0; brd->serial_driver->type = TTY_DRIVER_TYPE_SERIAL; brd->serial_driver->subtype = SERIAL_TYPE_NORMAL; - brd->serial_driver->init_termios = DgncDefaultTermios; + brd->serial_driver->init_termios = default_termios; brd->serial_driver->driver_name = DRVSTR; /* @@ -233,7 +195,7 @@ int dgnc_tty_register(struct dgnc_board *brd) brd->print_driver->minor_start = 0x80; brd->print_driver->type = TTY_DRIVER_TYPE_SERIAL; brd->print_driver->subtype = SERIAL_TYPE_NORMAL; - brd->print_driver->init_termios = DgncDefaultTermios; + brd->print_driver->init_termios = default_termios; brd->print_driver->driver_name = DRVSTR; /* @@ -285,9 +247,7 @@ int dgnc_tty_init(struct dgnc_board *brd) if (!brd) return -ENXIO; - /* - * Initialize board structure elements. - */ + /* Initialize board structure elements. */ vaddr = brd->re_map_membase; @@ -345,12 +305,10 @@ int dgnc_tty_init(struct dgnc_board *brd) classp = tty_register_device(brd->serial_driver, i, &ch->ch_bd->pdev->dev); ch->ch_tun.un_sysfs = classp; - dgnc_create_tty_sysfs(&ch->ch_tun, classp); classp = tty_register_device(brd->print_driver, i, &ch->ch_bd->pdev->dev); ch->ch_pun.un_sysfs = classp; - dgnc_create_tty_sysfs(&ch->ch_pun, classp); } } @@ -365,17 +323,6 @@ err_free_channels: } /* - * dgnc_tty_post_uninit() - * - * UnInitialize any global tty related data. - */ -void dgnc_tty_post_uninit(void) -{ - kfree(dgnc_TmpWriteBuf); - dgnc_TmpWriteBuf = NULL; -} - -/* * dgnc_cleanup_tty() * * Uninitialize the TTY portion of this driver. Free all memory and @@ -385,20 +332,14 @@ void dgnc_cleanup_tty(struct dgnc_board *brd) { int i = 0; - for (i = 0; i < brd->nasync; i++) { - if (brd->channels[i]) - dgnc_remove_tty_sysfs(brd->channels[i]-> - ch_tun.un_sysfs); + for (i = 0; i < brd->nasync; i++) tty_unregister_device(brd->serial_driver, i); - } + tty_unregister_driver(brd->serial_driver); - for (i = 0; i < brd->nasync; i++) { - if (brd->channels[i]) - dgnc_remove_tty_sysfs(brd->channels[i]-> - ch_pun.un_sysfs); + for (i = 0; i < brd->nasync; i++) tty_unregister_device(brd->print_driver, i); - } + tty_unregister_driver(brd->print_driver); put_tty_driver(brd->serial_driver); @@ -437,9 +378,7 @@ static void dgnc_wmove(struct channel_t *ch, char *buf, uint n) } if (n > 0) { - /* - * Move rest of data. - */ + /* Move rest of data. */ remain = n; memcpy(ch->ch_wqueue + head, buf, remain); head += remain; @@ -509,9 +448,8 @@ void dgnc_input(struct channel_t *ch) goto exit_unlock; } - /* - * If we are throttled, simply don't read any data. - */ + /* If we are throttled, simply don't read any data. */ + if (ch->ch_flags & CH_FORCED_STOPI) goto exit_unlock; @@ -624,10 +562,10 @@ exit_unlock: tty_ldisc_deref(ld); } -/************************************************************************ +/* * Determines when CARRIER changes state and takes appropriate * action. - ************************************************************************/ + */ void dgnc_carrier(struct channel_t *ch) { int virt_carrier = 0; @@ -645,28 +583,24 @@ void dgnc_carrier(struct channel_t *ch) if (ch->ch_c_cflag & CLOCAL) virt_carrier = 1; - /* - * Test for a VIRTUAL carrier transition to HIGH. - */ + /* Test for a VIRTUAL carrier transition to HIGH. */ + if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { /* * When carrier rises, wake any threads waiting * for carrier in the open routine. */ - if (waitqueue_active(&ch->ch_flags_wait)) wake_up_interruptible(&ch->ch_flags_wait); } - /* - * Test for a PHYSICAL carrier transition to HIGH. - */ + /* Test for a PHYSICAL carrier transition to HIGH. */ + if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { /* * When carrier rises, wake any threads waiting * for carrier in the open routine. */ - if (waitqueue_active(&ch->ch_flags_wait)) wake_up_interruptible(&ch->ch_flags_wait); } @@ -704,9 +638,8 @@ void dgnc_carrier(struct channel_t *ch) tty_hangup(ch->ch_pun.un_tty); } - /* - * Make sure that our cached values reflect the current reality. - */ + /* Make sure that our cached values reflect the current reality. */ + if (virt_carrier == 1) ch->ch_flags |= CH_FCAR; else @@ -718,9 +651,8 @@ void dgnc_carrier(struct channel_t *ch) ch->ch_flags &= ~CH_CD; } -/* - * Assign the custom baud rate to the channel structure - */ +/* Assign the custom baud rate to the channel structure */ + static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate) { int testdiv; @@ -854,6 +786,12 @@ void dgnc_check_queue_flow_control(struct channel_t *ch) } } +static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char sig) +{ + ch->ch_mostat &= ~(sig); + ch->ch_bd->bd_ops->assert_modem_signals(ch); +} + void dgnc_wakeup_writes(struct channel_t *ch) { int qlen = 0; @@ -864,9 +802,8 @@ void dgnc_wakeup_writes(struct channel_t *ch) spin_lock_irqsave(&ch->ch_lock, flags); - /* - * If channel now has space, wake up anyone waiting on the condition. - */ + /* If channel now has space, wake up anyone waiting on the condition. */ + qlen = ch->ch_w_head - ch->ch_w_tail; if (qlen < 0) qlen += WQUEUESIZE; @@ -892,19 +829,15 @@ void dgnc_wakeup_writes(struct channel_t *ch) * If RTS Toggle mode is on, whenever * the queue and UART is empty, keep RTS low. */ - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) { - ch->ch_mostat &= ~(UART_MCR_RTS); - ch->ch_bd->bd_ops->assert_modem_signals(ch); - } + if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) + dgnc_set_signal_low(ch, UART_MCR_RTS); /* * If DTR Toggle mode is on, whenever * the queue and UART is empty, keep DTR low. */ - if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) { - ch->ch_mostat &= ~(UART_MCR_DTR); - ch->ch_bd->bd_ops->assert_modem_signals(ch); - } + if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) + dgnc_set_signal_low(ch, UART_MCR_DTR); } } @@ -930,7 +863,7 @@ void dgnc_wakeup_writes(struct channel_t *ch) spin_unlock_irqrestore(&ch->ch_lock, flags); } -struct dgnc_board *find_board_by_major(unsigned int major) +static struct dgnc_board *find_board_by_major(unsigned int major) { int i; @@ -948,16 +881,10 @@ struct dgnc_board *find_board_by_major(unsigned int major) return NULL; } -/************************************************************************ - * - * TTY Entry points and helper functions - * - ************************************************************************/ +/* TTY Entry points and helper functions */ + +/* dgnc_tty_open() */ -/* - * dgnc_tty_open() - * - */ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) { struct dgnc_board *brd; @@ -1045,8 +972,8 @@ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) * ch_flags_wait to wake us back up. */ rc = wait_event_interruptible(ch->ch_flags_wait, - (((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & - UN_CLOSING) == 0)); + (((ch->ch_tun.un_flags | + ch->ch_pun.un_flags) & UN_CLOSING) == 0)); /* If ret is non-zero, user ctrl-c'ed us */ if (rc) @@ -1057,9 +984,8 @@ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) /* Store our unit into driver_data, so we always have it available. */ tty->driver_data = un; - /* - * Initialize tty's - */ + /* Initialize tty's */ + if (!(un->un_flags & UN_ISOPEN)) { /* Store important variables. */ un->un_tty = tty; @@ -1096,13 +1022,10 @@ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) ch->ch_flags &= ~(CH_OPENING); wake_up_interruptible(&ch->ch_flags_wait); - /* - * Initialize if neither terminal or printer is open. - */ + /* Initialize if neither terminal or printer is open. */ + if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { - /* - * Flush input queues. - */ + /* Flush input queues. */ ch->ch_r_head = 0; ch->ch_r_tail = 0; ch->ch_e_head = 0; @@ -1138,16 +1061,13 @@ static int dgnc_tty_open(struct tty_struct *tty, struct file *file) brd->bd_ops->uart_init(ch); } - /* - * Run param in case we changed anything - */ + /* Run param in case we changed anything */ + brd->bd_ops->param(tty); dgnc_carrier(ch); - /* - * follow protocol for opening port - */ + /* follow protocol for opening port */ spin_unlock_irqrestore(&ch->ch_lock, flags); @@ -1248,9 +1168,8 @@ static int dgnc_block_til_ready(struct tty_struct *tty, break; } - /* - * Store the flags before we let go of channel lock - */ + /* Store the flags before we let go of channel lock */ + if (sleep_on_un_flags) old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; else @@ -1269,12 +1188,13 @@ static int dgnc_block_til_ready(struct tty_struct *tty, * from the current value. */ if (sleep_on_un_flags) - retval = wait_event_interruptible(un->un_flags_wait, - (old_flags != (ch->ch_tun.un_flags | - ch->ch_pun.un_flags))); + retval = wait_event_interruptible + (un->un_flags_wait, + (old_flags != (ch->ch_tun.un_flags | + ch->ch_pun.un_flags))); else retval = wait_event_interruptible(ch->ch_flags_wait, - (old_flags != ch->ch_flags)); + (old_flags != ch->ch_flags)); /* * We got woken up for some reason. @@ -1304,10 +1224,8 @@ static void dgnc_tty_hangup(struct tty_struct *tty) dgnc_tty_flush_buffer(tty); } -/* - * dgnc_tty_close() - * - */ +/* dgnc_tty_close() */ + static void dgnc_tty_close(struct tty_struct *tty, struct file *file) { struct dgnc_board *bd; @@ -1377,9 +1295,8 @@ static void dgnc_tty_close(struct tty_struct *tty, struct file *file) !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { ch->ch_flags &= ~(CH_STOPI | CH_FORCED_STOPI); - /* - * turn off print device when closing print device. - */ + /* turn off print device when closing print device. */ + if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) { dgnc_wmove(ch, ch->ch_digi.digi_offstr, (int)ch->ch_digi.digi_offlen); @@ -1399,9 +1316,8 @@ static void dgnc_tty_close(struct tty_struct *tty, struct file *file) tty->closing = 0; - /* - * If we have HUPCL set, lower DTR and RTS - */ + /* If we have HUPCL set, lower DTR and RTS */ + if (ch->ch_c_cflag & HUPCL) { /* Drop RTS/DTR */ ch->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); @@ -1424,9 +1340,8 @@ static void dgnc_tty_close(struct tty_struct *tty, struct file *file) /* Turn off UART interrupts for this port */ ch->ch_bd->bd_ops->uart_off(ch); } else { - /* - * turn off print device when closing print device. - */ + /* turn off print device when closing print device. */ + if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) { dgnc_wmove(ch, ch->ch_digi.digi_offstr, (int)ch->ch_digi.digi_offlen); @@ -1543,7 +1458,7 @@ static int dgnc_tty_write_room(struct tty_struct *tty) int ret = 0; unsigned long flags; - if (!tty || !dgnc_TmpWriteBuf) + if (!tty) return 0; un = tty->driver_data; @@ -1598,9 +1513,8 @@ static int dgnc_tty_write_room(struct tty_struct *tty) */ static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c) { - /* - * Simply call tty_write. - */ + /* Simply call tty_write. */ + dgnc_tty_write(tty, &c, 1); return 1; } @@ -1623,7 +1537,7 @@ static int dgnc_tty_write(struct tty_struct *tty, ushort tmask; uint remain; - if (!tty || !dgnc_TmpWriteBuf) + if (!tty) return 0; un = tty->driver_data; @@ -1667,9 +1581,8 @@ static int dgnc_tty_write(struct tty_struct *tty, */ count = min(count, bufcount); - /* - * Bail if no space left. - */ + /* Bail if no space left. */ + if (count <= 0) goto exit_retry; @@ -1712,9 +1625,7 @@ static int dgnc_tty_write(struct tty_struct *tty, } if (n > 0) { - /* - * Move rest of data. - */ + /* Move rest of data. */ remain = n; memcpy(ch->ch_wqueue + head, buf, remain); head += remain; @@ -1749,9 +1660,7 @@ exit_retry: return 0; } -/* - * Return modem signals to ld. - */ +/* Return modem signals to ld. */ static int dgnc_tty_tiocmget(struct tty_struct *tty) { @@ -1960,9 +1869,8 @@ static void dgnc_tty_send_xchar(struct tty_struct *tty, char c) dev_dbg(tty->dev, "dgnc_tty_send_xchar finish\n"); } -/* - * Return modem signals to ld. - */ +/* Return modem signals to ld. */ + static inline int dgnc_get_mstat(struct channel_t *ch) { unsigned char mstat; @@ -1994,9 +1902,8 @@ static inline int dgnc_get_mstat(struct channel_t *ch) return result; } -/* - * Return modem signals to ld. - */ +/* Return modem signals to ld. */ + static int dgnc_get_modem_info(struct channel_t *ch, unsigned int __user *value) { @@ -2070,9 +1977,6 @@ static int dgnc_set_modem_info(struct channel_t *ch, * dgnc_tty_digigeta() * * Ioctl to get the information for ditty. - * - * - * */ static int dgnc_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo) @@ -2112,9 +2016,6 @@ static int dgnc_tty_digigeta(struct tty_struct *tty, * dgnc_tty_digiseta() * * Ioctl to set the information for ditty. - * - * - * */ static int dgnc_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info) @@ -2145,9 +2046,8 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, spin_lock_irqsave(&ch->ch_lock, flags); - /* - * Handle transistions to and from RTS Toggle. - */ + /* Handle transitions to and from RTS Toggle. */ + if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && (new_digi.digi_flags & DIGI_RTS_TOGGLE)) ch->ch_mostat &= ~(UART_MCR_RTS); @@ -2155,9 +2055,8 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, !(new_digi.digi_flags & DIGI_RTS_TOGGLE)) ch->ch_mostat |= (UART_MCR_RTS); - /* - * Handle transistions to and from DTR Toggle. - */ + /* Handle transitions to and from DTR Toggle. */ + if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && (new_digi.digi_flags & DIGI_DTR_TOGGLE)) ch->ch_mostat &= ~(UART_MCR_DTR); @@ -2195,9 +2094,8 @@ static int dgnc_tty_digiseta(struct tty_struct *tty, return 0; } -/* - * dgnc_set_termios() - */ +/* dgnc_set_termios() */ + static void dgnc_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { @@ -2428,11 +2326,18 @@ static void dgnc_tty_flush_buffer(struct tty_struct *tty) spin_unlock_irqrestore(&ch->ch_lock, flags); } -/***************************************************************************** - * - * The IOCTL function and all of its helpers +/* + * dgnc_wake_up_unit() * - *****************************************************************************/ + * Wakes up processes waiting in the unit's (teminal/printer) wait queue + */ +static void dgnc_wake_up_unit(struct un_t *unit) +{ + unit->un_flags &= ~(UN_LOW | UN_EMPTY); + wake_up_interruptible(&unit->un_flags_wait); +} + +/* The IOCTL function and all of its helpers */ /* * dgnc_tty_ioctl() @@ -2506,7 +2411,8 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, return 0; case TCSBRKP: - /* support for POSIX tcsendbreak() + /* + * support for POSIX tcsendbreak() * According to POSIX.1 spec (7.2.2.1.2) breaks should be * between 0.25 and 0.5 seconds so we'll ask for something * in the middle: 0.375 seconds. @@ -2583,9 +2489,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, spin_unlock_irqrestore(&ch->ch_lock, flags); return dgnc_set_modem_info(ch, cmd, uarg); - /* - * Here are any additional ioctl's that we want to implement - */ + /* Here are any additional ioctl's that we want to implement */ case TCFLSH: /* @@ -2615,17 +2519,11 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, ch->ch_w_head = ch->ch_w_tail; ch_bd_ops->flush_uart_write(ch); - if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY)) { - ch->ch_tun.un_flags &= - ~(UN_LOW | UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - - if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_pun.un_flags &= - ~(UN_LOW | UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } + if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY)) + dgnc_wake_up_unit(&ch->ch_tun); + + if (ch->ch_pun.un_flags & (UN_LOW | UN_EMPTY)) + dgnc_wake_up_unit(&ch->ch_pun); } } @@ -2705,9 +2603,10 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, case DIGI_LOOPBACK: { uint loopback = 0; - /* Let go of locks when accessing user space, + /* + * Let go of locks when accessing user space, * could sleep - */ + */ spin_unlock_irqrestore(&ch->ch_lock, flags); rc = get_user(loopback, (unsigned int __user *)arg); if (rc) @@ -2749,7 +2648,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, * This ioctl allows insertion of a character into the front * of any pending data to be transmitted. * - * This ioctl is to satify the "Send Character Immediate" + * This ioctl is to satisfy the "Send Character Immediate" * call that the RealPort protocol spec requires. */ case DIGI_REALPORT_SENDIMMEDIATE: @@ -2769,7 +2668,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, /* * This ioctl returns all the current counts for the port. * - * This ioctl is to satify the "Line Error Counters" + * This ioctl is to satisfy the "Line Error Counters" * call that the RealPort protocol spec requires. */ case DIGI_REALPORT_GETCOUNTERS: @@ -2795,7 +2694,7 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, /* * This ioctl returns all current events. * - * This ioctl is to satify the "Event Reporting" + * This ioctl is to satisfy the "Event Reporting" * call that the RealPort protocol spec requires. */ case DIGI_REALPORT_GETEVENTS: @@ -2831,23 +2730,23 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, spin_unlock_irqrestore(&ch->ch_lock, flags); - /* - * Get data from user first. - */ + /* Get data from user first. */ + if (copy_from_user(&buf, uarg, sizeof(buf))) return -EFAULT; spin_lock_irqsave(&ch->ch_lock, flags); - /* - * Figure out how much data is in our RX and TX queues. - */ + /* Figure out how much data is in our RX and TX queues. */ + buf.rxbuf = (ch->ch_r_head - ch->ch_r_tail) & RQUEUEMASK; buf.txbuf = (ch->ch_w_head - ch->ch_w_tail) & WQUEUEMASK; /* - * Is the UART empty? Add that value to whats in our TX queue. + * Is the UART empty? + * Add that value to whats in our TX queue. */ + count = buf.txbuf + ch_bd_ops->get_uart_bytes_left(ch); /* @@ -2867,9 +2766,8 @@ static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, if (buf.txbuf > tdist) buf.txbuf = tdist; - /* - * Report whether our queue and UART TX are completely empty. - */ + /* Report whether our queue and UART TX are completely empty. */ + if (count) buf.txdone = 0; else |