cregit-Linux how code gets into the kernel

Release 4.7 drivers/isdn/gigaset/interface.c

/*
 * interface to user space for the gigaset driver
 *
 * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de>
 *
 * =====================================================================
 *    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.
 * =====================================================================
 */

#include "gigaset.h"
#include <linux/gigaset_dev.h>
#include <linux/tty_flip.h>
#include <linux/module.h>

/*** our ioctls ***/


static int if_lock(struct cardstate *cs, int *arg) { int cmd = *arg; gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); if (cmd > 1) return -EINVAL; if (cmd < 0) { *arg = cs->mstate == MS_LOCKED; return 0; } if (!cmd && cs->mstate == MS_LOCKED && cs->connected) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS); cs->ops->baud_rate(cs, B115200); cs->ops->set_line_ctrl(cs, CS8); cs->control_state = TIOCM_DTR | TIOCM_RTS; } cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK, NULL, cmd, NULL)) { cs->waiting = 0; return -ENOMEM; } gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); if (cs->cmd_result >= 0) { *arg = cs->cmd_result; return 0; } return cs->cmd_result; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp20699.52%150.00%
tilman schmidttilman schmidt10.48%150.00%
Total207100.00%2100.00%


static int if_version(struct cardstate *cs, unsigned arg[4]) { static const unsigned version[4] = GIG_VERSION; static const unsigned compat[4] = GIG_COMPAT; unsigned cmd = arg[0]; gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); switch (cmd) { case GIGVER_DRIVER: memcpy(arg, version, sizeof version); return 0; case GIGVER_COMPAT: memcpy(arg, compat, sizeof compat); return 0; case GIGVER_FWBASE: cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER, NULL, 0, arg)) { cs->waiting = 0; return -ENOMEM; } gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); if (cs->cmd_result >= 0) return 0; return cs->cmd_result; default: return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp17599.43%150.00%
tilman schmidttilman schmidt10.57%150.00%
Total176100.00%2100.00%


static int if_config(struct cardstate *cs, int *arg) { gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg); if (*arg != 1) return -EINVAL; if (cs->mstate != MS_LOCKED) return -EBUSY; if (!cs->connected) { pr_err("%s: not connected\n", __func__); return -ENODEV; } *arg = 0; return gigaset_enterconfigmode(cs); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp6274.70%125.00%
tilman schmidttilman schmidt2125.30%375.00%
Total83100.00%4100.00%

/*** the terminal driver ***/
static int if_open(struct tty_struct *tty, struct file *filp) { struct cardstate *cs; gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); cs = gigaset_get_cs_by_tty(tty); if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; if (mutex_lock_interruptible(&cs->mutex)) { module_put(cs->driver->owner); return -ERESTARTSYS; } tty->driver_data = cs; ++cs->port.count; if (cs->port.count == 1) { tty_port_tty_set(&cs->port, tty); cs->port.low_latency = 1; } mutex_unlock(&cs->mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp10773.79%114.29%
tilman schmidttilman schmidt1611.03%342.86%
jiri slabyjiri slaby117.59%228.57%
pavel shvedpavel shved117.59%114.29%
Total145100.00%7100.00%


static void if_close(struct tty_struct *tty, struct file *filp) { struct cardstate *cs = tty->driver_data; if (!cs) { /* happens if we didn't find cs in open */ gig_dbg(DEBUG_IF, "%s: no cardstate", __func__); return; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ else if (!cs->port.count) dev_warn(cs->dev, "%s: device not opened\n", __func__); else if (!--cs->port.count) tty_port_tty_set(&cs->port, NULL); mutex_unlock(&cs->mutex); module_put(cs->driver->owner); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp8158.70%111.11%
tilman schmidttilman schmidt4331.16%666.67%
jiri slabyjiri slaby1410.14%222.22%
Total138100.00%9100.00%


static int if_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct cardstate *cs = tty->driver_data; int retval = -ENODEV; int int_arg; unsigned char buf[6]; unsigned version[4]; gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else { retval = 0; switch (cmd) { case GIGASET_REDIR: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_lock(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_CONFIG: retval = get_user(int_arg, (int __user *) arg); if (retval >= 0) retval = if_config(cs, &int_arg); if (retval >= 0) retval = put_user(int_arg, (int __user *) arg); break; case GIGASET_BRKCHARS: retval = copy_from_user(&buf, (const unsigned char __user *) arg, 6) ? -EFAULT : 0; if (retval >= 0) { gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", 6, (const unsigned char *) arg); retval = cs->ops->brkchars(cs, buf); } break; case GIGASET_VERSION: retval = copy_from_user(version, (unsigned __user *) arg, sizeof version) ? -EFAULT : 0; if (retval >= 0) retval = if_version(cs, version); if (retval >= 0) retval = copy_to_user((unsigned __user *) arg, version, sizeof version) ? -EFAULT : 0; break; default: gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x", __func__, cmd); retval = -ENOIOCTLCMD; } } mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp33687.50%114.29%
tilman schmidttilman schmidt4411.46%571.43%
jiri slabyjiri slaby41.04%114.29%
Total384100.00%7100.00%


static int if_tiocmget(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; int retval; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; retval = cs->control_state & (TIOCM_RTS | TIOCM_DTR); mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp6386.30%125.00%
tilman schmidttilman schmidt68.22%250.00%
jiri slabyjiri slaby45.48%125.00%
Total73100.00%4100.00%


static int if_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct cardstate *cs = tty->driver_data; int retval; unsigned mc; gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", cs->minor_index, __func__, set, clear); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else { mc = (cs->control_state | set) & ~clear & (TIOCM_RTS | TIOCM_DTR); retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc); cs->control_state = mc; } mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp12990.85%120.00%
tilman schmidttilman schmidt96.34%360.00%
jiri slabyjiri slaby42.82%120.00%
Total142100.00%5100.00%


static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct cardstate *cs = tty->driver_data; struct cmdbuf_t *cb; int retval; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; goto done; } if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; goto done; } if (count <= 0) { /* nothing to do */ retval = 0; goto done; } cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL); if (!cb) { dev_err(cs->dev, "%s: out of memory\n", __func__); retval = -ENOMEM; goto done; } memcpy(cb->buf, buf, count); cb->len = count; cb->offset = 0; cb->next = NULL; cb->wake_tasklet = &cs->if_wake_tasklet; retval = cs->ops->write_cmd(cs, cb); done: mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
tilman schmidttilman schmidt13557.20%571.43%
hansjoerg lipphansjoerg lipp9741.10%114.29%
jiri slabyjiri slaby41.69%114.29%
Total236100.00%7100.00%


static int if_write_room(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; int retval; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); retval = -ENODEV; } else if (cs->mstate != MS_LOCKED) { dev_warn(cs->dev, "can't write to unlocked device\n"); retval = -EBUSY; } else retval = cs->ops->write_room(cs); mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp8470.59%116.67%
tilman schmidttilman schmidt3126.05%466.67%
jiri slabyjiri slaby43.36%116.67%
Total119100.00%6100.00%


static int if_chars_in_buffer(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; int retval = 0; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); else if (cs->mstate != MS_LOCKED) dev_warn(cs->dev, "can't write to unlocked device\n"); else retval = cs->ops->chars_in_buffer(cs); mutex_unlock(&cs->mutex); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp7170.30%114.29%
tilman schmidttilman schmidt2625.74%571.43%
jiri slabyjiri slaby43.96%114.29%
Total101100.00%7100.00%


static void if_throttle(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ else gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); mutex_unlock(&cs->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp4763.51%114.29%
tilman schmidttilman schmidt2533.78%571.43%
jiri slabyjiri slaby22.70%114.29%
Total74100.00%7100.00%


static void if_unthrottle(struct tty_struct *tty) { struct cardstate *cs = tty->driver_data; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ else gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); mutex_unlock(&cs->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp4763.51%114.29%
tilman schmidttilman schmidt2533.78%571.43%
jiri slabyjiri slaby22.70%114.29%
Total74100.00%7100.00%


static void if_set_termios(struct tty_struct *tty, struct ktermios *old) { struct cardstate *cs = tty->driver_data; unsigned int iflag; unsigned int cflag; unsigned int old_cflag; unsigned int control_state, new_state; gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->connected) { gig_dbg(DEBUG_IF, "not connected"); goto out; } iflag = tty->termios.c_iflag; cflag = tty->termios.c_cflag; old_cflag = old ? old->c_cflag : cflag; gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index, iflag, cflag, old_cflag); /* get a local copy of the current port settings */ control_state = cs->control_state; /* * Update baud rate. * Do not attempt to cache old rates and skip settings, * disconnects screw such tricks up completely. * Premature optimization is the root of all evil. */ /* reassert DTR and (maybe) RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { new_state = control_state | TIOCM_DTR; /* don't set RTS if using hardware flow control */ if (!(old_cflag & CRTSCTS)) new_state |= TIOCM_RTS; gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index, (new_state & TIOCM_RTS) ? " only" : "/RTS"); cs->ops->set_modem_ctrl(cs, control_state, new_state); control_state = new_state; } cs->ops->baud_rate(cs, cflag & CBAUD); if ((cflag & CBAUD) == B0) { /* Drop RTS and DTR */ gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index); new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS); cs->ops->set_modem_ctrl(cs, control_state, new_state); control_state = new_state; } /* * Update line control register (LCR) */ cs->ops->set_line_ctrl(cs, cflag); /* save off the modified port settings */ cs->control_state = control_state; out: mutex_unlock(&cs->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp27993.31%114.29%
tilman schmidttilman schmidt134.35%342.86%
jiri slabyjiri slaby41.34%114.29%
alan coxalan cox31.00%228.57%
Total299100.00%7100.00%

static const struct tty_operations if_ops = { .open = if_open, .close = if_close, .ioctl = if_ioctl, .write = if_write, .write_room = if_write_room, .chars_in_buffer = if_chars_in_buffer, .set_termios = if_set_termios, .throttle = if_throttle, .unthrottle = if_unthrottle, .tiocmget = if_tiocmget, .tiocmset = if_tiocmset, }; /* wakeup tasklet for the write operation */
static void if_wake(unsigned long data) { struct cardstate *cs = (struct cardstate *)data; tty_port_tty_wakeup(&cs->port); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp2480.00%125.00%
jiri slabyjiri slaby620.00%375.00%
Total30100.00%4100.00%

/*** interface to common ***/
void gigaset_if_init(struct cardstate *cs) { struct gigaset_driver *drv; drv = cs->driver; if (!drv->have_tty) return; tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs); mutex_lock(&cs->mutex); cs->tty_dev = tty_port_register_device(&cs->port, drv->tty, cs->minor_index, NULL); if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); else { pr_warning("could not register device to the tty subsystem\n"); cs->tty_dev = NULL; } mutex_unlock(&cs->mutex); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp8775.00%228.57%
tilman schmidttilman schmidt1815.52%342.86%
jiri slabyjiri slaby65.17%114.29%
greg kroah-hartmangreg kroah-hartman54.31%114.29%
Total116100.00%7100.00%


void gigaset_if_free(struct cardstate *cs) { struct gigaset_driver *drv; drv = cs->driver; if (!drv->have_tty) return; tasklet_disable(&cs->if_wake_tasklet); tasklet_kill(&cs->if_wake_tasklet); cs->tty_dev = NULL; tty_unregister_device(drv->tty, cs->minor_index); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp6198.39%266.67%
greg kroah-hartmangreg kroah-hartman11.61%133.33%
Total62100.00%3100.00%

/** * gigaset_if_receive() - pass a received block of data to the tty device * @cs: device descriptor structure. * @buffer: received data. * @len: number of bytes received. * * Called by asyncdata/isocdata if a block of data received from the * device must be sent to userspace through the ttyG* device. */
void gigaset_if_receive(struct cardstate *cs, unsigned char *buffer, size_t len) { tty_insert_flip_string(&cs->port, buffer, len); tty_flip_buffer_push(&cs->port); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp3386.84%133.33%
jiri slabyjiri slaby513.16%266.67%
Total38100.00%3100.00%

EXPORT_SYMBOL_GPL(gigaset_if_receive); /* gigaset_if_initdriver * Initialize tty interface. * parameters: * drv Driver * procname Name of the driver (e.g. for /proc/tty/drivers) * devname Name of the device files (prefix without minor number) */
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, const char *devname) { int ret; struct tty_driver *tty; drv->have_tty = 0; drv->tty = tty = alloc_tty_driver(drv->minors); if (tty == NULL) goto enomem; tty->type = TTY_DRIVER_TYPE_SERIAL; tty->subtype = SERIAL_TYPE_NORMAL; tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty->driver_name = procname; tty->name = devname; tty->minor_start = drv->minor; tty->init_termios = tty_std_termios; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(tty, &if_ops); ret = tty_register_driver(tty); if (ret < 0) { pr_err("error %d registering tty driver\n", ret); goto error; } gig_dbg(DEBUG_IF, "tty driver initialized"); drv->have_tty = 1; return; enomem: pr_err("out of memory\n"); error: if (drv->tty) put_tty_driver(drv->tty); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp17090.91%114.29%
tilman schmidttilman schmidt115.88%342.86%
joe perchesjoe perches21.07%114.29%
greg kroah-hartmangreg kroah-hartman21.07%114.29%
jiri slabyjiri slaby21.07%114.29%
Total187100.00%7100.00%


void gigaset_if_freedriver(struct gigaset_driver *drv) { if (!drv->have_tty) return; drv->have_tty = 0; tty_unregister_driver(drv->tty); put_tty_driver(drv->tty); }

Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp38100.00%1100.00%
Total38100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
hansjoerg lipphansjoerg lipp221578.85%25.56%
tilman schmidttilman schmidt49017.44%1850.00%
jiri slabyjiri slaby762.71%822.22%
pavel shvedpavel shved110.39%12.78%
greg kroah-hartmangreg kroah-hartman90.32%38.33%
alan coxalan cox30.11%25.56%
paul gortmakerpaul gortmaker30.11%12.78%
joe perchesjoe perches20.07%12.78%
Total2809100.00%36100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}