cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/irda/irtty-sir.c

Directory: drivers/net/irda
/*********************************************************************
 *                
 * 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/slab.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/uaccess.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 tty_chars_in_buffer(priv->tty); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes4597.83%266.67%
Alan Cox12.17%133.33%
Total46100.00%3100.00%

/* 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 60
static 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->ops->wait_until_sent) { tty->ops->wait_until_sent(tty, msecs_to_jiffies(100)); } else { msleep(USBSERIAL_TX_DONE_DELAY); } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes7192.21%233.33%
Al Viro22.60%116.67%
Alan Cox22.60%116.67%
Domen Puncer11.30%116.67%
Andrew Morton11.30%116.67%
Total77100.00%6100.00%

/* * 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; down_write(&tty->termios_rwsem); old_termios = tty->termios; cflag = tty->termios.c_cflag; tty_encode_baud_rate(tty, speed, speed); if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); priv->io.speed = speed; up_write(&tty->termios_rwsem); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes10581.40%228.57%
Alan Cox1813.95%342.86%
Peter Hurley43.10%114.29%
Al Viro21.55%114.29%
Total129100.00%7100.00%

/* * 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->ops->tiocmset != NULL, return -1;); priv->tty->ops->tiocmset(priv->tty, set, clear); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes7971.82%240.00%
Russell King2825.45%120.00%
Alan Cox21.82%120.00%
Al Viro10.91%120.00%
Total110100.00%5100.00%

/* ------------------------------------------------------- */ /* 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->ops->write) return 0; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); writelen = tty_write_room(tty); if (writelen > len) writelen = len; return tty->ops->write(tty, ptr, writelen); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes10390.35%240.00%
Alan Cox97.89%240.00%
Al Viro21.75%120.00%
Total114100.00%5100.00%

/* ------------------------------------------------------- */ /* 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->port->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) { net_warn_ratelimited("%s(), not ready yet!\n", __func__); return; } for (i = 0; i < count; i++) { /* * Characters received with a parity error, etc? */ if (fp && *fp++) { pr_debug("Framing or parity error!\n"); sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */ return; } } sirdev_receive(dev, cp, count); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes12187.68%228.57%
Martin Diehl85.80%114.29%
Linus Torvalds64.35%114.29%
Joe Perches21.45%228.57%
Harvey Harrison10.72%114.29%
Total138100.00%7100.00%

/* * 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;); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (priv->dev) sirdev_write_complete(priv->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes4171.93%250.00%
Martin Diehl1017.54%125.00%
Alan Cox610.53%125.00%
Total57100.00%4100.00%

/* ------------------------------------------------------- */ /* * Function irtty_stop_receiver (tty, stop) * */
static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) { struct ktermios old_termios; int cflag; down_write(&tty->termios_rwsem); old_termios = tty->termios; cflag = tty->termios.c_cflag; if (stop) cflag &= ~CREAD; else cflag |= CREAD; tty->termios.c_cflag = cflag; if (tty->ops->set_termios) tty->ops->set_termios(tty, &old_termios); up_write(&tty->termios_rwsem); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes7377.66%116.67%
Alan Cox1515.96%350.00%
Peter Hurley44.26%116.67%
Al Viro22.13%116.67%
Total94100.00%6100.00%

/*****************************************************************/ /* 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->ops->start) tty->ops->start(tty); /* Make sure we can receive more data */ irtty_stop_receiver(tty, FALSE); mutex_unlock(&irtty_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes9090.00%125.00%
Arjan van de Ven66.00%125.00%
Al Viro22.00%125.00%
Alan Cox22.00%125.00%
Total100100.00%4100.00%

/* 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->ops->stop) tty->ops->stop(tty); mutex_unlock(&irtty_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes9090.00%125.00%
Arjan van de Ven66.00%125.00%
Al Viro22.00%125.00%
Alan Cox22.00%125.00%
Total100100.00%4100.00%

/* ------------------------------------------------------- */ 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;); pr_debug("%s(cmd=0x%X)\n", __func__, 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; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes19493.72%233.33%
Alan Cox104.83%116.67%
Harvey Harrison10.48%116.67%
Stephen Hemminger10.48%116.67%
Joe Perches10.48%116.67%
Total207100.00%6100.00%

/* * 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 */ /* stop the underlying driver */ irtty_stop_receiver(tty, TRUE); if (tty->ops->stop) tty->ops->stop(tty); 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) { ret = -ENOMEM; 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); pr_debug("%s - %s: irda line discipline opened\n", __func__, tty->name); return 0; out_put: sirdev_put_instance(dev); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes16383.16%216.67%
Alan Cox94.59%216.67%
Peter Senna Tschudin73.57%18.33%
Martin Diehl52.55%18.33%
Al Viro52.55%216.67%
Arjan van de Ven42.04%18.33%
Joe Perches10.51%18.33%
Harvey Harrison10.51%18.33%
Yoann Padioleau10.51%18.33%
Total196100.00%12100.00%

/* * 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 */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (tty->ops->stop) tty->ops->stop(tty); kfree(priv); pr_debug("%s - %s: irda line discipline closed\n", __func__, tty->name); }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes5963.44%222.22%
Martin Diehl2122.58%111.11%
Alan Cox88.60%222.22%
Al Viro33.23%222.22%
Joe Perches11.08%111.11%
Harvey Harrison11.08%111.11%
Total93100.00%9100.00%

/* ------------------------------------------------------- */ static struct tty_ldisc_ops 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) net_err_ratelimited("IrDA: can't register line discipline (err = %d)\n", err); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes3797.37%150.00%
Joe Perches12.63%150.00%
Total38100.00%2100.00%


static void __exit irtty_sir_cleanup(void) { int err; if ((err = tty_unregister_ldisc(N_IRDA))) { net_err_ratelimited("%s(), can't unregister line discipline (err = %d)\n", __func__, err); } }

Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes3191.18%125.00%
Harvey Harrison12.94%125.00%
Alexey Dobriyan12.94%125.00%
Joe Perches12.94%125.00%
Total34100.00%4100.00%

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");

Overall Contributors

PersonTokensPropCommitsCommitProp
Jean Tourrilhes151285.09%411.43%
Alan Cox854.78%720.00%
Martin Diehl452.53%12.86%
Russell King281.58%12.86%
Arjan van de Ven211.18%12.86%
Al Viro211.18%38.57%
Andrew Morton170.96%38.57%
Peter Hurley80.45%12.86%
Joe Perches70.39%25.71%
Peter Senna Tschudin70.39%12.86%
Linus Torvalds70.39%25.71%
Harvey Harrison50.28%12.86%
Domen Puncer40.23%12.86%
Stephen Hemminger30.17%25.71%
Tejun Heo30.17%12.86%
Jan Engelhardt10.06%12.86%
Jiri Slaby10.06%12.86%
Alexey Dobriyan10.06%12.86%
Yoann Padioleau10.06%12.86%
Total1777100.00%35100.00%
Directory: drivers/net/irda
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.