static int
ctc_tty_tiocmset(struct tty_struct *tty, struct file *file,
		 unsigned int set, unsigned int clear)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	DBF_TEXT(trace, 4, __FUNCTION__);
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
		return -ENODEV;
	if (tty->flags & (1 << TTY_IO_ERROR))
		return -EIO;

	if (set & TIOCM_RTS)
		info->mcr |= UART_MCR_RTS;
	if (set & TIOCM_DTR)
		info->mcr |= UART_MCR_DTR;

	if (clear & TIOCM_RTS)
		info->mcr &= ~UART_MCR_RTS;
	if (clear & TIOCM_DTR)
		info->mcr &= ~UART_MCR_DTR;

	if ((set | clear) & (TIOCM_RTS|TIOCM_DTR))
		ctc_tty_transmit_status(info);
	return 0;
}
static void
ctc_tty_flush_buffer(struct tty_struct *tty)
{
	ctc_tty_info *info;
	unsigned long flags;

	DBF_TEXT(trace, 4, __FUNCTION__);
	if (!tty)
		goto ex;
	spin_lock_irqsave(&ctc_tty_lock, flags);
	info = (ctc_tty_info *) tty->driver_data;
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) {
		spin_unlock_irqrestore(&ctc_tty_lock, flags);
		goto ex;
	}
	skb_queue_purge(&info->tx_queue);
	info->lsr |= UART_LSR_TEMT;
	spin_unlock_irqrestore(&ctc_tty_lock, flags);
	wake_up_interruptible(&tty->write_wait);
	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
	    tty->ldisc.write_wakeup)
		(tty->ldisc.write_wakeup) (tty);
ex:
	DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__);
	return;
}
示例#3
0
static void
ctc_tty_flush_buffer(struct tty_struct *tty)
{
	ctc_tty_info *info;
	unsigned long flags;

	save_flags(flags);
	cli();
	if (!tty) {
		restore_flags(flags);
		return;
	}
	info = (ctc_tty_info *) tty->driver_data;
	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_buffer")) {
		restore_flags(flags);
		return;
	}
	skb_queue_purge(&info->tx_queue);
	info->lsr |= UART_LSR_TEMT;
	restore_flags(flags);
	wake_up_interruptible(&tty->write_wait);
	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
	    tty->ldisc.write_wakeup)
		(tty->ldisc.write_wakeup) (tty);
}
static int ctc_tty_tiocmget(struct tty_struct *tty, struct file *file)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
	u_char control,
	 status;
	uint result;
	ulong flags;

	DBF_TEXT(trace, 4, __FUNCTION__);
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_ioctl"))
		return -ENODEV;
	if (tty->flags & (1 << TTY_IO_ERROR))
		return -EIO;

	control = info->mcr;
	spin_lock_irqsave(&ctc_tty_lock, flags);
	status = info->msr;
	spin_unlock_irqrestore(&ctc_tty_lock, flags);
	result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
	    | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
	    | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
	    | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
	    | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
	    | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
	return result;
}
/* ctc_tty_write() is the main send-routine. It is called from the upper
 * levels within the kernel to perform sending data. Depending on the
 * online-flag it either directs output to the at-command-interpreter or
 * to the lower level. Additional tasks done here:
 *  - If online, check for escape-sequence (+++)
 *  - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes.
 *  - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed.
 *  - If dialing, abort dial.
 */
static int
ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
{
	int c;
	int total = 0;
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	DBF_TEXT(trace, 5, __FUNCTION__);
	if (ctc_tty_shuttingdown)
		goto ex;
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write"))
		goto ex;
	if (!tty)
		goto ex;
	if (!info->netdev) {
		total = -ENODEV;
		goto ex;
	}
	if (from_user)
		down(&info->write_sem);
	while (1) {
		struct sk_buff *skb;
		int skb_res;

		c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE;
		if (c <= 0)
			break;
		
		skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
			+ sizeof(__u32);
		skb = dev_alloc_skb(skb_res + c);
		if (!skb) {
			printk(KERN_WARNING
			       "ctc_tty: Out of memory in %s%d write\n",
			       CTC_TTY_NAME, info->line);
			break;
		}
		skb_reserve(skb, skb_res);
		if (from_user)
			copy_from_user(skb_put(skb, c),
					(const u_char __user *)buf, c);
		else
			memcpy(skb_put(skb, c), buf, c);
		skb_queue_tail(&info->tx_queue, skb);
		buf += c;
		total += c;
		count -= c;
	}
	if (skb_queue_len(&info->tx_queue)) {
		info->lsr &= ~UART_LSR_TEMT;
		tasklet_schedule(&info->tasklet);
	}
	if (from_user)
		up(&info->write_sem);
ex:
	DBF_TEXT(trace, 6, __FUNCTION__);
	return total;
}
示例#6
0
static int
ctc_tty_chars_in_buffer(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_chars_in_buffer"))
		return 0;
	return 0;
}
示例#7
0
static int
ctc_tty_write_room(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write_room"))
		return 0;
	return CTC_TTY_XMIT_SIZE;
}
示例#8
0
/* ctc_tty_write() is the main send-routine. It is called from the upper
 * levels within the kernel to perform sending data. Depending on the
 * online-flag it either directs output to the at-command-interpreter or
 * to the lower level. Additional tasks done here:
 *  - If online, check for escape-sequence (+++)
 *  - If sending audio-data, call ctc_tty_DLEdown() to parse DLE-codes.
 *  - If receiving audio-data, call ctc_tty_end_vrx() to abort if needed.
 *  - If dialing, abort dial.
 */
static int
ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
{
	int c;
	int total = 0;
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	if (ctc_tty_shuttingdown)
		return 0;
	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
		return 0;
	if (!tty)
		return 0;
	if (!info->netdev)
		return -ENODEV;
	if (from_user)
		down(&info->write_sem);
	while (1) {
		struct sk_buff *skb;
		int skb_res;

		c = (count < CTC_TTY_XMIT_SIZE) ? count : CTC_TTY_XMIT_SIZE;
		if (c <= 0)
			break;
		
		skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
			+ sizeof(__u32);
		skb = dev_alloc_skb(skb_res + c);
		if (!skb) {
			printk(KERN_WARNING
			       "ctc_tty: Out of memory in %s%d write\n",
			       CTC_TTY_NAME, info->line);
			break;
		}
		skb_reserve(skb, skb_res);
		if (from_user)
			copy_from_user(skb_put(skb, c), buf, c);
		else
			memcpy(skb_put(skb, c), buf, c);
		skb_queue_tail(&info->tx_queue, skb);
		buf += c;
		total += c;
		count -= c;
	}
	if (skb_queue_len(&info->tx_queue)) {
		info->lsr &= ~UART_LSR_TEMT;
		queue_task(&info->tq, &tq_immediate);
		mark_bh(IMMEDIATE_BH);
	}
	if (from_user)
		up(&info->write_sem);
	return total;
}
示例#9
0
static void
ctc_tty_unthrottle(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
		return;
	info->mcr |= UART_MCR_RTS;
	if (I_IXOFF(tty))
		ctc_tty_inject(info, START_CHAR(tty));
	ctc_tty_transmit_status(info);
}
/*
 * ------------------------------------------------------------
 * ctc_tty_throttle()
 *
 * This routine is called by the upper-layer tty layer to signal that
 * incoming characters should be throttled.
 * ------------------------------------------------------------
 */
static void
ctc_tty_throttle(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	DBF_TEXT(trace, 4, __FUNCTION__);
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_throttle"))
		return;
	info->mcr &= ~UART_MCR_RTS;
	if (I_IXOFF(tty))
		ctc_tty_inject(info, STOP_CHAR(tty));
	ctc_tty_transmit_status(info);
}
示例#11
0
/*
 * This routine is called whenever a serial port is opened.  It
 * enables interrupts for a serial port, linking in its async structure into
 * the IRQ chain.   It also performs the serial-specific
 * initialization for the tty structure.
 */
static int
ctc_tty_open(struct tty_struct *tty, struct file *filp)
{
	ctc_tty_info *info;
	unsigned long saveflags;
	int retval,
	 line;

	line = MINOR(tty->device) - tty->driver.minor_start;
	if (line < 0 || line > CTC_TTY_MAX_DEVICES)
		return -ENODEV;
	info = &driver->info[line];
	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_open"))
		return -ENODEV;
	if (!info->netdev)
		return -ENODEV;
#ifdef CTC_DEBUG_MODEM_OPEN
	printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
	       info->line, info->count);
#endif
	spin_lock_irqsave(&ctc_tty_lock, saveflags);
	info->count++;
	tty->driver_data = info;
	info->tty = tty;
	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
	/*
	 * Start up serial port
	 */
	retval = ctc_tty_startup(info);
	if (retval) {
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_open return after startup\n");
#endif
		return retval;
	}
	retval = ctc_tty_block_til_ready(tty, filp, info);
	if (retval) {
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n");
#endif
		return retval;
	}
	if ((info->count == 1) && (info->flags & CTC_ASYNC_SPLIT_TERMIOS)) {
		*tty->termios = info->normal_termios;
		ctc_tty_change_speed(info);
	}
#ifdef CTC_DEBUG_MODEM_OPEN
	printk(KERN_DEBUG "ctc_tty_open %s%d successful...\n", CTC_TTY_NAME, info->line);
#endif
	return 0;
}
static void
ctc_tty_flush_chars(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	DBF_TEXT(trace, 4, __FUNCTION__);
	if (ctc_tty_shuttingdown)
		return;
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars"))
		return;
	if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
		return;
	tasklet_schedule(&info->tasklet);
}
示例#13
0
static void
ctc_tty_flush_chars(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;

	if (ctc_tty_shuttingdown)
		return;
	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
		return;
	if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
		return;
	queue_task(&info->tq, &tq_immediate);
	mark_bh(IMMEDIATE_BH);
}
/*
 * This routine is called whenever a serial port is opened.  It
 * enables interrupts for a serial port, linking in its async structure into
 * the IRQ chain.   It also performs the serial-specific
 * initialization for the tty structure.
 */
static int
ctc_tty_open(struct tty_struct *tty, struct file *filp)
{
	ctc_tty_info *info;
	unsigned long saveflags;
	int retval,
	 line;

	DBF_TEXT(trace, 3, __FUNCTION__);
	line = tty->index;
	if (line < 0 || line > CTC_TTY_MAX_DEVICES)
		return -ENODEV;
	info = &driver->info[line];
	if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_open"))
		return -ENODEV;
	if (!info->netdev)
		return -ENODEV;
#ifdef CTC_DEBUG_MODEM_OPEN
	printk(KERN_DEBUG "ctc_tty_open %s, count = %d\n", tty->name,
	       info->count);
#endif
	spin_lock_irqsave(&ctc_tty_lock, saveflags);
	info->count++;
	tty->driver_data = info;
	info->tty = tty;
	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
	/*
	 * Start up serial port
	 */
	retval = ctc_tty_startup(info);
	if (retval) {
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_open return after startup\n");
#endif
		return retval;
	}
	retval = ctc_tty_block_til_ready(tty, filp, info);
	if (retval) {
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_open return after ctc_tty_block_til_ready \n");
#endif
		return retval;
	}
#ifdef CTC_DEBUG_MODEM_OPEN
	printk(KERN_DEBUG "ctc_tty_open %s successful...\n", tty->name);
#endif
	return 0;
}
示例#15
0
/*
 * ctc_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
 */
static void
ctc_tty_hangup(struct tty_struct *tty)
{
	ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
	unsigned long saveflags;

	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
		return;
	ctc_tty_shutdown(info);
	info->count = 0;
	info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
	spin_lock_irqsave(&ctc_tty_lock, saveflags);
	info->tty = 0;
	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
	wake_up_interruptible(&info->open_wait);
}
示例#16
0
static int
ctc_tty_ioctl(struct tty_struct *tty, struct file *file,
	       uint cmd, ulong arg)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
	int error;
	int retval;

	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_ioctl"))
		return -ENODEV;
	if (tty->flags & (1 << TTY_IO_ERROR))
		return -EIO;
	switch (cmd) {
		case TCSBRK:   /* SVID version: non-zero arg --> no break */
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line);
#endif
			retval = tty_check_change(tty);
			if (retval)
				return retval;
			tty_wait_until_sent(tty, 0);
			return 0;
		case TCSBRKP:  /* support for POSIX tcsendbreak() */
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line);
#endif
			retval = tty_check_change(tty);
			if (retval)
				return retval;
			tty_wait_until_sent(tty, 0);
			return 0;
		case TIOCGSOFTCAR:
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME,
			       info->line);
#endif
			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
			if (error)
				return error;
			put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
			return 0;
		case TIOCSSOFTCAR:
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME,
			       info->line);
#endif
			error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
			if (error)
				return error;
			get_user(arg, (ulong *) arg);
			tty->termios->c_cflag =
			    ((tty->termios->c_cflag & ~CLOCAL) |
			     (arg ? CLOCAL : 0));
			return 0;
		case TIOCMGET:
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME,
			       info->line);
#endif
			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
			if (error)
				return error;
			return ctc_tty_get_ctc_tty_info(info, (uint *) arg);
		case TIOCMBIS:
		case TIOCMBIC:
		case TIOCMSET:
			error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
			if (error)
				return error;
			return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg);
		case TIOCSERGETLSR:	/* Get line status register */
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME,
			       info->line);
#endif
			error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
			if (error)
				return error;
			else
				return ctc_tty_get_lsr_info(info, (uint *) arg);
		default:
#ifdef CTC_DEBUG_MODEM_IOCTL
			printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd,
			       CTC_TTY_NAME, info->line);
#endif
			return -ENOIOCTLCMD;
	}
	return 0;
}
示例#17
0
static void
ctc_tty_close(struct tty_struct *tty, struct file *filp)
{
	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
	unsigned long saveflags;
	ulong flags;
	ulong timeout;

	if (!info || ctc_tty_paranoia_check(info, tty->device, "ctc_tty_close"))
		return;
	save_flags(flags);
	cli();
	if (tty_hung_up_p(filp)) {
		restore_flags(flags);
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n");
#endif
		return;
	}
	if ((tty->count == 1) && (info->count != 1)) {
		/*
		 * Uh, oh.  tty->count is 1, which means that the tty
		 * structure will be freed.  Info->count should always
		 * be one in these conditions.  If it's greater than
		 * one, we've got real problems, since it means the
		 * serial port won't be shutdown.
		 */
		printk(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, "
		       "info->count is %d\n", info->count);
		info->count = 1;
	}
	if (--info->count < 0) {
		printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n",
		       CTC_TTY_NAME, info->line, info->count);
		info->count = 0;
	}
	if (info->count) {
		restore_flags(flags);
#ifdef CTC_DEBUG_MODEM_OPEN
		printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n");
#endif
		return;
	}
	info->flags |= CTC_ASYNC_CLOSING;
	/*
	 * Save the termios structure, since this port may have
	 * separate termios for callout and dialin.
	 */
	if (info->flags & CTC_ASYNC_NORMAL_ACTIVE)
		info->normal_termios = *tty->termios;

	tty->closing = 1;
	/*
	 * At this point we stop accepting input.  To do this, we
	 * disable the receive line status interrupts, and tell the
	 * interrupt driver to stop checking the data ready bit in the
	 * line status register.
	 */
	if (info->flags & CTC_ASYNC_INITIALIZED) {
		tty_wait_until_sent(tty, 3000);	/* 30 seconds timeout */
		/*
		 * Before we drop DTR, make sure the UART transmitter
		 * has completely drained; this is especially
		 * important if there is a transmit FIFO!
		 */
		timeout = jiffies + HZ;
		while (!(info->lsr & UART_LSR_TEMT)) {
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(20);
			if (time_after(jiffies,timeout))
				break;
		}
	}
	ctc_tty_shutdown(info);
	if (tty->driver.flush_buffer)
		tty->driver.flush_buffer(tty);
	if (tty->ldisc.flush_buffer)
		tty->ldisc.flush_buffer(tty);
	spin_lock_irqsave(&ctc_tty_lock, saveflags);
	info->tty = 0;
	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
	tty->closing = 0;
	if (info->blocked_open) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(50);
		wake_up_interruptible(&info->open_wait);
	}
	info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING);
	wake_up_interruptible(&info->close_wait);
	restore_flags(flags);
#ifdef CTC_DEBUG_MODEM_OPEN
	printk(KERN_DEBUG "ctc_tty_close normal exit\n");
#endif
}