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 + -
显示快捷键?