irtty-sir.c

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

C
622
字号
/* ------------------------------------------------------- *//* * Function irtty_stop_receiver (tty, stop) * */static inline void irtty_stop_receiver(struct tty_struct *tty, int stop){	struct ktermios old_termios;	int cflag;	lock_kernel();	old_termios = *(tty->termios);	cflag = tty->termios->c_cflag;		if (stop)		cflag &= ~CREAD;	else		cflag |= CREAD;	tty->termios->c_cflag = cflag;	if (tty->driver->set_termios)		tty->driver->set_termios(tty, &old_termios);	unlock_kernel();}/*****************************************************************//* serialize ldisc open/close with sir_dev */static DEFINE_MUTEX(irtty_mutex);/* notifier from sir_dev when irda% device gets opened (ifup) */static int irtty_start_dev(struct sir_dev *dev){	struct sirtty_cb *priv;	struct tty_struct *tty;	/* serialize with ldisc open/close */	mutex_lock(&irtty_mutex);	priv = dev->priv;	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {		mutex_unlock(&irtty_mutex);		return -ESTALE;	}	tty = priv->tty;	if (tty->driver->start)		tty->driver->start(tty);	/* Make sure we can receive more data */	irtty_stop_receiver(tty, FALSE);	mutex_unlock(&irtty_mutex);	return 0;}/* notifier from sir_dev when irda% device gets closed (ifdown) */static int irtty_stop_dev(struct sir_dev *dev){	struct sirtty_cb *priv;	struct tty_struct *tty;	/* serialize with ldisc open/close */	mutex_lock(&irtty_mutex);	priv = dev->priv;	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {		mutex_unlock(&irtty_mutex);		return -ESTALE;	}	tty = priv->tty;	/* Make sure we don't receive more data */	irtty_stop_receiver(tty, TRUE);	if (tty->driver->stop)		tty->driver->stop(tty);	mutex_unlock(&irtty_mutex);	return 0;}/* ------------------------------------------------------- */static struct sir_driver sir_tty_drv = {	.owner			= THIS_MODULE,	.driver_name		= "sir_tty",	.start_dev		= irtty_start_dev,	.stop_dev		= irtty_stop_dev,	.do_write		= irtty_do_write,	.chars_in_buffer	= irtty_chars_in_buffer,	.wait_until_sent	= irtty_wait_until_sent,	.set_speed		= irtty_change_speed,	.set_dtr_rts		= irtty_set_dtr_rts,};/* ------------------------------------------------------- *//* * Function irtty_ioctl (tty, file, cmd, arg) * *     The Swiss army knife of system calls :-) * */static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){	struct irtty_info { char name[6]; } info;	struct sir_dev *dev;	struct sirtty_cb *priv = tty->disc_data;	int err = 0;	IRDA_ASSERT(priv != NULL, return -ENODEV;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);	IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __FUNCTION__, cmd);	dev = priv->dev;	IRDA_ASSERT(dev != NULL, return -1;);	switch (cmd) {	case IRTTY_IOCTDONGLE:		/* this call blocks for completion */		err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg);		break;	case IRTTY_IOCGET:		IRDA_ASSERT(dev->netdev != NULL, return -1;);		memset(&info, 0, sizeof(info)); 		strncpy(info.name, dev->netdev->name, sizeof(info.name)-1);		if (copy_to_user((void __user *)arg, &info, sizeof(info)))			err = -EFAULT;		break;	default:		err = tty_mode_ioctl(tty, file, cmd, arg);		break;	}	return err;}/*  *  Function irtty_open(tty) * *    This function is called by the TTY module when the IrDA line *    discipline is called for.  Because we are sure the tty line exists, *    we only have to link it to a free IrDA channel.   */static int irtty_open(struct tty_struct *tty) {	struct sir_dev *dev;	struct sirtty_cb *priv;	int ret = 0;	/* Module stuff handled via irda_ldisc.owner - Jean II */	/* First make sure we're not already connected. */	if (tty->disc_data != NULL) {		priv = tty->disc_data;		if (priv && priv->magic == IRTTY_MAGIC) {			ret = -EEXIST;			goto out;		}		tty->disc_data = NULL;		/* ### */	}	/* stop the underlying  driver */	irtty_stop_receiver(tty, TRUE);	if (tty->driver->stop)		tty->driver->stop(tty);	if (tty->driver->flush_buffer)		tty->driver->flush_buffer(tty);		/* apply mtt override */	sir_tty_drv.qos_mtt_bits = qos_mtt_bits;	/* get a sir device instance for this driver */	dev = sirdev_get_instance(&sir_tty_drv, tty->name);	if (!dev) {		ret = -ENODEV;		goto out;	}	/* allocate private device info block */	priv = kzalloc(sizeof(*priv), GFP_KERNEL);	if (!priv)		goto out_put;	priv->magic = IRTTY_MAGIC;	priv->tty = tty;	priv->dev = dev;	/* serialize with start_dev - in case we were racing with ifup */	mutex_lock(&irtty_mutex);	dev->priv = priv;	tty->disc_data = priv;	tty->receive_room = 65536;	mutex_unlock(&irtty_mutex);	IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name);	return 0;out_put:	sirdev_put_instance(dev);out:	return ret;}/*  *  Function irtty_close (tty) * *    Close down a IrDA channel. This means flushing out any pending queues, *    and then restoring the TTY line discipline to what it was before it got *    hooked to IrDA (which usually is TTY again).   */static void irtty_close(struct tty_struct *tty) {	struct sirtty_cb *priv = tty->disc_data;	IRDA_ASSERT(priv != NULL, return;);	IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);	/* Hm, with a dongle attached the dongle driver wants	 * to close the dongle - which requires the use of	 * some tty write and/or termios or ioctl operations.	 * Are we allowed to call those when already requested	 * to shutdown the ldisc?	 * If not, we should somehow mark the dev being staled.	 * Question remains, how to close the dongle in this case...	 * For now let's assume we are granted to issue tty driver calls	 * until we return here from the ldisc close. I'm just wondering	 * how this behaves with hotpluggable serial hardware like	 * rs232-pcmcia card or usb-serial...	 *	 * priv->tty = NULL?;	 */	/* we are dead now */	tty->disc_data = NULL;	sirdev_put_instance(priv->dev);	/* Stop tty */	irtty_stop_receiver(tty, TRUE);	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);	if (tty->driver->stop)		tty->driver->stop(tty);	kfree(priv);	IRDA_DEBUG(0, "%s - %s: irda line discipline closed\n", __FUNCTION__, tty->name);}/* ------------------------------------------------------- */static struct tty_ldisc irda_ldisc = {	.magic		= TTY_LDISC_MAGIC, 	.name		= "irda",	.flags		= 0,	.open		= irtty_open,	.close		= irtty_close,	.read		= NULL,	.write		= NULL,	.ioctl		= irtty_ioctl, 	.poll		= NULL,	.receive_buf	= irtty_receive_buf,	.write_wakeup	= irtty_write_wakeup,	.owner		= THIS_MODULE,};/* ------------------------------------------------------- */static int __init irtty_sir_init(void){	int err;	if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)		IRDA_ERROR("IrDA: can't register line discipline (err = %d)\n",			   err);	return err;}static void __exit irtty_sir_cleanup(void) {	int err;	if ((err = tty_unregister_ldisc(N_IRDA))) {		IRDA_ERROR("%s(), can't unregister line discipline (err = %d)\n",			   __FUNCTION__, err);	}}module_init(irtty_sir_init);module_exit(irtty_sir_cleanup);MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("IrDA TTY device driver");MODULE_ALIAS_LDISC(N_IRDA);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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