irtty-sir.c

来自「linux 内核源代码」· C语言 代码 · 共 622 行 · 第 1/2 页

C
622
字号
/********************************************************************* *                 * Filename:      irtty-sir.c * Version:       2.0 * Description:   IrDA line discipline implementation * Status:        Experimental. * Author:        Dag Brattli <dagb@cs.uit.no> * Created at:    Tue Dec  9 21:18:38 1997 * Modified at:   Sun Oct 27 22:13:30 2002 * Modified by:   Martin Diehl <mad@mdiehl.de> * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk> *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> *  *     Copyright (c) 1998-2000 Dag Brattli, *     Copyright (c) 2002 Martin Diehl, *     All Rights Reserved. *       *     This program is free software; you can redistribute it and/or  *     modify it under the terms of the GNU General Public License as  *     published by the Free Software Foundation; either version 2 of  *     the License, or (at your option) any later version. *   *     Neither Dag Brattli nor University of Tromsø admit liability nor *     provide warranty for any of this software. This material is  *     provided "AS-IS" and at no charge. *      ********************************************************************/    #include <linux/module.h>#include <linux/kernel.h>#include <linux/tty.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/smp_lock.h>#include <linux/delay.h>#include <linux/mutex.h>#include <net/irda/irda.h>#include <net/irda/irda_device.h>#include "sir-dev.h"#include "irtty-sir.h"static int qos_mtt_bits = 0x03;      /* 5 ms or more */module_param(qos_mtt_bits, int, 0);MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");/* ------------------------------------------------------- *//* device configuration callbacks always invoked with irda-thread context *//* find out, how many chars we have in buffers below us * this is allowed to lie, i.e. return less chars than we * actually have. The returned value is used to determine * how long the irdathread should wait before doing the * real blocking wait_until_sent() */static int irtty_chars_in_buffer(struct sir_dev *dev){	struct sirtty_cb *priv = dev->priv;	IRDA_ASSERT(priv != NULL, return -1;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);	return priv->tty->driver->chars_in_buffer(priv->tty);}/* Wait (sleep) until underlaying hardware finished transmission * i.e. hardware buffers are drained * this must block and not return before all characters are really sent * * If the tty sits on top of a 16550A-like uart, there are typically * up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec * * With usbserial the uart-fifo is basically replaced by the converter's * outgoing endpoint buffer, which can usually hold 64 bytes (at least). * With pl2303 it appears we are safe with 60msec here. * * I really wish all serial drivers would provide * correct implementation of wait_until_sent() */#define USBSERIAL_TX_DONE_DELAY	60static void irtty_wait_until_sent(struct sir_dev *dev){	struct sirtty_cb *priv = dev->priv;	struct tty_struct *tty;	IRDA_ASSERT(priv != NULL, return;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);	tty = priv->tty;	if (tty->driver->wait_until_sent) {		lock_kernel();		tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));		unlock_kernel();	}	else {		msleep(USBSERIAL_TX_DONE_DELAY);	}}/*  *  Function irtty_change_speed (dev, speed) * *    Change the speed of the serial port. * * This may sleep in set_termios (usbserial driver f.e.) and must * not be called from interrupt/timer/tasklet therefore. * All such invocations are deferred to kIrDAd now so we can sleep there. */static int irtty_change_speed(struct sir_dev *dev, unsigned speed){	struct sirtty_cb *priv = dev->priv;	struct tty_struct *tty;        struct ktermios old_termios;	int cflag;	IRDA_ASSERT(priv != NULL, return -1;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);	tty = priv->tty;	lock_kernel();	old_termios = *(tty->termios);	cflag = tty->termios->c_cflag;	cflag &= ~CBAUD;	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;	return 0;}/* * Function irtty_set_dtr_rts (dev, dtr, rts) * *    This function can be used by dongles etc. to set or reset the status *    of the dtr and rts lines */static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts){	struct sirtty_cb *priv = dev->priv;	int set = 0;	int clear = 0;	IRDA_ASSERT(priv != NULL, return -1;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);	if (rts)		set |= TIOCM_RTS;	else		clear |= TIOCM_RTS;	if (dtr)		set |= TIOCM_DTR;	else		clear |= TIOCM_DTR;	/*	 * We can't use ioctl() because it expects a non-null file structure,	 * and we don't have that here.	 * This function is not yet defined for all tty driver, so	 * let's be careful... Jean II	 */	IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);	priv->tty->driver->tiocmset(priv->tty, NULL, set, clear);	return 0;}/* ------------------------------------------------------- *//* called from sir_dev when there is more data to send * context is either netdev->hard_xmit or some transmit-completion bh * i.e. we are under spinlock here and must not sleep. */static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len){	struct sirtty_cb *priv = dev->priv;	struct tty_struct *tty;	int writelen;	IRDA_ASSERT(priv != NULL, return -1;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);	tty = priv->tty;	if (!tty->driver->write)		return 0;	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);	if (tty->driver->write_room) {		writelen = tty->driver->write_room(tty);		if (writelen > len)			writelen = len;	}	else		writelen = len;	return tty->driver->write(tty, ptr, writelen);}/* ------------------------------------------------------- *//* irda line discipline callbacks *//*  *  Function irtty_receive_buf( tty, cp, count) * *    Handle the 'receiver data ready' interrupt.  This function is called *    by the 'tty_io' module in the kernel when a block of IrDA data has *    been received, which can now be decapsulated and delivered for *    further processing  * * calling context depends on underlying driver and tty->low_latency! * for example (low_latency: 1 / 0): * serial.c:	uart-interrupt / softint * usbserial:	urb-complete-interrupt / softint */static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,			      char *fp, int count) {	struct sir_dev *dev;	struct sirtty_cb *priv = tty->disc_data;	int	i;	IRDA_ASSERT(priv != NULL, return;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);	if (unlikely(count==0))		/* yes, this happens */		return;	dev = priv->dev;	if (!dev) {		IRDA_WARNING("%s(), not ready yet!\n", __FUNCTION__);		return;	}	for (i = 0; i < count; i++) {		/* 		 *  Characters received with a parity error, etc?		 */ 		if (fp && *fp++) { 			IRDA_DEBUG(0, "Framing or parity error!\n");			sirdev_receive(dev, NULL, 0);	/* notify sir_dev (updating stats) */			return; 		}	}	sirdev_receive(dev, cp, count);}/* * Function irtty_write_wakeup (tty) * *    Called by the driver when there's room for more data.  If we have *    more packets to send, we send them here. * */static void irtty_write_wakeup(struct tty_struct *tty) {	struct sirtty_cb *priv = tty->disc_data;	IRDA_ASSERT(priv != NULL, return;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	if (priv->dev)		sirdev_write_complete(priv->dev);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?