📄 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.h>#include <linux/tty_flip.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 = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove? return 0; } if (!cmd && atomic_read(&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; } gig_dbg(DEBUG_CMD, "scheduling IF_LOCK"); 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;}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; } gig_dbg(DEBUG_CMD, "scheduling IF_VER"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); if (cs->cmd_result >= 0) return 0; return cs->cmd_result; default: return -EINVAL; }}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 (atomic_read(&cs->mstate) != MS_LOCKED) return -EBUSY; if (!cs->connected) { err("not connected!"); return -ENODEV; } *arg = 0; return gigaset_enterconfigmode(cs);}/*** the terminal driver ***//* stolen from usbserial and some other tty drivers */static int if_open(struct tty_struct *tty, struct file *filp);static void if_close(struct tty_struct *tty, struct file *filp);static int if_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);static int if_write_room(struct tty_struct *tty);static int if_chars_in_buffer(struct tty_struct *tty);static void if_throttle(struct tty_struct *tty);static void if_unthrottle(struct tty_struct *tty);static void if_set_termios(struct tty_struct *tty, struct termios *old);static int if_tiocmget(struct tty_struct *tty, struct file *file);static int if_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);static int if_write(struct tty_struct *tty, const unsigned char *buf, int count);static 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,#if 0 .break_ctl = serial_break,#endif .tiocmget = if_tiocmget, .tiocmset = if_tiocmset,};static int if_open(struct tty_struct *tty, struct file *filp){ struct cardstate *cs; unsigned long flags; gig_dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, __func__); tty->driver_data = NULL; cs = gigaset_get_cs_by_tty(tty); if (!cs) return -ENODEV; if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? tty->driver_data = cs; ++cs->open_count; if (cs->open_count == 1) { spin_lock_irqsave(&cs->lock, flags); cs->tty = tty; spin_unlock_irqrestore(&cs->lock, flags); tty->low_latency = 1; //FIXME test } mutex_unlock(&cs->mutex); return 0;}static void if_close(struct tty_struct *tty, struct file *filp){ struct cardstate *cs; unsigned long flags; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); mutex_lock(&cs->mutex); if (!cs->open_count) warn("%s: device not opened", __func__); else { if (!--cs->open_count) { spin_lock_irqsave(&cs->lock, flags); cs->tty = NULL; spin_unlock_irqrestore(&cs->lock, flags); } } mutex_unlock(&cs->mutex);}static int if_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ struct cardstate *cs; int retval = -ENODEV; int int_arg; unsigned char buf[6]; unsigned version[4]; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) warn("%s: device not opened", __func__); 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: //FIXME test if MS_LOCKED if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); retval = -ENODEV; break; } 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_ANY, "%s: arg not supported - 0x%04x", __func__, cmd); retval = -ENOIOCTLCMD; } } mutex_unlock(&cs->mutex); return retval;}static int if_tiocmget(struct tty_struct *tty, struct file *file){ struct cardstate *cs; int retval; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? // FIXME read from device? retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR); mutex_unlock(&cs->mutex); return retval;}static int if_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct cardstate *cs; int retval; unsigned mc; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", cs->minor_index, __func__, set, clear); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); 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;}static int if_write(struct tty_struct *tty, const unsigned char *buf, int count){ struct cardstate *cs; int retval = -ENODEV; cs = (struct cardstate *) tty->driver_data; if (!cs) { err("cs==NULL in %s", __func__); return -ENODEV; } gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -