From 19b1e7695be8cbdf14e85ddefc9c5a9d3e88bdfd Mon Sep 17 00:00:00 2001 From: Kristina Martšenko Date: Tue, 1 Jul 2014 02:14:02 +0300 Subject: staging: dgrp: remove driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the driver as it hasn't been cleaned up and it doesn't look like anyone is going to work on it anymore. This can be reverted if someone wants to work to fix the remaining issues the driver has. Signed-off-by: Kristina Martšenko Cc: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/dgrp/Kconfig | 9 - drivers/staging/dgrp/Makefile | 12 - drivers/staging/dgrp/README | 2 - drivers/staging/dgrp/TODO | 13 - drivers/staging/dgrp/dgrp_common.c | 169 -- drivers/staging/dgrp/dgrp_common.h | 150 -- drivers/staging/dgrp/dgrp_dpa_ops.c | 534 ----- drivers/staging/dgrp/dgrp_driver.c | 105 - drivers/staging/dgrp/dgrp_mon_ops.c | 327 --- drivers/staging/dgrp/dgrp_net_ops.c | 3666 --------------------------------- drivers/staging/dgrp/dgrp_ports_ops.c | 156 -- drivers/staging/dgrp/dgrp_specproc.c | 541 ----- drivers/staging/dgrp/dgrp_sysfs.c | 558 ----- drivers/staging/dgrp/dgrp_tty.c | 3337 ------------------------------ drivers/staging/dgrp/digirp.h | 129 -- drivers/staging/dgrp/drp.h | 693 ------- 18 files changed, 10404 deletions(-) delete mode 100644 drivers/staging/dgrp/Kconfig delete mode 100644 drivers/staging/dgrp/Makefile delete mode 100644 drivers/staging/dgrp/README delete mode 100644 drivers/staging/dgrp/TODO delete mode 100644 drivers/staging/dgrp/dgrp_common.c delete mode 100644 drivers/staging/dgrp/dgrp_common.h delete mode 100644 drivers/staging/dgrp/dgrp_dpa_ops.c delete mode 100644 drivers/staging/dgrp/dgrp_driver.c delete mode 100644 drivers/staging/dgrp/dgrp_mon_ops.c delete mode 100644 drivers/staging/dgrp/dgrp_net_ops.c delete mode 100644 drivers/staging/dgrp/dgrp_ports_ops.c delete mode 100644 drivers/staging/dgrp/dgrp_specproc.c delete mode 100644 drivers/staging/dgrp/dgrp_sysfs.c delete mode 100644 drivers/staging/dgrp/dgrp_tty.c delete mode 100644 drivers/staging/dgrp/digirp.h delete mode 100644 drivers/staging/dgrp/drp.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 85dde86e8965..91ebf62497bc 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -114,8 +114,6 @@ source "drivers/staging/ced1401/Kconfig" source "drivers/staging/imx-drm/Kconfig" -source "drivers/staging/dgrp/Kconfig" - source "drivers/staging/fwserial/Kconfig" source "drivers/staging/goldfish/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 59e5e0968a1a..a1e0b1c5f72f 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ obj-$(CONFIG_CED1401) += ced1401/ obj-$(CONFIG_DRM_IMX) += imx-drm/ -obj-$(CONFIG_DGRP) += dgrp/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_LUSTRE_FS) += lustre/ diff --git a/drivers/staging/dgrp/Kconfig b/drivers/staging/dgrp/Kconfig deleted file mode 100644 index e4c41552923a..000000000000 --- a/drivers/staging/dgrp/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config DGRP - tristate "Digi Realport driver" - default n - depends on SYSFS && TTY - ---help--- - Support for Digi Realport devices. These devices allow you to - access remote serial ports as if they are local tty devices. This - will build the kernel driver, you will still need the userspace - component to make your Realport device work. diff --git a/drivers/staging/dgrp/Makefile b/drivers/staging/dgrp/Makefile deleted file mode 100644 index d9c3b88d7162..000000000000 --- a/drivers/staging/dgrp/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_DGRP) += dgrp.o - -dgrp-y := \ - dgrp_common.o \ - dgrp_dpa_ops.o \ - dgrp_driver.o \ - dgrp_mon_ops.o \ - dgrp_net_ops.o \ - dgrp_ports_ops.o \ - dgrp_specproc.o \ - dgrp_tty.o \ - dgrp_sysfs.o diff --git a/drivers/staging/dgrp/README b/drivers/staging/dgrp/README deleted file mode 100644 index 1d8aaee270e8..000000000000 --- a/drivers/staging/dgrp/README +++ /dev/null @@ -1,2 +0,0 @@ -The user space code to work with this driver is located at -https://github.com/wfp5p/dgrp-utils diff --git a/drivers/staging/dgrp/TODO b/drivers/staging/dgrp/TODO deleted file mode 100644 index 3ef2611bc6d7..000000000000 --- a/drivers/staging/dgrp/TODO +++ /dev/null @@ -1,13 +0,0 @@ -- Use configfs for config stuff. This will require changes to the - user space code. - -- dgrp_send() and dgrp_receive() could use some refactoring - -- Don't automatically create CHAN_MAX (64) channel array entries for - every device as many devices are going to have much less than 64 - channels. - -- The locking needs to be checked. It seems haphazardly done in most - places. - -- Check Kconfig dependencies diff --git a/drivers/staging/dgrp/dgrp_common.c b/drivers/staging/dgrp/dgrp_common.c deleted file mode 100644 index 9a9b45624ba9..000000000000 --- a/drivers/staging/dgrp/dgrp_common.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_common.c - * - * Description: - * - * Definitions of global variables and functions which are either - * shared by the tty, mon, and net drivers; or which cross them - * functionally (like the poller). - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include - -#include "dgrp_common.h" - -/** - * dgrp_carrier -- check for carrier change state and act - * @ch: struct ch_struct * - */ -void dgrp_carrier(struct ch_struct *ch) -{ - struct nd_struct *nd; - - int virt_carrier = 0; - int phys_carrier = 0; - - /* fix case when the tty has already closed. */ - - if (!ch) - return; - nd = ch->ch_nd; - if (!nd) - return; - - /* - * If we are currently waiting to determine the status of the port, - * we don't yet know the state of the modem lines. As a result, - * we ignore state changes when we are waiting for the modem lines - * to be established. We know, as a result of code in dgrp_net_ops, - * that we will be called again immediately following the reception - * of the status message with the true modem status flags in it. - */ - if (ch->ch_expect & RR_STATUS) - return; - - /* - * If CH_HANGUP is set, we gotta keep trying to get all the processes - * that have the port open to close the port. - * So lets just keep sending a hangup every time we get here. - */ - if ((ch->ch_flag & CH_HANGUP) && - (ch->ch_tun.un_open_count > 0)) - tty_hangup(ch->ch_tun.un_tty); - - /* - * Compute the effective state of both the physical and virtual - * senses of carrier. - */ - - if (ch->ch_s_mlast & DM_CD) - phys_carrier = 1; - - if ((ch->ch_s_mlast & DM_CD) || - (ch->ch_digi.digi_flags & DIGI_FORCEDCD) || - (ch->ch_flag & CH_CLOCAL)) - virt_carrier = 1; - - /* - * Test for a VIRTUAL carrier transition to HIGH. - * - * The CH_HANGUP condition is intended to prevent any action - * except for close. As a result, we ignore positive carrier - * transitions during CH_HANGUP. - */ - if (((ch->ch_flag & CH_HANGUP) == 0) && - ((ch->ch_flag & CH_VIRT_CD) == 0) && - (virt_carrier == 1)) { - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - nd->nd_tx_work = 1; - - if (waitqueue_active(&ch->ch_flag_wait)) - wake_up_interruptible(&ch->ch_flag_wait); - } - - /* - * Test for a PHYSICAL transition to low, so long as we aren't - * currently ignoring physical transitions (which is what "virtual - * carrier" indicates). - * - * The transition of the virtual carrier to low really doesn't - * matter... it really only means "ignore carrier state", not - * "make pretend that carrier is there". - */ - if ((virt_carrier == 0) && - ((ch->ch_flag & CH_PHYS_CD) != 0) && - (phys_carrier == 0)) { - /* - * When carrier drops: - * - * Do a Hard Hangup if that is called for. - * - * Drop carrier on all open units. - * - * Flush queues, waking up any task waiting in the - * line discipline. - * - * Send a hangup to the control terminal. - * - * Enable all select calls. - */ - - nd->nd_tx_work = 1; - - ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT); - - if (waitqueue_active(&ch->ch_flag_wait)) - wake_up_interruptible(&ch->ch_flag_wait); - - if (ch->ch_tun.un_open_count > 0) - tty_hangup(ch->ch_tun.un_tty); - - if (ch->ch_pun.un_open_count > 0) - tty_hangup(ch->ch_pun.un_tty); - } - - /* - * Make sure that our cached values reflect the current reality. - */ - if (virt_carrier == 1) - ch->ch_flag |= CH_VIRT_CD; - else - ch->ch_flag &= ~CH_VIRT_CD; - - if (phys_carrier == 1) - ch->ch_flag |= CH_PHYS_CD; - else - ch->ch_flag &= ~CH_PHYS_CD; - -} diff --git a/drivers/staging/dgrp/dgrp_common.h b/drivers/staging/dgrp/dgrp_common.h deleted file mode 100644 index 23aba6c4d22c..000000000000 --- a/drivers/staging/dgrp/dgrp_common.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -#ifndef __DGRP_COMMON_H -#define __DGRP_COMMON_H - -#define DIGI_VERSION "1.9-29" - -#include -#include -#include "drp.h" - -#define DGRP_TTIME 100 -#define DGRP_RTIME 100 - -/************************************************************************ - * All global storage allocation. - ************************************************************************/ - -extern int dgrp_register_cudevices; /* enable legacy cu devices */ -extern int dgrp_register_prdevices; /* enable transparent print devices */ -extern int dgrp_poll_tick; /* Poll interval - in ms */ - -extern struct list_head nd_struct_list; - -struct dgrp_poll_data { - spinlock_t poll_lock; - struct timer_list timer; - int poll_tick; - ulong poll_round; /* Timer rouding factor */ - long node_active_count; -}; - -extern struct dgrp_poll_data dgrp_poll_data; -extern void dgrp_poll_handler(unsigned long arg); - -/* from dgrp_mon_ops.c */ -extern const struct file_operations dgrp_mon_ops; - -/* from dgrp_tty.c */ -extern int dgrp_tty_init(struct nd_struct *nd); -extern void dgrp_tty_uninit(struct nd_struct *nd); - -/* from dgrp_ports_ops.c */ -extern const struct file_operations dgrp_ports_ops; - -/* from dgrp_net_ops.c */ -extern const struct file_operations dgrp_net_ops; - -/* from dgrp_dpa_ops.c */ -extern const struct file_operations dgrp_dpa_ops; -extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int); - -/* from dgrp_sysfs.c */ -extern int dgrp_create_class_sysfs_files(void); -extern void dgrp_remove_class_sysfs_files(void); - -extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd); -extern void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd); - -extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c); -extern void dgrp_remove_tty_sysfs(struct device *c); - -/* from dgrp_specproc.c */ -extern void dgrp_unregister_proc(void); -extern void dgrp_register_proc(void); - -/*-----------------------------------------------------------------------* - * - * Declarations for common operations: - * - * (either used by more than one of net, mon, or tty, - * or in interrupt context (i.e. the poller)) - * - *-----------------------------------------------------------------------*/ - -void dgrp_carrier(struct ch_struct *ch); - - -/* - * ID manipulation macros (where c1 & c2 are characters, i is - * a long integer, and s is a character array of at least three members - */ - -static inline void ID_TO_CHAR(long i, char *s) -{ - s[0] = ((i & 0xff00)>>8); - s[1] = (i & 0xff); - s[2] = 0; -} - -static inline long CHAR_TO_ID(char *s) -{ - return ((s[0] & 0xff) << 8) | (s[1] & 0xff); -} - -static inline struct nd_struct *nd_struct_get(long major) -{ - struct nd_struct *nd; - - list_for_each_entry(nd, &nd_struct_list, list) { - if (major == nd->nd_major) - return nd; - } - - return NULL; -} - -static inline int nd_struct_add(struct nd_struct *entry) -{ - struct nd_struct *ptr; - - ptr = nd_struct_get(entry->nd_major); - - if (ptr) - return -EBUSY; - - list_add_tail(&entry->list, &nd_struct_list); - - return 0; -} - -static inline int nd_struct_del(struct nd_struct *entry) -{ - struct nd_struct *nd; - - nd = nd_struct_get(entry->nd_major); - - if (!nd) - return -ENODEV; - - list_del(&nd->list); - return 0; -} - -#endif /* __DGRP_COMMON_H */ diff --git a/drivers/staging/dgrp/dgrp_dpa_ops.c b/drivers/staging/dgrp/dgrp_dpa_ops.c deleted file mode 100644 index 69bfe309376d..000000000000 --- a/drivers/staging/dgrp/dgrp_dpa_ops.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_dpa_ops.c - * - * Description: - * - * Handle the file operations required for the "dpa" devices. - * Includes those functions required to register the "dpa" devices - * in "/proc". - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dgrp_common.h" - -/* File operation declarations */ -static int dgrp_dpa_open(struct inode *, struct file *); -static int dgrp_dpa_release(struct inode *, struct file *); -static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *); -static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *); - -const struct file_operations dgrp_dpa_ops = { - .owner = THIS_MODULE, - .read = dgrp_dpa_read, - .poll = dgrp_dpa_select, - .unlocked_ioctl = dgrp_dpa_ioctl, - .open = dgrp_dpa_open, - .release = dgrp_dpa_release, -}; - -struct digi_node { - uint nd_state; /* Node state: 1 = up, 0 = down. */ - uint nd_chan_count; /* Number of channels found */ - uint nd_tx_byte; /* Tx data count */ - uint nd_rx_byte; /* RX data count */ - u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */ -}; - -#define DIGI_GETNODE (('d'<<8) | 249) /* get board info */ - - -struct digi_chan { - uint ch_port; /* Port number to get info on */ - uint ch_open; /* 1 if open, 0 if not */ - uint ch_txcount; /* TX data count */ - uint ch_rxcount; /* RX data count */ - uint ch_s_brate; /* Realport BRATE */ - uint ch_s_estat; /* Realport ELAST */ - uint ch_s_cflag; /* Realport CFLAG */ - uint ch_s_iflag; /* Realport IFLAG */ - uint ch_s_oflag; /* Realport OFLAG */ - uint ch_s_xflag; /* Realport XFLAG */ - uint ch_s_mstat; /* Realport MLAST */ -}; - -#define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */ - - -struct digi_vpd { - int vpd_len; - char vpd_data[VPDSIZE]; -}; - -#define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */ - - -struct digi_debug { - int onoff; - int port; -}; - -#define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */ - - -/* - * dgrp_dpa_open -- open the DPA device for a particular PortServer - */ -static int dgrp_dpa_open(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - int rtn = 0; - - rtn = try_module_get(THIS_MODULE); - if (!rtn) - return -ENXIO; - - rtn = 0; - - if (!capable(CAP_SYS_ADMIN)) { - rtn = -EPERM; - goto done; - } - - /* - * Make sure that the "private_data" field hasn't already been used. - */ - if (file->private_data) { - rtn = -EINVAL; - goto done; - } - - /* - * Get the node pointer, and fail if it doesn't exist. - */ - nd = PDE_DATA(inode); - if (!nd) { - rtn = -ENXIO; - goto done; - } - - file->private_data = (void *) nd; - - /* - * Allocate the DPA buffer. - */ - - if (nd->nd_dpa_buf) { - rtn = -EBUSY; - } else { - nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL); - - if (!nd->nd_dpa_buf) { - rtn = -ENOMEM; - } else { - nd->nd_dpa_out = 0; - nd->nd_dpa_in = 0; - nd->nd_dpa_lbolt = jiffies; - } - } - -done: - - if (rtn) - module_put(THIS_MODULE); - return rtn; -} - -/* - * dgrp_dpa_release -- close the DPA device for a particular PortServer - */ -static int dgrp_dpa_release(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - u8 *buf; - unsigned long lock_flags; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - goto done; - - /* - * Free the dpa buffer. - */ - - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - - buf = nd->nd_dpa_buf; - - nd->nd_dpa_buf = NULL; - nd->nd_dpa_out = nd->nd_dpa_in; - - /* - * Wakeup any thread waiting for buffer space. - */ - - if (nd->nd_dpa_flag & DPA_WAIT_SPACE) { - nd->nd_dpa_flag &= ~DPA_WAIT_SPACE; - wake_up_interruptible(&nd->nd_dpa_wqueue); - } - - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - - kfree(buf); - -done: - module_put(THIS_MODULE); - file->private_data = NULL; - return 0; -} - -/* - * dgrp_dpa_read - * - * Copy data from the monitoring buffer to the user, freeing space - * in the monitoring buffer for more messages - */ -static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct nd_struct *nd; - int n; - int r; - int offset = 0; - int res = 0; - ssize_t rtn; - unsigned long lock_flags; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - return -ENXIO; - - /* - * Wait for some data to appear in the buffer. - */ - - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - - for (;;) { - n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK; - - if (n != 0) - break; - - nd->nd_dpa_flag |= DPA_WAIT_DATA; - - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - - /* - * Go to sleep waiting until the condition becomes true. - */ - rtn = wait_event_interruptible(nd->nd_dpa_wqueue, - ((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0)); - - if (rtn) - return rtn; - - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - } - - /* - * Read whatever is there. - */ - - if (n > count) - n = count; - - res = n; - - r = DPA_MAX - nd->nd_dpa_out; - - if (r <= n) { - - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - rtn = copy_to_user((void __user *)buf, - nd->nd_dpa_buf + nd->nd_dpa_out, r); - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - - if (rtn) { - rtn = -EFAULT; - goto done; - } - - nd->nd_dpa_out = 0; - n -= r; - offset = r; - } - - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - rtn = copy_to_user((void __user *)buf + offset, - nd->nd_dpa_buf + nd->nd_dpa_out, n); - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - - if (rtn) { - rtn = -EFAULT; - goto done; - } - - nd->nd_dpa_out += n; - - *ppos += res; - - rtn = res; - - /* - * Wakeup any thread waiting for buffer space. - */ - - n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK; - - if (nd->nd_dpa_flag & DPA_WAIT_SPACE && - (DPA_MAX - n) > DPA_HIGH_WATER) { - nd->nd_dpa_flag &= ~DPA_WAIT_SPACE; - wake_up_interruptible(&nd->nd_dpa_wqueue); - } - - done: - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - return rtn; -} - -static unsigned int dgrp_dpa_select(struct file *file, - struct poll_table_struct *table) -{ - unsigned int retval = 0; - struct nd_struct *nd = file->private_data; - - if (nd->nd_dpa_out != nd->nd_dpa_in) - retval |= POLLIN | POLLRDNORM; /* Conditionally readable */ - - retval |= POLLOUT | POLLWRNORM; /* Always writeable */ - - return retval; -} - -static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - - struct nd_struct *nd; - struct digi_chan getchan; - struct digi_node getnode; - struct ch_struct *ch; - struct digi_debug setdebug; - struct digi_vpd vpd; - unsigned int port; - void __user *uarg = (void __user *) arg; - - nd = file->private_data; - - switch (cmd) { - case DIGI_GETCHAN: - if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan))) - return -EFAULT; - - port = getchan.ch_port; - - if (port > nd->nd_chan_count) - return -EINVAL; - - ch = nd->nd_chan + port; - - getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0; - getchan.ch_txcount = ch->ch_txcount; - getchan.ch_rxcount = ch->ch_rxcount; - getchan.ch_s_brate = ch->ch_s_brate; - getchan.ch_s_estat = ch->ch_s_elast; - getchan.ch_s_cflag = ch->ch_s_cflag; - getchan.ch_s_iflag = ch->ch_s_iflag; - getchan.ch_s_oflag = ch->ch_s_oflag; - getchan.ch_s_xflag = ch->ch_s_xflag; - getchan.ch_s_mstat = ch->ch_s_mlast; - - if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan))) - return -EFAULT; - break; - - - case DIGI_GETNODE: - getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0; - getnode.nd_chan_count = nd->nd_chan_count; - getnode.nd_tx_byte = nd->nd_tx_byte; - getnode.nd_rx_byte = nd->nd_rx_byte; - - memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN); - strlcpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN); - - if (copy_to_user(uarg, &getnode, sizeof(struct digi_node))) - return -EFAULT; - break; - - - case DIGI_SETDEBUG: - if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug))) - return -EFAULT; - - nd->nd_dpa_debug = setdebug.onoff; - nd->nd_dpa_port = setdebug.port; - break; - - - case DIGI_GETVPD: - memset(&vpd, 0, sizeof(vpd)); - if (nd->nd_vpd_len > 0) { - vpd.vpd_len = nd->nd_vpd_len; - memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len); - } else { - vpd.vpd_len = 0; - } - - if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd))) - return -EFAULT; - break; - } - - return 0; -} - -/** - * dgrp_dpa() -- send data to the device monitor queue - * @nd: pointer to a node structure - * @buf: buffer of data to copy to the monitoring buffer - * @len: number of bytes to transfer to the buffer - * - * Called by the net device routines to send data to the device - * monitor queue. If the device monitor buffer is too full to - * accept the data, it waits until the buffer is ready. - */ -static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf) -{ - int n; - int r; - unsigned long lock_flags; - - /* - * Grab DPA lock. - */ - spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); - - /* - * Loop while data remains. - */ - while (nbuf > 0 && nd->nd_dpa_buf != NULL) { - - n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK; - - /* - * Enforce flow control on the DPA device. - */ - if (n < (DPA_MAX - DPA_HIGH_WATER)) - nd->nd_dpa_flag |= DPA_WAIT_SPACE; - - /* - * This should never happen, as the flow control above - * should have stopped things before they got to this point. - */ - if (n == 0) { - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); - return; - } - - /* - * Copy as much data as will fit. - */ - - if (n > nbuf) - n = nbuf; - - r = DPA_MAX - nd->nd_dpa_in; - - if (r <= n) { - memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r); - - n -= r; - - nd->nd_dpa_in = 0; - - buf += r; - nbuf -= r; - } - - memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n); - - nd->nd_dpa_in += n; - - buf += n; - nbuf -= n; - - if (nd->nd_dpa_in >= DPA_MAX) - pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n", - __func__, nd->nd_dpa_in); - - /* - * Wakeup any thread waiting for data - */ - if (nd->nd_dpa_flag & DPA_WAIT_DATA) { - nd->nd_dpa_flag &= ~DPA_WAIT_DATA; - wake_up_interruptible(&nd->nd_dpa_wqueue); - } - } - - /* - * Release the DPA lock. - */ - spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); -} - -/** - * dgrp_monitor_data() -- builds a DPA data packet - * @nd: pointer to a node structure - * @type: type of message to be logged in the DPA buffer - * @buf: buffer of data to be logged in the DPA buffer - * @size -- number of bytes in the "buf" buffer - */ -void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size) -{ - u8 header[5]; - - header[0] = type; - - put_unaligned_be32(size, header + 1); - - dgrp_dpa(nd, header, sizeof(header)); - dgrp_dpa(nd, buf, size); -} diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c deleted file mode 100644 index b60a8da6350a..000000000000 --- a/drivers/staging/dgrp/dgrp_driver.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Copyright 1999-2003 Digi International (www.digi.com) - * Jeff Randall - * James Puzzo - * Scott Kilau - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * Driver specific includes - */ -#include -#include -#include - -/* - * PortServer includes - */ -#include "dgrp_common.h" - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("RealPort driver for Digi's ethernet-based serial connectivity product line"); -MODULE_VERSION(DIGI_VERSION); - -struct list_head nd_struct_list; -struct dgrp_poll_data dgrp_poll_data; - -int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */ -int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */ -int dgrp_poll_tick = 20; /* Poll interval - in ms */ - -module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644); -MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices"); - -module_param_named(register_prdevices, dgrp_register_prdevices, int, 0644); -MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print devices"); - -module_param_named(pollrate, dgrp_poll_tick, int, 0644); -MODULE_PARM_DESC(pollrate, "Poll interval in ms"); - -/* - * init_module() - * - * Module load. This is where it all starts. - */ -static int __init dgrp_init_module(void) -{ - int ret; - - INIT_LIST_HEAD(&nd_struct_list); - - spin_lock_init(&dgrp_poll_data.poll_lock); - init_timer(&dgrp_poll_data.timer); - dgrp_poll_data.poll_tick = dgrp_poll_tick; - dgrp_poll_data.timer.function = dgrp_poll_handler; - dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data; - - ret = dgrp_create_class_sysfs_files(); - if (ret) - return ret; - - dgrp_register_proc(); - - return 0; -} - - -/* - * Module unload. This is where it all ends. - */ -static void __exit dgrp_cleanup_module(void) -{ - struct nd_struct *nd, *next; - - /* - * Attempting to free resources in backwards - * order of allocation, in case that helps - * memory pool fragmentation. - */ - dgrp_unregister_proc(); - - dgrp_remove_class_sysfs_files(); - - - list_for_each_entry_safe(nd, next, &nd_struct_list, list) { - dgrp_tty_uninit(nd); - kfree(nd); - } -} - -module_init(dgrp_init_module); -module_exit(dgrp_cleanup_module); diff --git a/drivers/staging/dgrp/dgrp_mon_ops.c b/drivers/staging/dgrp/dgrp_mon_ops.c deleted file mode 100644 index d18be4180e3b..000000000000 --- a/drivers/staging/dgrp/dgrp_mon_ops.c +++ /dev/null @@ -1,327 +0,0 @@ -/***************************************************************************** - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_mon_ops.c - * - * Description: - * - * Handle the file operations required for the "monitor" devices. - * Includes those functions required to register the "mon" devices - * in "/proc". - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "dgrp_common.h" - -/* File operation declarations */ -static int dgrp_mon_open(struct inode *, struct file *); -static int dgrp_mon_release(struct inode *, struct file *); -static ssize_t dgrp_mon_read(struct file *, char __user *, size_t, loff_t *); -static long dgrp_mon_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); - -const struct file_operations dgrp_mon_ops = { - .owner = THIS_MODULE, - .read = dgrp_mon_read, - .unlocked_ioctl = dgrp_mon_ioctl, - .open = dgrp_mon_open, - .release = dgrp_mon_release, -}; - -/** - * dgrp_mon_open() -- open /proc/dgrp/ports device for a PortServer - * @inode: struct inode * - * @file: struct file * - * - * Open function to open the /proc/dgrp/ports device for a PortServer. - */ -static int dgrp_mon_open(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - struct timeval tv; - uint32_t time; - u8 *buf; - int rtn; - - rtn = try_module_get(THIS_MODULE); - if (!rtn) - return -ENXIO; - - rtn = 0; - - if (!capable(CAP_SYS_ADMIN)) { - rtn = -EPERM; - goto done; - } - - /* - * Make sure that the "private_data" field hasn't already been used. - */ - if (file->private_data) { - rtn = -EINVAL; - goto done; - } - - /* - * Get the node pointer, and fail if it doesn't exist. - */ - nd = PDE_DATA(inode); - if (!nd) { - rtn = -ENXIO; - goto done; - } - - file->private_data = (void *) nd; - - /* - * Allocate the monitor buffer. - */ - - /* - * Grab the MON lock. - */ - down(&nd->nd_mon_semaphore); - - if (nd->nd_mon_buf) { - rtn = -EBUSY; - goto done_up; - } - - nd->nd_mon_buf = kmalloc(MON_MAX, GFP_KERNEL); - - if (!nd->nd_mon_buf) { - rtn = -ENOMEM; - goto done_up; - } - - /* - * Enter an RPDUMP file header into the buffer. - */ - - buf = nd->nd_mon_buf; - - strcpy(buf, RPDUMP_MAGIC); - buf += strlen(buf) + 1; - - do_gettimeofday(&tv); - - /* - * tv.tv_sec might be a 64 bit quantity. Pare - * it down to 32 bits before attempting to encode - * it. - */ - time = (uint32_t) (tv.tv_sec & 0xffffffff); - - put_unaligned_be32(time, buf); - put_unaligned_be16(0, buf + 4); - buf += 6; - - if (nd->nd_tx_module) { - buf[0] = RPDUMP_CLIENT; - put_unaligned_be32(0, buf + 1); - put_unaligned_be16(1, buf + 5); - buf[7] = 0xf0 + nd->nd_tx_module; - buf += 8; - } - - if (nd->nd_rx_module) { - buf[0] = RPDUMP_SERVER; - put_unaligned_be32(0, buf + 1); - put_unaligned_be16(1, buf + 5); - buf[7] = 0xf0 + nd->nd_rx_module; - buf += 8; - } - - nd->nd_mon_out = 0; - nd->nd_mon_in = buf - nd->nd_mon_buf; - nd->nd_mon_lbolt = jiffies; - -done_up: - up(&nd->nd_mon_semaphore); - -done: - if (rtn) - module_put(THIS_MODULE); - return rtn; -} - - -/** - * dgrp_mon_release() - Close the MON device for a particular PortServer - * @inode: struct inode * - * @file: struct file * - */ -static int dgrp_mon_release(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - goto done; - - /* - * Free the monitor buffer. - */ - - down(&nd->nd_mon_semaphore); - - kfree(nd->nd_mon_buf); - nd->nd_mon_buf = NULL; - nd->nd_mon_out = nd->nd_mon_in; - - /* - * Wakeup any thread waiting for buffer space. - */ - - if (nd->nd_mon_flag & MON_WAIT_SPACE) { - nd->nd_mon_flag &= ~MON_WAIT_SPACE; - wake_up_interruptible(&nd->nd_mon_wqueue); - } - - up(&nd->nd_mon_semaphore); - - /* - * Make sure there is no thread in the middle of writing a packet. - */ - down(&nd->nd_net_semaphore); - up(&nd->nd_net_semaphore); - -done: - module_put(THIS_MODULE); - file->private_data = NULL; - return 0; -} - -/** - * dgrp_mon_read() -- Copy data from the monitoring buffer to the user - */ -static ssize_t dgrp_mon_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct nd_struct *nd; - int r; - int offset = 0; - int res = 0; - ssize_t rtn; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - return -ENXIO; - - /* - * Wait for some data to appear in the buffer. - */ - - down(&nd->nd_mon_semaphore); - - for (;;) { - res = (nd->nd_mon_in - nd->nd_mon_out) & MON_MASK; - - if (res) - break; - - nd->nd_mon_flag |= MON_WAIT_DATA; - - up(&nd->nd_mon_semaphore); - - /* - * Go to sleep waiting until the condition becomes true. - */ - rtn = wait_event_interruptible(nd->nd_mon_wqueue, - ((nd->nd_mon_flag & MON_WAIT_DATA) == 0)); - - if (rtn) - return rtn; - - down(&nd->nd_mon_semaphore); - } - - /* - * Read whatever is there. - */ - - if (res > count) - res = count; - - r = MON_MAX - nd->nd_mon_out; - - if (r <= res) { - rtn = copy_to_user((void __user *)buf, - nd->nd_mon_buf + nd->nd_mon_out, r); - if (rtn) { - up(&nd->nd_mon_semaphore); - return -EFAULT; - } - - nd->nd_mon_out = 0; - res -= r; - offset = r; - } - - rtn = copy_to_user((void __user *) buf + offset, - nd->nd_mon_buf + nd->nd_mon_out, res); - if (rtn) { - up(&nd->nd_mon_semaphore); - return -EFAULT; - } - - nd->nd_mon_out += res; - - *ppos += res; - - up(&nd->nd_mon_semaphore); - - /* - * Wakeup any thread waiting for buffer space. - */ - - if (nd->nd_mon_flag & MON_WAIT_SPACE) { - nd->nd_mon_flag &= ~MON_WAIT_SPACE; - wake_up_interruptible(&nd->nd_mon_wqueue); - } - - return res; -} - -/* ioctl is not valid on monitor device */ -static long dgrp_mon_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return -EINVAL; -} diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c deleted file mode 100644 index 33ac7fb88cbd..000000000000 --- a/drivers/staging/dgrp/dgrp_net_ops.c +++ /dev/null @@ -1,3666 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_net_ops.c - * - * Description: - * - * Handle the file operations required for the "network" devices. - * Includes those functions required to register the "net" devices - * in "/proc". - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MYFLIPLEN TBUF_MAX - -#include "dgrp_common.h" - -#define TTY_FLIPBUF_SIZE 512 -#define DEVICE_NAME_SIZE 50 - -/* - * Generic helper function declarations - */ -static void parity_scan(struct ch_struct *ch, unsigned char *cbuf, - unsigned char *fbuf, int *len); - -/* - * File operation declarations - */ -static int dgrp_net_open(struct inode *, struct file *); -static int dgrp_net_release(struct inode *, struct file *); -static ssize_t dgrp_net_read(struct file *, char __user *, size_t, loff_t *); -static ssize_t dgrp_net_write(struct file *, const char __user *, size_t, - loff_t *); -static long dgrp_net_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -static unsigned int dgrp_net_select(struct file *file, - struct poll_table_struct *table); - -const struct file_operations dgrp_net_ops = { - .owner = THIS_MODULE, - .read = dgrp_net_read, - .write = dgrp_net_write, - .poll = dgrp_net_select, - .unlocked_ioctl = dgrp_net_ioctl, - .open = dgrp_net_open, - .release = dgrp_net_release, -}; - -/** - * dgrp_dump() -- prints memory for debugging purposes. - * @mem: Memory location which should be printed to the console - * @len: Number of bytes to be dumped - */ -static void dgrp_dump(u8 *mem, int len) -{ - int i; - - pr_debug("dgrp dump length = %d, data = ", len); - for (i = 0; i < len; ++i) - pr_debug("%.2x ", mem[i]); - pr_debug("\n"); -} - -/** - * dgrp_read_data_block() -- Read a data block - * @ch: struct ch_struct * - * @flipbuf: u8 * - * @flipbuf_size: size of flipbuf - */ -static void dgrp_read_data_block(struct ch_struct *ch, u8 *flipbuf, - int flipbuf_size) -{ - int t; - int n; - - if (flipbuf_size <= 0) - return; - - t = RBUF_MAX - ch->ch_rout; - n = flipbuf_size; - - if (n >= t) { - memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, t); - flipbuf += t; - n -= t; - ch->ch_rout = 0; - } - - memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, n); - flipbuf += n; - ch->ch_rout += n; -} - - -/** - * dgrp_input() -- send data to the line disipline - * @ch: pointer to channel struct - * - * Copys the rbuf to the flipbuf and sends to line discipline. - * Sends input buffer data to the line discipline. - * - */ -static void dgrp_input(struct ch_struct *ch) -{ - struct nd_struct *nd; - struct tty_struct *tty; - int data_len; - int len; - int tty_count; - ulong lock_flags; - u8 *myflipbuf; - u8 *myflipflagbuf; - - if (!ch) - return; - - nd = ch->ch_nd; - - if (!nd) - return; - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - myflipbuf = nd->nd_inputbuf; - myflipflagbuf = nd->nd_inputflagbuf; - - if (!ch->ch_open_count) { - ch->ch_rout = ch->ch_rin; - goto out; - } - - if (ch->ch_tun.un_flag & UN_CLOSING) { - ch->ch_rout = ch->ch_rin; - goto out; - } - - tty = (ch->ch_tun).un_tty; - - - if (!tty || tty->magic != TTY_MAGIC) { - ch->ch_rout = ch->ch_rin; - goto out; - } - - tty_count = tty->count; - if (!tty_count) { - ch->ch_rout = ch->ch_rin; - goto out; - } - - if (tty->closing || test_bit(TTY_CLOSING, &tty->flags)) { - ch->ch_rout = ch->ch_rin; - goto out; - } - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - /* data_len should be the number of chars that we read in */ - data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK; - - /* len is the amount of data we are going to transfer here */ - len = tty_buffer_request_room(&ch->port, data_len); - - /* Check DPA flow control */ - if ((nd->nd_dpa_debug) && - (nd->nd_dpa_flag & DPA_WAIT_SPACE) && - (nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty)))) - len = 0; - - if ((len) && !(ch->ch_flag & CH_RXSTOP)) { - - dgrp_read_data_block(ch, myflipbuf, len); - - if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty)) - parity_scan(ch, myflipbuf, myflipflagbuf, &len); - else - memset(myflipflagbuf, TTY_NORMAL, len); - - if ((nd->nd_dpa_debug) && - (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty))))) - dgrp_dpa_data(nd, 1, myflipbuf, len); - - tty_insert_flip_string_flags(&ch->port, myflipbuf, - myflipflagbuf, len); - tty_flip_buffer_push(&ch->port); - - ch->ch_rxcount += len; - } - - /* - * Wake up any sleepers (maybe dgrp close) that might be waiting - * for a channel flag state change. - */ - wake_up_interruptible(&ch->ch_flag_wait); - return; - -out: - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); -} - - -/* - * parity_scan - * - * Loop to inspect each single character or 0xFF escape. - * - * if PARMRK & ~DOSMODE: - * 0xFF 0xFF Normal 0xFF character, escaped - * to eliminate confusion. - * 0xFF 0x00 0x00 Break - * 0xFF 0x00 CC Error character CC. - * CC Normal character CC. - * - * if PARMRK & DOSMODE: - * 0xFF 0x18 0x00 Break - * 0xFF 0x08 0x00 Framing Error - * 0xFF 0x04 0x00 Parity error - * 0xFF 0x0C 0x00 Both Framing and Parity error - * - * TODO: do we need to do the XMODEM, XOFF, XON, XANY processing?? - * as per protocol - */ -static void parity_scan(struct ch_struct *ch, unsigned char *cbuf, - unsigned char *fbuf, int *len) -{ - int l = *len; - int count = 0; - int DOS = ((ch->ch_iflag & IF_DOSMODE) == 0 ? 0 : 1); - unsigned char *cout; /* character buffer */ - unsigned char *fout; /* flag buffer */ - unsigned char *in; - unsigned char c; - - in = cbuf; - cout = cbuf; - fout = fbuf; - - while (l--) { - c = *in; - in++; - - switch (ch->ch_pscan_state) { - default: - /* reset to sanity and fall through */ - ch->ch_pscan_state = 0; - - case 0: - /* No FF seen yet */ - if (c == 0xff) /* delete this character from stream */ - ch->ch_pscan_state = 1; - else { - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - } - break; - - case 1: - /* first FF seen */ - if (c == 0xff) { - /* doubled ff, transform to single ff */ - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - ch->ch_pscan_state = 0; - } else { - /* save value examination in next state */ - ch->ch_pscan_savechar = c; - ch->ch_pscan_state = 2; - } - break; - - case 2: - /* third character of ff sequence */ - *cout++ = c; - if (DOS) { - if (ch->ch_pscan_savechar & 0x10) - *fout++ = TTY_BREAK; - else if (ch->ch_pscan_savechar & 0x08) - *fout++ = TTY_FRAME; - else - /* - * either marked as a parity error, - * indeterminate, or not in DOSMODE - * call it a parity error - */ - *fout++ = TTY_PARITY; - } else { - /* case FF XX ?? where XX is not 00 */ - if (ch->ch_pscan_savechar & 0xff) { - /* this should not happen */ - pr_info("%s: parity_scan: error unexpected byte\n", - __func__); - *fout++ = TTY_PARITY; - } - /* case FF 00 XX where XX is not 00 */ - else if (c == 0xff) - *fout++ = TTY_PARITY; - /* case FF 00 00 */ - else - *fout++ = TTY_BREAK; - - } - count += 1; - ch->ch_pscan_state = 0; - } - } - *len = count; -} - - -/** - * dgrp_net_idle() -- Idle the network connection - * @nd: pointer to node structure to idle - */ -static void dgrp_net_idle(struct nd_struct *nd) -{ - struct ch_struct *ch; - int i; - - nd->nd_tx_work = 1; - - nd->nd_state = NS_IDLE; - nd->nd_flag = 0; - - for (i = nd->nd_seq_out; ; i = (i + 1) & SEQ_MASK) { - if (!nd->nd_seq_wait[i]) { - nd->nd_seq_wait[i] = 0; - wake_up_interruptible(&nd->nd_seq_wque[i]); - } - - if (i == nd->nd_seq_in) - break; - } - - nd->nd_seq_out = nd->nd_seq_in; - - nd->nd_unack = 0; - nd->nd_remain = 0; - - nd->nd_tx_module = 0x10; - nd->nd_rx_module = 0x00; - - for (i = 0, ch = nd->nd_chan; i < CHAN_MAX; i++, ch++) { - ch->ch_state = CS_IDLE; - - ch->ch_otype = 0; - ch->ch_otype_waiting = 0; - } -} - -/* - * Increase the number of channels, waking up any - * threads that might be waiting for the channels - * to appear. - */ -static void increase_channel_count(struct nd_struct *nd, int n) -{ - struct ch_struct *ch; - struct device *classp; - char name[DEVICE_NAME_SIZE]; - int ret; - u8 *buf; - int i; - - for (i = nd->nd_chan_count; i < n; ++i) { - ch = nd->nd_chan + i; - - /* FIXME: return a useful error instead! */ - buf = kmalloc(TBUF_MAX, GFP_KERNEL); - if (!buf) - return; - - if (ch->ch_tbuf) - pr_info_ratelimited("%s - ch_tbuf was not NULL\n", - __func__); - - ch->ch_tbuf = buf; - - buf = kmalloc(RBUF_MAX, GFP_KERNEL); - if (!buf) - return; - - if (ch->ch_rbuf) - pr_info("%s - ch_rbuf was not NULL\n", - __func__); - ch->ch_rbuf = buf; - - classp = tty_port_register_device(&ch->port, - nd->nd_serial_ttdriver, i, - NULL); - - ch->ch_tun.un_sysfs = classp; - snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i); - - dgrp_create_tty_sysfs(&ch->ch_tun, classp); - ret = sysfs_create_link(&nd->nd_class_dev->kobj, - &classp->kobj, name); - - /* NOTE: We don't support "cu" devices anymore, - * so you will notice we don't register them - * here anymore. */ - if (dgrp_register_prdevices) { - classp = tty_register_device(nd->nd_xprint_ttdriver, - i, NULL); - ch->ch_pun.un_sysfs = classp; - snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i); - - dgrp_create_tty_sysfs(&ch->ch_pun, classp); - ret = sysfs_create_link(&nd->nd_class_dev->kobj, - &classp->kobj, name); - } - - nd->nd_chan_count = i + 1; - wake_up_interruptible(&ch->ch_flag_wait); - } -} - -/* - * Decrease the number of channels, and wake up any threads that might - * be waiting on the channels that vanished. - */ -static void decrease_channel_count(struct nd_struct *nd, int n) -{ - struct ch_struct *ch; - char name[DEVICE_NAME_SIZE]; - int i; - - for (i = nd->nd_chan_count - 1; i >= n; --i) { - ch = nd->nd_chan + i; - - /* - * Make any open ports inoperative. - */ - ch->ch_state = CS_IDLE; - - ch->ch_otype = 0; - ch->ch_otype_waiting = 0; - - /* - * Only "HANGUP" if we care about carrier - * transitions and we are already open. - */ - if (ch->ch_open_count != 0) { - ch->ch_flag |= CH_HANGUP; - dgrp_carrier(ch); - } - - /* - * Unlike the CH_HANGUP flag above, use another - * flag to indicate to the RealPort state machine - * that this port has disappeared. - */ - if (ch->ch_open_count != 0) - ch->ch_flag |= CH_PORT_GONE; - - wake_up_interruptible(&ch->ch_flag_wait); - - nd->nd_chan_count = i; - - kfree(ch->ch_tbuf); - ch->ch_tbuf = NULL; - - kfree(ch->ch_rbuf); - ch->ch_rbuf = NULL; - - nd->nd_chan_count = i; - - dgrp_remove_tty_sysfs(ch->ch_tun.un_sysfs); - snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i); - sysfs_remove_link(&nd->nd_class_dev->kobj, name); - tty_unregister_device(nd->nd_serial_ttdriver, i); - - /* - * NOTE: We don't support "cu" devices anymore, so don't - * unregister them here anymore. - */ - - if (dgrp_register_prdevices) { - dgrp_remove_tty_sysfs(ch->ch_pun.un_sysfs); - snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i); - sysfs_remove_link(&nd->nd_class_dev->kobj, name); - tty_unregister_device(nd->nd_xprint_ttdriver, i); - } - } -} - -/** - * dgrp_chan_count() -- Adjust the node channel count. - * @nd: pointer to a node structure - * @n: new value for channel count - * - * Adjusts the node channel count. If new ports have appeared, it tries - * to signal those processes that might have been waiting for ports to - * appear. If ports have disappeared it tries to signal those processes - * that might be hung waiting for a response for the now non-existant port. - */ -static void dgrp_chan_count(struct nd_struct *nd, int n) -{ - if (n == nd->nd_chan_count) - return; - - if (n > nd->nd_chan_count) - increase_channel_count(nd, n); - - if (n < nd->nd_chan_count) - decrease_channel_count(nd, n); -} - -/** - * dgrp_monitor() -- send data to the device monitor queue - * @nd: pointer to a node structure - * @buf: data to copy to the monitoring buffer - * @len: number of bytes to transfer to the buffer - * - * Called by the net device routines to send data to the device - * monitor queue. If the device monitor buffer is too full to - * accept the data, it waits until the buffer is ready. - */ -static void dgrp_monitor(struct nd_struct *nd, u8 *buf, int len) -{ - int n; - int r; - int rtn; - - /* - * Grab monitor lock. - */ - down(&nd->nd_mon_semaphore); - - /* - * Loop while data remains. - */ - while ((len > 0) && (nd->nd_mon_buf)) { - /* - * Determine the amount of available space left in the - * buffer. If there's none, wait until some appears. - */ - - n = (nd->nd_mon_out - nd->nd_mon_in - 1) & MON_MASK; - - if (!n) { - nd->nd_mon_flag |= MON_WAIT_SPACE; - - up(&nd->nd_mon_semaphore); - - /* - * Go to sleep waiting until the condition becomes true. - */ - rtn = wait_event_interruptible(nd->nd_mon_wqueue, - ((nd->nd_mon_flag & MON_WAIT_SPACE) == 0)); - -/* FIXME: really ignore rtn? */ - - /* - * We can't exit here if we receive a signal, since - * to do so would trash the debug stream. - */ - - down(&nd->nd_mon_semaphore); - - continue; - } - - /* - * Copy as much data as will fit. - */ - - if (n > len) - n = len; - - r = MON_MAX - nd->nd_mon_in; - - if (r <= n) { - memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, r); - - n -= r; - - nd->nd_mon_in = 0; - - buf += r; - len -= r; - } - - memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, n); - - nd->nd_mon_in += n; - - buf += n; - len -= n; - - if (nd->nd_mon_in >= MON_MAX) - pr_info_ratelimited("%s - nd_mon_in (%i) >= MON_MAX\n", - __func__, nd->nd_mon_in); - - /* - * Wakeup any thread waiting for data - */ - - if (nd->nd_mon_flag & MON_WAIT_DATA) { - nd->nd_mon_flag &= ~MON_WAIT_DATA; - wake_up_interruptible(&nd->nd_mon_wqueue); - } - } - - /* - * Release the monitor lock. - */ - up(&nd->nd_mon_semaphore); -} - -/** - * dgrp_encode_time() -- Encodes rpdump time into a 4-byte quantity. - * @nd: pointer to a node structure - * @buf: destination buffer - * - * Encodes "rpdump" time into a 4-byte quantity. Time is measured since - * open. - */ -static void dgrp_encode_time(struct nd_struct *nd, u8 *buf) -{ - ulong t; - - /* - * Convert time in HZ since open to time in milliseconds - * since open. - */ - t = jiffies - nd->nd_mon_lbolt; - t = 1000 * (t / HZ) + 1000 * (t % HZ) / HZ; - - put_unaligned_be32((uint)(t & 0xffffffff), buf); -} - - - -/** - * dgrp_monitor_message() -- Builds a rpdump style message. - * @nd: pointer to a node structure - * @message: destination buffer - */ -static void dgrp_monitor_message(struct nd_struct *nd, char *message) -{ - u8 header[7]; - int n; - - header[0] = RPDUMP_MESSAGE; - - dgrp_encode_time(nd, header + 1); - - n = strlen(message); - - put_unaligned_be16(n, header + 5); - - dgrp_monitor(nd, header, sizeof(header)); - dgrp_monitor(nd, (u8 *) message, n); -} - - - -/** - * dgrp_monitor_reset() -- Note a reset in the monitoring buffer. - * @nd: pointer to a node structure - */ -static void dgrp_monitor_reset(struct nd_struct *nd) -{ - u8 header[5]; - - header[0] = RPDUMP_RESET; - - dgrp_encode_time(nd, header + 1); - - dgrp_monitor(nd, header, sizeof(header)); -} - -/** - * dgrp_monitor_data() -- builds a monitor data packet - * @nd: pointer to a node structure - * @type: type of message to be logged - * @buf: data to be logged - * @size: number of bytes in the buffer - */ -static void dgrp_monitor_data(struct nd_struct *nd, u8 type, u8 *buf, int size) -{ - u8 header[7]; - - header[0] = type; - - dgrp_encode_time(nd, header + 1); - - put_unaligned_be16(size, header + 5); - - dgrp_monitor(nd, header, sizeof(header)); - dgrp_monitor(nd, buf, size); -} - -static int alloc_nd_buffers(struct nd_struct *nd) -{ - - nd->nd_iobuf = NULL; - nd->nd_writebuf = NULL; - nd->nd_inputbuf = NULL; - nd->nd_inputflagbuf = NULL; - - /* - * Allocate the network read/write buffer. - */ - nd->nd_iobuf = kzalloc(UIO_MAX + 10, GFP_KERNEL); - if (!nd->nd_iobuf) - goto out_err; - - /* - * Allocate a buffer for doing the copy from user space to - * kernel space in the write routines. - */ - nd->nd_writebuf = kzalloc(WRITEBUFLEN, GFP_KERNEL); - if (!nd->nd_writebuf) - goto out_err; - - /* - * Allocate a buffer for doing the copy from kernel space to - * tty buffer space in the read routines. - */ - nd->nd_inputbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); - if (!nd->nd_inputbuf) - goto out_err; - - /* - * Allocate a buffer for doing the copy from kernel space to - * tty buffer space in the read routines. - */ - nd->nd_inputflagbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); - if (!nd->nd_inputflagbuf) - goto out_err; - - return 0; - -out_err: - kfree(nd->nd_iobuf); - kfree(nd->nd_writebuf); - kfree(nd->nd_inputbuf); - kfree(nd->nd_inputflagbuf); - return -ENOMEM; -} - -/* - * dgrp_net_open() -- Open the NET device for a particular PortServer - */ -static int dgrp_net_open(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - ulong lock_flags; - int rtn; - - rtn = try_module_get(THIS_MODULE); - if (!rtn) - return -EAGAIN; - - if (!capable(CAP_SYS_ADMIN)) { - rtn = -EPERM; - goto done; - } - - /* - * Make sure that the "private_data" field hasn't already been used. - */ - if (file->private_data) { - rtn = -EINVAL; - goto done; - } - - /* - * Get the node pointer, and fail if it doesn't exist. - */ - nd = PDE_DATA(inode); - if (!nd) { - rtn = -ENXIO; - goto done; - } - - file->private_data = (void *) nd; - - /* - * Grab the NET lock. - */ - down(&nd->nd_net_semaphore); - - if (nd->nd_state != NS_CLOSED) { - rtn = -EBUSY; - goto unlock; - } - - /* - * Initialize the link speed parameters. - */ - - nd->nd_link.lk_fast_rate = UIO_MAX; - nd->nd_link.lk_slow_rate = UIO_MAX; - - nd->nd_link.lk_fast_delay = 1000; - nd->nd_link.lk_slow_delay = 1000; - - nd->nd_link.lk_header_size = 46; - - - rtn = alloc_nd_buffers(nd); - if (rtn) - goto unlock; - - /* - * The port is now open, so move it to the IDLE state - */ - dgrp_net_idle(nd); - - nd->nd_tx_time = jiffies; - - /* - * If the polling routing is not running, start it running here - */ - spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); - - if (!dgrp_poll_data.node_active_count) { - dgrp_poll_data.node_active_count = 2; - dgrp_poll_data.timer.expires = jiffies + - dgrp_poll_tick * HZ / 1000; - add_timer(&dgrp_poll_data.timer); - } - - spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); - - dgrp_monitor_message(nd, "Net Open"); - -unlock: - /* - * Release the NET lock. - */ - up(&nd->nd_net_semaphore); - -done: - if (rtn) - module_put(THIS_MODULE); - - return rtn; -} - -/* dgrp_net_release() -- close the NET device for a particular PortServer */ -static int dgrp_net_release(struct inode *inode, struct file *file) -{ - struct nd_struct *nd; - ulong lock_flags; - - nd = (struct nd_struct *)(file->private_data); - if (!nd) - goto done; - -/* TODO : historical locking placeholder */ -/* - * In the HPUX version of the RealPort driver (which served as a basis - * for this driver) this locking code was used. Saved if ever we need - * to review the locking under Linux. - */ -/* spinlock(&nd->nd_lock); */ - - - /* - * Grab the NET lock. - */ - down(&nd->nd_net_semaphore); - - /* - * Before "closing" the internal connection, make sure all - * ports are "idle". - */ - dgrp_net_idle(nd); - - nd->nd_state = NS_CLOSED; - nd->nd_flag = 0; - - /* - * TODO ... must the wait queue be reset on close? - * should any pending waiters be reset? - * Let's decide to assert that the waitq is empty... and see - * how soon we break. - */ - if (waitqueue_active(&nd->nd_tx_waitq)) - pr_info("%s - expected waitqueue_active to be false\n", - __func__); - - nd->nd_send = 0; - - kfree(nd->nd_iobuf); - nd->nd_iobuf = NULL; - -/* TODO : historical locking placeholder */ -/* - * In the HPUX version of the RealPort driver (which served as a basis - * for this driver) this locking code was used. Saved if ever we need - * to review the locking under Linux. - */ -/* spinunlock( &nd->nd_lock ); */ - - - kfree(nd->nd_writebuf); - nd->nd_writebuf = NULL; - - kfree(nd->nd_inputbuf); - nd->nd_inputbuf = NULL; - - kfree(nd->nd_inputflagbuf); - nd->nd_inputflagbuf = NULL; - -/* TODO : historical locking placeholder */ -/* - * In the HPUX version of the RealPort driver (which served as a basis - * for this driver) this locking code was used. Saved if ever we need - * to review the locking under Linux. - */ -/* spinlock(&nd->nd_lock); */ - - /* - * Set the active port count to zero. - */ - dgrp_chan_count(nd, 0); - -/* TODO : historical locking placeholder */ -/* - * In the HPUX version of the RealPort driver (which served as a basis - * for this driver) this locking code was used. Saved if ever we need - * to review the locking under Linux. - */ -/* spinunlock(&nd->nd_lock); */ - - /* - * Release the NET lock. - */ - up(&nd->nd_net_semaphore); - - /* - * Cause the poller to stop scheduling itself if this is - * the last active node. - */ - spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); - - if (dgrp_poll_data.node_active_count == 2) { - del_timer(&dgrp_poll_data.timer); - dgrp_poll_data.node_active_count = 0; - } - - spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); - - down(&nd->nd_net_semaphore); - - dgrp_monitor_message(nd, "Net Close"); - - up(&nd->nd_net_semaphore); - -done: - module_put(THIS_MODULE); - file->private_data = NULL; - return 0; -} - -/* used in dgrp_send to setup command header */ -static inline u8 *set_cmd_header(u8 *b, u8 port, u8 cmd) -{ - *b++ = 0xb0 + (port & 0x0f); - *b++ = cmd; - return b; -} - -/** - * dgrp_send() -- build a packet for transmission to the server - * @nd: pointer to a node structure - * @tmax: maximum bytes to transmit - * - * returns number of bytes sent - */ -static int dgrp_send(struct nd_struct *nd, long tmax) -{ - struct ch_struct *ch = nd->nd_chan; - u8 *b; - u8 *buf; - u8 *mbuf; - u8 port; - int mod; - long send; - int maxport; - long lastport = -1; - ushort rwin; - long in; - ushort n; - long t; - long ttotal; - long tchan; - long tsend; - ushort tsafe; - long work; - long send_sync; - long wanted_sync_port = -1; - ushort tdata[CHAN_MAX]; - long used_buffer; - - mbuf = nd->nd_iobuf + UIO_BASE; - buf = b = mbuf; - - send_sync = nd->nd_link.lk_slow_rate < UIO_MAX; - - ttotal = 0; - tchan = 0; - - memset(tdata, 0, sizeof(tdata)); - - - /* - * If there are any outstanding requests to be serviced, - * service them here. - */ - if (nd->nd_send & NR_PASSWORD) { - - /* - * Send Password response. - */ - - b[0] = 0xfc; - b[1] = 0x20; - put_unaligned_be16(strlen(nd->password), b + 2); - b += 4; - b += strlen(nd->password); - nd->nd_send &= ~(NR_PASSWORD); - } - - - /* - * Loop over all modules to generate commands, and determine - * the amount of data queued for transmit. - */ - - for (mod = 0, port = 0; port < nd->nd_chan_count; mod++) { - /* - * If this is not the current module, enter a module select - * code in the buffer. - */ - - if (mod != nd->nd_tx_module) - mbuf = ++b; - - /* - * Loop to process one module. - */ - - maxport = port + 16; - - if (maxport > nd->nd_chan_count) - maxport = nd->nd_chan_count; - - for (; port < maxport; port++, ch++) { - /* - * Switch based on channel state. - */ - - switch (ch->ch_state) { - /* - * Send requests when the port is closed, and there - * are no Open, Close or Cancel requests expected. - */ - - case CS_IDLE: - /* - * Wait until any open error code - * has been delivered to all - * associated ports. - */ - - if (ch->ch_open_error) { - if (ch->ch_wait_count[ch->ch_otype]) { - work = 1; - break; - } - - ch->ch_open_error = 0; - } - - /* - * Wait until the channel HANGUP flag is reset - * before sending the first open. We can only - * get to this state after a server disconnect. - */ - - if ((ch->ch_flag & CH_HANGUP) != 0) - break; - - /* - * If recovering from a TCP disconnect, or if - * there is an immediate open pending, send an - * Immediate Open request. - */ - if ((ch->ch_flag & CH_PORT_GONE) || - ch->ch_wait_count[OTYPE_IMMEDIATE] != 0) { - b = set_cmd_header(b, port, 10); - *b++ = 0; - - ch->ch_state = CS_WAIT_OPEN; - ch->ch_otype = OTYPE_IMMEDIATE; - break; - } - - /* - * If there is no Persistent or Incoming Open on the wait - * list in the server, and a thread is waiting for a - * Persistent or Incoming Open, send a Persistent or Incoming - * Open Request. - */ - if (ch->ch_otype_waiting == 0) { - if (ch->ch_wait_count[OTYPE_PERSISTENT] != 0) { - b = set_cmd_header(b, port, 10); - *b++ = 1; - - ch->ch_state = CS_WAIT_OPEN; - ch->ch_otype = OTYPE_PERSISTENT; - } else if (ch->ch_wait_count[OTYPE_INCOMING] != 0) { - b = set_cmd_header(b, port, 10); - *b++ = 2; - - ch->ch_state = CS_WAIT_OPEN; - ch->ch_otype = OTYPE_INCOMING; - } - break; - } - - /* - * If a Persistent or Incoming Open is pending in - * the server, but there is no longer an open - * thread waiting for it, cancel the request. - */ - - if (ch->ch_wait_count[ch->ch_otype_waiting] == 0) { - b = set_cmd_header(b, port, 10); - *b++ = 4; - - ch->ch_state = CS_WAIT_CANCEL; - ch->ch_otype = ch->ch_otype_waiting; - } - break; - - /* - * Send port parameter queries. - */ - case CS_SEND_QUERY: - /* - * Clear out all FEP state that might remain - * from the last connection. - */ - - ch->ch_flag |= CH_PARAM; - - ch->ch_flag &= ~CH_RX_FLUSH; - - ch->ch_expect = 0; - - ch->ch_s_tin = 0; - ch->ch_s_tpos = 0; - ch->ch_s_tsize = 0; - ch->ch_s_treq = 0; - ch->ch_s_elast = 0; - - ch->ch_s_rin = 0; - ch->ch_s_rwin = 0; - ch->ch_s_rsize = 0; - - ch->ch_s_tmax = 0; - ch->ch_s_ttime = 0; - ch->ch_s_rmax = 0; - ch->ch_s_rtime = 0; - ch->ch_s_rlow = 0; - ch->ch_s_rhigh = 0; - - ch->ch_s_brate = 0; - ch->ch_s_iflag = 0; - ch->ch_s_cflag = 0; - ch->ch_s_oflag = 0; - ch->ch_s_xflag = 0; - - ch->ch_s_mout = 0; - ch->ch_s_mflow = 0; - ch->ch_s_mctrl = 0; - ch->ch_s_xon = 0; - ch->ch_s_xoff = 0; - ch->ch_s_lnext = 0; - ch->ch_s_xxon = 0; - ch->ch_s_xxoff = 0; - - /* Send Sequence Request */ - b = set_cmd_header(b, port, 14); - - /* Configure Event Conditions Packet */ - b = set_cmd_header(b, port, 42); - put_unaligned_be16(0x02c0, b); - b += 2; - *b++ = (DM_DTR | DM_RTS | DM_CTS | - DM_DSR | DM_RI | DM_CD); - - /* Send Status Request */ - b = set_cmd_header(b, port, 16); - - /* Send Buffer Request */ - b = set_cmd_header(b, port, 20); - - /* Send Port Capability Request */ - b = set_cmd_header(b, port, 22); - - ch->ch_expect = (RR_SEQUENCE | - RR_STATUS | - RR_BUFFER | - RR_CAPABILITY); - - ch->ch_state = CS_WAIT_QUERY; - - /* Raise modem signals */ - b = set_cmd_header(b, port, 44); - - if (ch->ch_flag & CH_PORT_GONE) - ch->ch_s_mout = ch->ch_mout; - else - ch->ch_s_mout = ch->ch_mout = DM_DTR | DM_RTS; - - *b++ = ch->ch_mout; - *b++ = ch->ch_s_mflow = 0; - *b++ = ch->ch_s_mctrl = ch->ch_mctrl = 0; - - if (ch->ch_flag & CH_PORT_GONE) - ch->ch_flag &= ~CH_PORT_GONE; - - break; - - /* - * Handle normal open and ready mode. - */ - - case CS_READY: - - /* - * If the port is not open, and there are no - * no longer any ports requesting an open, - * then close the port. - */ - - if (ch->ch_open_count == 0 && - ch->ch_wait_count[ch->ch_otype] == 0) { - goto send_close; - } - - /* - * Process waiting input. - * - * If there is no one to read it, discard the data. - * - * Otherwise if we are not in fastcook mode, or if there is a - * fastcook thread waiting for data, send the data to the - * line discipline. - */ - if (ch->ch_rin != ch->ch_rout) { - if (ch->ch_tun.un_open_count == 0 || - (ch->ch_tun.un_flag & UN_CLOSING) || - (ch->ch_cflag & CF_CREAD) == 0) { - ch->ch_rout = ch->ch_rin; - } else if ((ch->ch_flag & CH_FAST_READ) == 0 || - ch->ch_inwait != 0) { - dgrp_input(ch); - - if (ch->ch_rin != ch->ch_rout) - work = 1; - } - } - - /* - * Handle receive flush, and changes to - * server port parameters. - */ - - if (ch->ch_flag & (CH_RX_FLUSH | CH_PARAM)) { - /* - * If we are in receive flush mode, - * and enough data has gone by, reset - * receive flush mode. - */ - if (ch->ch_flag & CH_RX_FLUSH) { - if (((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) > - ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) - ch->ch_flag &= ~CH_RX_FLUSH; - else - work = 1; - } - - /* - * Send TMAX, TTIME. - */ - - if (ch->ch_s_tmax != ch->ch_tmax || - ch->ch_s_ttime != ch->ch_ttime) { - b = set_cmd_header(b, port, 48); - - ch->ch_s_tmax = ch->ch_tmax; - ch->ch_s_ttime = ch->ch_ttime; - - put_unaligned_be16(ch->ch_s_tmax, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_ttime, - b); - b += 2; - } - - /* - * Send RLOW, RHIGH. - */ - - if (ch->ch_s_rlow != ch->ch_rlow || - ch->ch_s_rhigh != ch->ch_rhigh) { - b = set_cmd_header(b, port, 45); - - ch->ch_s_rlow = ch->ch_rlow; - ch->ch_s_rhigh = ch->ch_rhigh; - - put_unaligned_be16(ch->ch_s_rlow, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_rhigh, - b); - b += 2; - } - - /* - * Send BRATE, CFLAG, IFLAG, - * OFLAG, XFLAG. - */ - - if (ch->ch_s_brate != ch->ch_brate || - ch->ch_s_cflag != ch->ch_cflag || - ch->ch_s_iflag != ch->ch_iflag || - ch->ch_s_oflag != ch->ch_oflag || - ch->ch_s_xflag != ch->ch_xflag) { - b = set_cmd_header(b, port, 40); - - ch->ch_s_brate = ch->ch_brate; - ch->ch_s_cflag = ch->ch_cflag; - ch->ch_s_iflag = ch->ch_iflag; - ch->ch_s_oflag = ch->ch_oflag; - ch->ch_s_xflag = ch->ch_xflag; - - put_unaligned_be16(ch->ch_s_brate, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_cflag, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_iflag, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_oflag, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_xflag, - b); - b += 2; - } - - /* - * Send MOUT, MFLOW, MCTRL. - */ - - if (ch->ch_s_mout != ch->ch_mout || - ch->ch_s_mflow != ch->ch_mflow || - ch->ch_s_mctrl != ch->ch_mctrl) { - b = set_cmd_header(b, port, 44); - - *b++ = ch->ch_s_mout = ch->ch_mout; - *b++ = ch->ch_s_mflow = ch->ch_mflow; - *b++ = ch->ch_s_mctrl = ch->ch_mctrl; - } - - /* - * Send Flow control characters. - */ - - if (ch->ch_s_xon != ch->ch_xon || - ch->ch_s_xoff != ch->ch_xoff || - ch->ch_s_lnext != ch->ch_lnext || - ch->ch_s_xxon != ch->ch_xxon || - ch->ch_s_xxoff != ch->ch_xxoff) { - b = set_cmd_header(b, port, 46); - - *b++ = ch->ch_s_xon = ch->ch_xon; - *b++ = ch->ch_s_xoff = ch->ch_xoff; - *b++ = ch->ch_s_lnext = ch->ch_lnext; - *b++ = ch->ch_s_xxon = ch->ch_xxon; - *b++ = ch->ch_s_xxoff = ch->ch_xxoff; - } - - /* - * Send RMAX, RTIME. - */ - - if (ch->ch_s_rmax != ch->ch_rmax || - ch->ch_s_rtime != ch->ch_rtime) { - b = set_cmd_header(b, port, 47); - - ch->ch_s_rmax = ch->ch_rmax; - ch->ch_s_rtime = ch->ch_rtime; - - put_unaligned_be16(ch->ch_s_rmax, - b); - b += 2; - - put_unaligned_be16(ch->ch_s_rtime, - b); - b += 2; - } - - ch->ch_flag &= ~CH_PARAM; - wake_up_interruptible(&ch->ch_flag_wait); - } - - - /* - * Handle action commands. - */ - - if (ch->ch_send != 0) { - /* int send = ch->ch_send & ~ch->ch_expect; */ - send = ch->ch_send & ~ch->ch_expect; - - /* Send character immediate */ - if ((send & RR_TX_ICHAR) != 0) { - b = set_cmd_header(b, port, 60); - - *b++ = ch->ch_xon; - ch->ch_expect |= RR_TX_ICHAR; - } - - /* BREAK request */ - if ((send & RR_TX_BREAK) != 0) { - if (ch->ch_break_time != 0) { - b = set_cmd_header(b, port, 61); - put_unaligned_be16(ch->ch_break_time, - b); - b += 2; - - ch->ch_expect |= RR_TX_BREAK; - ch->ch_break_time = 0; - } else { - ch->ch_send &= ~RR_TX_BREAK; - ch->ch_flag &= ~CH_TX_BREAK; - wake_up_interruptible(&ch->ch_flag_wait); - } - } - - /* - * Flush input/output buffers. - */ - - if ((send & (RR_RX_FLUSH | RR_TX_FLUSH)) != 0) { - b = set_cmd_header(b, port, 62); - - *b++ = ((send & RR_TX_FLUSH) == 0 ? 1 : - (send & RR_RX_FLUSH) == 0 ? 2 : 3); - - if (send & RR_RX_FLUSH) { - ch->ch_flush_seq = nd->nd_seq_in; - ch->ch_flag |= CH_RX_FLUSH; - work = 1; - send_sync = 1; - wanted_sync_port = port; - } - - ch->ch_send &= ~(RR_RX_FLUSH | RR_TX_FLUSH); - } - - /* Pause input/output */ - if ((send & (RR_RX_STOP | RR_TX_STOP)) != 0) { - b = set_cmd_header(b, port, 63); - *b = 0; - - if ((send & RR_TX_STOP) != 0) - *b |= EV_OPU; - - if ((send & RR_RX_STOP) != 0) - *b |= EV_IPU; - - b++; - - ch->ch_send &= ~(RR_RX_STOP | RR_TX_STOP); - } - - /* Start input/output */ - if ((send & (RR_RX_START | RR_TX_START)) != 0) { - b = set_cmd_header(b, port, 64); - *b = 0; - - if ((send & RR_TX_START) != 0) - *b |= EV_OPU | EV_OPS | EV_OPX; - - if ((send & RR_RX_START) != 0) - *b |= EV_IPU | EV_IPS; - - b++; - - ch->ch_send &= ~(RR_RX_START | RR_TX_START); - } - } - - - /* - * Send a window sequence to acknowledge received data. - */ - - rwin = (ch->ch_s_rin + - ((ch->ch_rout - ch->ch_rin - 1) & RBUF_MASK)); - - n = (rwin - ch->ch_s_rwin) & 0xffff; - - if (n >= RBUF_MAX / 4) { - b[0] = 0xa0 + (port & 0xf); - ch->ch_s_rwin = rwin; - put_unaligned_be16(rwin, b + 1); - b += 3; - } - - /* - * If the terminal is waiting on LOW - * water or EMPTY, and the condition - * is now satisfied, call the line - * discipline to put more data in the - * buffer. - */ - - n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - - if ((ch->ch_tun.un_flag & (UN_EMPTY|UN_LOW)) != 0) { - if ((ch->ch_tun.un_flag & UN_LOW) != 0 ? - (n <= TBUF_LOW) : - (n == 0 && ch->ch_s_tpos == ch->ch_s_tin)) { - ch->ch_tun.un_flag &= ~(UN_EMPTY|UN_LOW); - - if (waitqueue_active(&((ch->ch_tun.un_tty)->write_wait))) - wake_up_interruptible(&((ch->ch_tun.un_tty)->write_wait)); - tty_wakeup(ch->ch_tun.un_tty); - n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - } - } - - /* - * If the printer is waiting on LOW - * water, TIME, EMPTY or PWAIT, and is - * now ready to put more data in the - * buffer, call the line discipline to - * do the job. - */ - - /* FIXME: jiffies - ch->ch_waketime can never - be < 0. Someone needs to work out what is - actually intended here */ - if (ch->ch_pun.un_open_count && - (ch->ch_pun.un_flag & - (UN_EMPTY|UN_TIME|UN_LOW|UN_PWAIT)) != 0) { - - if ((ch->ch_pun.un_flag & UN_LOW) != 0 ? - (n <= TBUF_LOW) : - (ch->ch_pun.un_flag & UN_TIME) != 0 ? - time_is_before_jiffies(ch->ch_waketime) : - (n == 0 && ch->ch_s_tpos == ch->ch_s_tin) && - ((ch->ch_pun.un_flag & UN_EMPTY) != 0 || - ((ch->ch_tun.un_open_count && - ch->ch_tun.un_tty->ops->chars_in_buffer) ? - (ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) == 0 - : 1 - ) - )) { - ch->ch_pun.un_flag &= ~(UN_EMPTY | UN_TIME | UN_LOW | UN_PWAIT); - - if (waitqueue_active(&((ch->ch_pun.un_tty)->write_wait))) - wake_up_interruptible(&((ch->ch_pun.un_tty)->write_wait)); - tty_wakeup(ch->ch_pun.un_tty); - n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - - } else if ((ch->ch_pun.un_flag & UN_TIME) != 0) { - work = 1; - } - } - - - /* - * Determine the max number of bytes - * this port can send, including - * packet header overhead. - */ - - t = ((ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff); - - if (n > t) - n = t; - - if (n != 0) { - n += (n <= 8 ? 1 : n <= 255 ? 2 : 3); - - tdata[tchan++] = n; - ttotal += n; - } - break; - - /* - * Close the port. - */ - -send_close: - case CS_SEND_CLOSE: - b = set_cmd_header(b, port, 10); - if (ch->ch_otype == OTYPE_IMMEDIATE) - *b++ = 3; - else - *b++ = 4; - - ch->ch_state = CS_WAIT_CLOSE; - break; - - /* - * Wait for a previous server request. - */ - - case CS_WAIT_OPEN: - case CS_WAIT_CANCEL: - case CS_WAIT_FAIL: - case CS_WAIT_QUERY: - case CS_WAIT_CLOSE: - break; - - default: - pr_info("%s - unexpected channel state (%i)\n", - __func__, ch->ch_state); - } - } - - /* - * If a module select code is needed, drop one in. If space - * was reserved for one, but none is needed, recover the space. - */ - - if (mod != nd->nd_tx_module) { - if (b != mbuf) { - mbuf[-1] = 0xf0 | mod; - nd->nd_tx_module = mod; - } else { - b--; - } - } - } - - /* - * Adjust "tmax" so that under worst case conditions we do - * not overflow either the daemon buffer or the internal - * buffer in the loop that follows. Leave a safe area - * of 64 bytes so we start getting asserts before we start - * losing data or clobbering memory. - */ - - n = UIO_MAX - UIO_BASE; - - if (tmax > n) - tmax = n; - - tmax -= 64; - - tsafe = tmax; - - /* - * Allocate space for 5 Module Selects, 1 Sequence Request, - * and 1 Set TREQ for each active channel. - */ - - tmax -= 5 + 3 + 4 * nd->nd_chan_count; - - /* - * Further reduce "tmax" to the available transmit credit. - * Note that this is a soft constraint; The transmit credit - * can go negative for a time and then recover. - */ - - n = nd->nd_tx_deposit - nd->nd_tx_charge - nd->nd_link.lk_header_size; - - if (tmax > n) - tmax = n; - - /* - * Finally reduce tmax by the number of bytes already in - * the buffer. - */ - - tmax -= b - buf; - - /* - * Suspend data transmit unless every ready channel can send - * at least 1 character. - */ - if (tmax < 2 * nd->nd_chan_count) { - tsend = 1; - - } else if (tchan > 1 && ttotal > tmax) { - - /* - * If transmit is limited by the credit budget, find the - * largest number of characters we can send without driving - * the credit negative. - */ - - long tm = tmax; - int tc = tchan; - int try; - - tsend = tm / tc; - - for (try = 0; try < 3; try++) { - int i; - int c = 0; - - for (i = 0; i < tc; i++) { - if (tsend < tdata[i]) - tdata[c++] = tdata[i]; - else - tm -= tdata[i]; - } - - if (c == tc) - break; - - tsend = tm / c; - - if (c == 1) - break; - - tc = c; - } - - tsend = tm / nd->nd_chan_count; - - if (tsend < 2) - tsend = 1; - - } else { - /* - * If no budgetary constraints, or only one channel ready - * to send, set the character limit to the remaining - * buffer size. - */ - - tsend = tmax; - } - - tsend -= (tsend <= 9) ? 1 : (tsend <= 257) ? 2 : 3; - - /* - * Loop over all channels, sending queued data. - */ - - port = 0; - ch = nd->nd_chan; - used_buffer = tmax; - - for (mod = 0; port < nd->nd_chan_count; mod++) { - /* - * If this is not the current module, enter a module select - * code in the buffer. - */ - - if (mod != nd->nd_tx_module) - mbuf = ++b; - - /* - * Loop to process one module. - */ - - maxport = port + 16; - - if (maxport > nd->nd_chan_count) - maxport = nd->nd_chan_count; - - for (; port < maxport; port++, ch++) { - if (ch->ch_state != CS_READY) - continue; - - lastport = port; - - n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - - /* - * If there is data that can be sent, send it. - */ - - if (n != 0 && used_buffer > 0) { - t = (ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff; - - if (n > t) - n = t; - - if (n > tsend) { - work = 1; - n = tsend; - } - - if (n > used_buffer) { - work = 1; - n = used_buffer; - } - - if (n <= 0) - continue; - - /* - * Create the correct size transmit header, - * depending on the amount of data to transmit. - */ - - if (n <= 8) { - - b[0] = ((n - 1) << 4) + (port & 0xf); - b += 1; - - } else if (n <= 255) { - - b[0] = 0x80 + (port & 0xf); - b[1] = n; - b += 2; - - } else { - - b[0] = 0x90 + (port & 0xf); - put_unaligned_be16(n, b + 1); - b += 3; - } - - ch->ch_s_tin = (ch->ch_s_tin + n) & 0xffff; - - /* - * Copy transmit data to the packet. - */ - - t = TBUF_MAX - ch->ch_tout; - - if (n >= t) { - memcpy(b, ch->ch_tbuf + ch->ch_tout, t); - b += t; - n -= t; - used_buffer -= t; - ch->ch_tout = 0; - } - - memcpy(b, ch->ch_tbuf + ch->ch_tout, n); - b += n; - used_buffer -= n; - ch->ch_tout += n; - n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - } - - /* - * Wake any terminal unit process waiting in the - * dgrp_write routine for low water. - */ - - if (n > TBUF_LOW) - continue; - - if ((ch->ch_flag & CH_LOW) != 0) { - ch->ch_flag &= ~CH_LOW; - wake_up_interruptible(&ch->ch_flag_wait); - } - - /* selwakeup tty_sel */ - if (ch->ch_tun.un_open_count) { - struct tty_struct *tty = (ch->ch_tun.un_tty); - - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - tty_wakeup(tty); - } - - if (ch->ch_pun.un_open_count) { - struct tty_struct *tty = (ch->ch_pun.un_tty); - - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - tty_wakeup(tty); - } - - /* - * Do EMPTY processing. - */ - - if (n != 0) - continue; - - if ((ch->ch_flag & (CH_EMPTY | CH_DRAIN)) != 0 || - (ch->ch_pun.un_flag & UN_EMPTY) != 0) { - /* - * If there is still data in the server, ask the server - * to notify us when its all gone. - */ - - if (ch->ch_s_treq != ch->ch_s_tin) { - b = set_cmd_header(b, port, 43); - - ch->ch_s_treq = ch->ch_s_tin; - put_unaligned_be16(ch->ch_s_treq, - b); - b += 2; - } - - /* - * If there is a thread waiting for buffer empty, - * and we are truly empty, wake the thread. - */ - - else if ((ch->ch_flag & CH_EMPTY) != 0 && - (ch->ch_send & RR_TX_BREAK) == 0) { - ch->ch_flag &= ~CH_EMPTY; - - wake_up_interruptible(&ch->ch_flag_wait); - } - } - } - - /* - * If a module select code is needed, drop one in. If space - * was reserved for one, but none is needed, recover the space. - */ - - if (mod != nd->nd_tx_module) { - if (b != mbuf) { - mbuf[-1] = 0xf0 | mod; - nd->nd_tx_module = mod; - } else { - b--; - } - } - } - - /* - * Send a synchronization sequence associated with the last open - * channel that sent data, and remember the time when the data was - * sent. - */ - - in = nd->nd_seq_in; - - if ((send_sync || nd->nd_seq_wait[in] != 0) && lastport >= 0) { - u8 *bb = b; - - /* - * Attempt the use the port that really wanted the sync. - * This gets around a race condition where the "lastport" is in - * the middle of the close() routine, and by the time we - * send this command, it will have already acked the close, and - * thus not send the sync response. - */ - if (wanted_sync_port >= 0) - lastport = wanted_sync_port; - /* - * Set a flag just in case the port is in the middle of a close, - * it will not be permitted to actually close until we get an - * sync response, and clear the flag there. - */ - ch = nd->nd_chan + lastport; - ch->ch_flag |= CH_WAITING_SYNC; - - mod = lastport >> 4; - - if (mod != nd->nd_tx_module) { - bb[0] = 0xf0 + mod; - bb += 1; - - nd->nd_tx_module = mod; - } - - bb = set_cmd_header(bb, lastport, 12); - *bb++ = in; - - nd->nd_seq_size[in] = bb - buf; - nd->nd_seq_time[in] = jiffies; - - if (++in >= SEQ_MAX) - in = 0; - - if (in != nd->nd_seq_out) { - b = bb; - nd->nd_seq_in = in; - nd->nd_unack += b - buf; - } - } - - /* - * If there are no open ports, a sync cannot be sent. - * There is nothing left to wait for anyway, so wake any - * thread waiting for an acknowledgement. - */ - - else if (nd->nd_seq_wait[in] != 0) { - nd->nd_seq_wait[in] = 0; - - wake_up_interruptible(&nd->nd_seq_wque[in]); - } - - /* - * If there is no traffic for an interval of IDLE_MAX, then - * send a single byte packet. - */ - - if (b != buf) { - nd->nd_tx_time = jiffies; - } else if ((ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX) { - *b++ = 0xf0 | nd->nd_tx_module; - nd->nd_tx_time = jiffies; - } - - n = b - buf; - - if (n >= tsafe) - pr_info("%s - n(%i) >= tsafe(%i)\n", - __func__, n, tsafe); - - if (tsend < 0) - dgrp_dump(buf, n); - - nd->nd_tx_work = work; - - return n; -} - -/* - * dgrp_net_read() - * Data to be sent TO the PortServer from the "async." half of the driver. - */ -static ssize_t dgrp_net_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct nd_struct *nd; - long n; - u8 *local_buf; - u8 *b; - ssize_t rtn; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - return -ENXIO; - - if (count < UIO_MIN) - return -EINVAL; - - /* - * Only one read/write operation may be in progress at - * any given time. - */ - - /* - * Grab the NET lock. - */ - down(&nd->nd_net_semaphore); - - nd->nd_read_count++; - - nd->nd_tx_ready = 0; - - /* - * Determine the effective size of the buffer. - */ - - if (nd->nd_remain > UIO_BASE) - pr_info_ratelimited("%s - nd_remain(%i) > UIO_BASE\n", - __func__, nd->nd_remain); - - b = local_buf = nd->nd_iobuf + UIO_BASE; - - /* - * Generate data according to the node state. - */ - - switch (nd->nd_state) { - /* - * Initialize the connection. - */ - - case NS_IDLE: - if (nd->nd_mon_buf) - dgrp_monitor_reset(nd); - - /* - * Request a Product ID Packet. - */ - - b[0] = 0xfb; - b[1] = 0x01; - b += 2; - - nd->nd_expect |= NR_IDENT; - - /* - * Request a Server Capability ID Response. - */ - - b[0] = 0xfb; - b[1] = 0x02; - b += 2; - - nd->nd_expect |= NR_CAPABILITY; - - /* - * Request a Server VPD Response. - */ - - b[0] = 0xfb; - b[1] = 0x18; - b += 2; - - nd->nd_expect |= NR_VPD; - - nd->nd_state = NS_WAIT_QUERY; - break; - - /* - * We do serious communication with the server only in - * the READY state. - */ - - case NS_READY: - b = dgrp_send(nd, count) + local_buf; - break; - - /* - * Send off an error after receiving a bogus message - * from the server. - */ - - case NS_SEND_ERROR: - n = strlen(nd->nd_error); - - b[0] = 0xff; - b[1] = n; - memcpy(b + 2, nd->nd_error, n); - b += 2 + n; - - dgrp_net_idle(nd); - /* - * Set the active port count to zero. - */ - dgrp_chan_count(nd, 0); - break; - - default: - break; - } - - n = b - local_buf; - - if (n != 0) { - nd->nd_send_count++; - - nd->nd_tx_byte += n + nd->nd_link.lk_header_size; - nd->nd_tx_charge += n + nd->nd_link.lk_header_size; - } - - rtn = copy_to_user((void __user *)buf, local_buf, n); - if (rtn) { - rtn = -EFAULT; - goto done; - } - - *ppos += n; - - rtn = n; - - if (nd->nd_mon_buf) - dgrp_monitor_data(nd, RPDUMP_CLIENT, local_buf, n); - - /* - * Release the NET lock. - */ -done: - up(&nd->nd_net_semaphore); - - return rtn; -} - -/** - * dgrp_receive() -- decode data packets received from the remote PortServer. - * @nd: pointer to a node structure - */ -static void dgrp_receive(struct nd_struct *nd) -{ - struct ch_struct *ch; - u8 *buf; - u8 *b; - u8 *dbuf; - char *error; - long port; - long dlen; - long plen; - long remain; - long n; - long mlast; - long elast; - long mstat; - long estat; - - char ID[3]; - - nd->nd_tx_time = jiffies; - - ID_TO_CHAR(nd->nd_ID, ID); - - b = buf = nd->nd_iobuf; - remain = nd->nd_remain; - - /* - * Loop to process Realport protocol packets. - */ - - while (remain > 0) { - int n0 = b[0] >> 4; - int n1 = b[0] & 0x0f; - - if (n0 <= 12) { - port = (nd->nd_rx_module << 4) + n1; - - if (port >= nd->nd_chan_count) { - error = "Improper Port Number"; - goto prot_error; - } - - ch = nd->nd_chan + port; - } else { - port = -1; - ch = NULL; - } - - /* - * Process by major packet type. - */ - - switch (n0) { - - /* - * Process 1-byte header data packet. - */ - - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - dlen = n0 + 1; - plen = dlen + 1; - - dbuf = b + 1; - goto data; - - /* - * Process 2-byte header data packet. - */ - - case 8: - if (remain < 3) - goto done; - - dlen = b[1]; - plen = dlen + 2; - - dbuf = b + 2; - goto data; - - /* - * Process 3-byte header data packet. - */ - - case 9: - if (remain < 4) - goto done; - - dlen = get_unaligned_be16(b + 1); - plen = dlen + 3; - - dbuf = b + 3; - - /* - * Common packet handling code. - */ - -data: - nd->nd_tx_work = 1; - - /* - * Otherwise data should appear only when we are - * in the CS_READY state. - */ - - if (ch->ch_state < CS_READY) { - error = "Data received before RWIN established"; - goto prot_error; - } - - /* - * Assure that the data received is within the - * allowable window. - */ - - n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff; - - if (dlen > n) { - error = "Receive data overrun"; - goto prot_error; - } - - /* - * If we received 3 or less characters, - * assume it is a human typing, and set RTIME - * to 10 milliseconds. - * - * If we receive 10 or more characters, - * assume its not a human typing, and set RTIME - * to 100 milliseconds. - */ - - if (ch->ch_edelay != DGRP_RTIME) { - if (ch->ch_rtime != ch->ch_edelay) { - ch->ch_rtime = ch->ch_edelay; - ch->ch_flag |= CH_PARAM; - } - } else if (dlen <= 3) { - if (ch->ch_rtime != 10) { - ch->ch_rtime = 10; - ch->ch_flag |= CH_PARAM; - } - } else { - if (ch->ch_rtime != DGRP_RTIME) { - ch->ch_rtime = DGRP_RTIME; - ch->ch_flag |= CH_PARAM; - } - } - - /* - * If a portion of the packet is outside the - * buffer, shorten the effective length of the - * data packet to be the amount of data received. - */ - - if (remain < plen) - dlen -= plen - remain; - - /* - * Detect if receive flush is now complete. - */ - - if ((ch->ch_flag & CH_RX_FLUSH) != 0 && - ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >= - ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { - ch->ch_flag &= ~CH_RX_FLUSH; - } - - /* - * If we are ready to receive, move the data into - * the receive buffer. - */ - - ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff; - - if (ch->ch_state == CS_READY && - (ch->ch_tun.un_open_count != 0) && - (ch->ch_tun.un_flag & UN_CLOSING) == 0 && - (ch->ch_cflag & CF_CREAD) != 0 && - (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 && - (ch->ch_send & RR_RX_FLUSH) == 0) { - - if (ch->ch_rin + dlen >= RBUF_MAX) { - n = RBUF_MAX - ch->ch_rin; - - memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n); - - ch->ch_rin = 0; - dbuf += n; - dlen -= n; - } - - memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen); - - ch->ch_rin += dlen; - - - /* - * If we are not in fastcook mode, or - * if there is a fastcook thread - * waiting for data, send the data to - * the line discipline. - */ - - if ((ch->ch_flag & CH_FAST_READ) == 0 || - ch->ch_inwait != 0) { - dgrp_input(ch); - } - - /* - * If there is a read thread waiting - * in select, and we are in fastcook - * mode, wake him up. - */ - - if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) && - (ch->ch_flag & CH_FAST_READ) != 0) - wake_up_interruptible(&ch->ch_tun.un_tty->read_wait); - - /* - * Wake any thread waiting in the - * fastcook loop. - */ - - if ((ch->ch_flag & CH_INPUT) != 0) { - ch->ch_flag &= ~CH_INPUT; - - wake_up_interruptible(&ch->ch_flag_wait); - } - } - - /* - * Fabricate and insert a data packet header to - * preced the remaining data when it comes in. - */ - - if (remain < plen) { - dlen = plen - remain; - b = buf; - - b[0] = 0x90 + n1; - put_unaligned_be16(dlen, b + 1); - - remain = 3; - goto done; - } - break; - - /* - * Handle Window Sequence packets. - */ - - case 10: - plen = 3; - if (remain < plen) - goto done; - - nd->nd_tx_work = 1; - - { - ushort tpos = get_unaligned_be16(b + 1); - - ushort ack = (tpos - ch->ch_s_tpos) & 0xffff; - ushort unack = (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff; - ushort notify = (ch->ch_s_treq - ch->ch_s_tpos) & 0xffff; - - if (ch->ch_state < CS_READY || ack > unack) { - error = "Improper Window Sequence"; - goto prot_error; - } - - ch->ch_s_tpos = tpos; - - if (notify <= ack) - ch->ch_s_treq = tpos; - } - break; - - /* - * Handle Command response packets. - */ - - case 11: - - /* - * RealPort engine fix - 03/11/2004 - * - * This check did not used to be here. - * - * We were using b[1] without verifying that the data - * is actually there and valid. On a split packet, it - * might not be yet. - * - * NOTE: I have never actually seen the failure happen - * under Linux, but since I have seen it occur - * under both Solaris and HP-UX, the assumption - * is that it *could* happen here as well... - */ - if (remain < 2) - goto done; - - - switch (b[1]) { - - /* - * Handle Open Response. - */ - - case 11: - plen = 6; - if (remain < plen) - goto done; - - nd->nd_tx_work = 1; - - { - int req = b[2]; - int resp = b[3]; - port = get_unaligned_be16(b + 4); - - if (port >= nd->nd_chan_count) { - error = "Open channel number out of range"; - goto prot_error; - } - - ch = nd->nd_chan + port; - - /* - * How we handle an open response depends primarily - * on our current channel state. - */ - - switch (ch->ch_state) { - case CS_IDLE: - - /* - * Handle a delayed open. - */ - - if (ch->ch_otype_waiting != 0 && - req == ch->ch_otype_waiting && - resp == 0) { - ch->ch_otype = req; - ch->ch_otype_waiting = 0; - ch->ch_state = CS_SEND_QUERY; - break; - } - goto open_error; - - case CS_WAIT_OPEN: - - /* - * Handle the open response. - */ - - if (req == ch->ch_otype) { - switch (resp) { - - /* - * On successful response, open the - * port and proceed normally. - */ - - case 0: - ch->ch_state = CS_SEND_QUERY; - break; - - /* - * On a busy response to a persistent open, - * remember that the open is pending. - */ - - case 1: - case 2: - if (req != OTYPE_IMMEDIATE) { - ch->ch_otype_waiting = req; - ch->ch_state = CS_IDLE; - break; - } - - /* - * Otherwise the server open failed. If - * the Unix port is open, hang it up. - */ - - default: - if (ch->ch_open_count != 0) { - ch->ch_flag |= CH_HANGUP; - dgrp_carrier(ch); - ch->ch_state = CS_IDLE; - break; - } - - ch->ch_open_error = resp; - ch->ch_state = CS_IDLE; - - wake_up_interruptible(&ch->ch_flag_wait); - } - break; - } - - /* - * Handle delayed response arrival preceding - * the open response we are waiting for. - */ - - if (ch->ch_otype_waiting != 0 && - req == ch->ch_otype_waiting && - resp == 0) { - ch->ch_otype = ch->ch_otype_waiting; - ch->ch_otype_waiting = 0; - ch->ch_state = CS_WAIT_FAIL; - break; - } - goto open_error; - - - case CS_WAIT_FAIL: - - /* - * Handle response to immediate open arriving - * after a delayed open success. - */ - - if (req == OTYPE_IMMEDIATE) { - ch->ch_state = CS_SEND_QUERY; - break; - } - goto open_error; - - - case CS_WAIT_CANCEL: - /* - * Handle delayed open response arriving before - * the cancel response. - */ - - if (req == ch->ch_otype_waiting && - resp == 0) { - ch->ch_otype_waiting = 0; - break; - } - - /* - * Handle cancel response. - */ - - if (req == 4 && resp == 0) { - ch->ch_otype_waiting = 0; - ch->ch_state = CS_IDLE; - break; - } - goto open_error; - - - case CS_WAIT_CLOSE: - /* - * Handle a successful response to a port - * close. - */ - - if (req >= 3) { - ch->ch_state = CS_IDLE; - break; - } - goto open_error; - -open_error: - default: - { - error = "Improper Open Response"; - goto prot_error; - } - } - } - break; - - /* - * Handle Synchronize Response. - */ - - case 13: - plen = 3; - if (remain < plen) - goto done; - { - int seq = b[2]; - int s; - - /* - * If channel was waiting for this sync response, - * unset the flag, and wake up anyone waiting - * on the event. - */ - if (ch->ch_flag & CH_WAITING_SYNC) { - ch->ch_flag &= ~(CH_WAITING_SYNC); - wake_up_interruptible(&ch->ch_flag_wait); - } - - if (((seq - nd->nd_seq_out) & SEQ_MASK) >= - ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { - break; - } - - for (s = nd->nd_seq_out;; s = (s + 1) & SEQ_MASK) { - if (nd->nd_seq_wait[s] != 0) { - nd->nd_seq_wait[s] = 0; - - wake_up_interruptible(&nd->nd_seq_wque[s]); - } - - nd->nd_unack -= nd->nd_seq_size[s]; - - if (s == seq) - break; - } - - nd->nd_seq_out = (seq + 1) & SEQ_MASK; - } - break; - - /* - * Handle Sequence Response. - */ - - case 15: - plen = 6; - if (remain < plen) - goto done; - - { - /* Record that we have received the Sequence - * Response, but we aren't interested in the - * sequence numbers. We were using RIN like it - * was ROUT and that was causing problems, - * fixed 7-13-2001 David Fries. See comment in - * drp.h for ch_s_rin variable. - int rin = get_unaligned_be16(b + 2); - int tpos = get_unaligned_be16(b + 4); - */ - - ch->ch_send &= ~RR_SEQUENCE; - ch->ch_expect &= ~RR_SEQUENCE; - } - goto check_query; - - /* - * Handle Status Response. - */ - - case 17: - plen = 5; - if (remain < plen) - goto done; - - { - ch->ch_s_elast = get_unaligned_be16(b + 2); - ch->ch_s_mlast = b[4]; - - ch->ch_expect &= ~RR_STATUS; - ch->ch_send &= ~RR_STATUS; - - /* - * CH_PHYS_CD is cleared because something _could_ be - * waiting for the initial sense of carrier... and if - * carrier is high immediately, we want to be sure to - * wake them as soon as possible. - */ - ch->ch_flag &= ~CH_PHYS_CD; - - dgrp_carrier(ch); - } - goto check_query; - - /* - * Handle Line Error Response. - */ - - case 19: - plen = 14; - if (remain < plen) - goto done; - - break; - - /* - * Handle Buffer Response. - */ - - case 21: - plen = 6; - if (remain < plen) - goto done; - - { - ch->ch_s_rsize = get_unaligned_be16(b + 2); - ch->ch_s_tsize = get_unaligned_be16(b + 4); - - ch->ch_send &= ~RR_BUFFER; - ch->ch_expect &= ~RR_BUFFER; - } - goto check_query; - - /* - * Handle Port Capability Response. - */ - - case 23: - plen = 32; - if (remain < plen) - goto done; - - { - ch->ch_send &= ~RR_CAPABILITY; - ch->ch_expect &= ~RR_CAPABILITY; - } - - /* - * When all queries are complete, set those parameters - * derived from the query results, then transition - * to the READY state. - */ - -check_query: - if (ch->ch_state == CS_WAIT_QUERY && - (ch->ch_expect & (RR_SEQUENCE | - RR_STATUS | - RR_BUFFER | - RR_CAPABILITY)) == 0) { - ch->ch_tmax = ch->ch_s_tsize / 4; - - if (ch->ch_edelay == DGRP_TTIME) - ch->ch_ttime = DGRP_TTIME; - else - ch->ch_ttime = ch->ch_edelay; - - ch->ch_rmax = ch->ch_s_rsize / 4; - - if (ch->ch_edelay == DGRP_RTIME) - ch->ch_rtime = DGRP_RTIME; - else - ch->ch_rtime = ch->ch_edelay; - - ch->ch_rlow = 2 * ch->ch_s_rsize / 8; - ch->ch_rhigh = 6 * ch->ch_s_rsize / 8; - - ch->ch_state = CS_READY; - - nd->nd_tx_work = 1; - wake_up_interruptible(&ch->ch_flag_wait); - - } - break; - - default: - goto decode_error; - } - break; - - /* - * Handle Events. - */ - - case 12: - plen = 4; - if (remain < plen) - goto done; - - mlast = ch->ch_s_mlast; - elast = ch->ch_s_elast; - - mstat = ch->ch_s_mlast = b[1]; - estat = ch->ch_s_elast = get_unaligned_be16(b + 2); - - /* - * Handle modem changes. - */ - - if (((mstat ^ mlast) & DM_CD) != 0) - dgrp_carrier(ch); - - - /* - * Handle received break. - */ - - if ((estat & ~elast & EV_RXB) != 0 && - (ch->ch_tun.un_open_count != 0) && - I_BRKINT(ch->ch_tun.un_tty) && - !(I_IGNBRK(ch->ch_tun.un_tty))) { - - tty_buffer_request_room(&ch->port, 1); - tty_insert_flip_char(&ch->port, 0, TTY_BREAK); - tty_flip_buffer_push(&ch->port); - - } - - /* - * On transmit break complete, if more break traffic - * is waiting then send it. Otherwise wake any threads - * waiting for transmitter empty. - */ - - if ((~estat & elast & EV_TXB) != 0 && - (ch->ch_expect & RR_TX_BREAK) != 0) { - - nd->nd_tx_work = 1; - - ch->ch_expect &= ~RR_TX_BREAK; - - if (ch->ch_break_time != 0) { - ch->ch_send |= RR_TX_BREAK; - } else { - ch->ch_send &= ~RR_TX_BREAK; - ch->ch_flag &= ~CH_TX_BREAK; - wake_up_interruptible(&ch->ch_flag_wait); - } - } - break; - - case 13: - case 14: - error = "Unrecognized command"; - goto prot_error; - - /* - * Decode Special Codes. - */ - - case 15: - switch (n1) { - /* - * One byte module select. - */ - - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - plen = 1; - nd->nd_rx_module = n1; - break; - - /* - * Two byte module select. - */ - - case 8: - plen = 2; - if (remain < plen) - goto done; - - nd->nd_rx_module = b[1]; - break; - - /* - * ID Request packet. - */ - - case 11: - if (remain < 4) - goto done; - - plen = get_unaligned_be16(b + 2); - - if (plen < 12 || plen > 1000) { - error = "Response Packet length error"; - goto prot_error; - } - - nd->nd_tx_work = 1; - - switch (b[1]) { - /* - * Echo packet. - */ - - case 0: - nd->nd_send |= NR_ECHO; - break; - - /* - * ID Response packet. - */ - - case 1: - nd->nd_send |= NR_IDENT; - break; - - /* - * ID Response packet. - */ - - case 32: - nd->nd_send |= NR_PASSWORD; - break; - - } - break; - - /* - * Various node-level response packets. - */ - - case 12: - if (remain < 4) - goto done; - - plen = get_unaligned_be16(b + 2); - - if (plen < 4 || plen > 1000) { - error = "Response Packet length error"; - goto prot_error; - } - - nd->nd_tx_work = 1; - - switch (b[1]) { - /* - * Echo packet. - */ - - case 0: - nd->nd_expect &= ~NR_ECHO; - break; - - /* - * Product Response Packet. - */ - - case 1: - { - int desclen; - - nd->nd_hw_ver = (b[8] << 8) | b[9]; - nd->nd_sw_ver = (b[10] << 8) | b[11]; - nd->nd_hw_id = b[6]; - desclen = (plen - 12 > MAX_DESC_LEN - 1) ? MAX_DESC_LEN - 1 : - plen - 12; - - if (desclen <= 0) { - error = "Response Packet desclen error"; - goto prot_error; - } - - strncpy(nd->nd_ps_desc, b + 12, desclen); - nd->nd_ps_desc[desclen] = 0; - } - - nd->nd_expect &= ~NR_IDENT; - break; - - /* - * Capability Response Packet. - */ - - case 2: - { - int nn = get_unaligned_be16(b + 4); - - if (nn > CHAN_MAX) - nn = CHAN_MAX; - - dgrp_chan_count(nd, nn); - } - - nd->nd_expect &= ~NR_CAPABILITY; - break; - - /* - * VPD Response Packet. - */ - - case 15: - /* - * NOTE: case 15 is here ONLY because the EtherLite - * is broken, and sends a response to 24 back as 15. - * To resolve this, the EtherLite firmware is now - * fixed to send back 24 correctly, but, for backwards - * compatibility, we now have reserved 15 for the - * bad EtherLite response to 24 as well. - */ - - /* Fallthru! */ - - case 24: - - /* - * If the product doesn't support VPD, - * it will send back a null IDRESP, - * which is a length of 4 bytes. - */ - if (plen > 4) { - memcpy(nd->nd_vpd, b + 4, min(plen - 4, (long) VPDSIZE)); - nd->nd_vpd_len = min(plen - 4, (long) VPDSIZE); - } - - nd->nd_expect &= ~NR_VPD; - break; - - default: - goto decode_error; - } - - if (nd->nd_expect == 0 && - nd->nd_state == NS_WAIT_QUERY) { - nd->nd_state = NS_READY; - } - break; - - /* - * Debug packet. - */ - - case 14: - if (remain < 4) - goto done; - - plen = get_unaligned_be16(b + 2) + 4; - - if (plen > 1000) { - error = "Debug Packet too large"; - goto prot_error; - } - - if (remain < plen) - goto done; - break; - - /* - * Handle reset packet. - */ - - case 15: - if (remain < 2) - goto done; - - plen = 2 + b[1]; - - if (remain < plen) - goto done; - - nd->nd_tx_work = 1; - - n = b[plen]; - b[plen] = 0; - - b[plen] = n; - - error = "Client Reset Acknowledge"; - goto prot_error; - - default: - goto decode_error; - } - break; - - default: - goto decode_error; - } - - b += plen; - remain -= plen; - } - - /* - * When the buffer is exhausted, copy any data left at the - * top of the buffer back down to the bottom for the next - * read request. - */ - -done: - if (remain > 0 && b != buf) - memcpy(buf, b, remain); - - nd->nd_remain = remain; - return; - -/* - * Handle a decode error. - */ - -decode_error: - error = "Protocol decode error"; - -/* - * Handle a general protocol error. - */ - -prot_error: - nd->nd_remain = 0; - nd->nd_state = NS_SEND_ERROR; - nd->nd_error = error; -} - -/* - * dgrp_net_write() -- write data to the network device. - * - * A zero byte write indicates that the connection to the RealPort - * device has been broken. - * - * A non-zero write indicates data from the RealPort device. - */ -static ssize_t dgrp_net_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct nd_struct *nd; - ssize_t rtn = 0; - long n; - long total = 0; - - /* - * Get the node pointer, and quit if it doesn't exist. - */ - nd = (struct nd_struct *)(file->private_data); - if (!nd) - return -ENXIO; - - /* - * Grab the NET lock. - */ - down(&nd->nd_net_semaphore); - - nd->nd_write_count++; - - /* - * Handle disconnect. - */ - - if (count == 0) { - dgrp_net_idle(nd); - /* - * Set the active port count to zero. - */ - dgrp_chan_count(nd, 0); - goto unlock; - } - - /* - * Loop to process entire receive packet. - */ - - while (count > 0) { - n = UIO_MAX - nd->nd_remain; - - if (n > count) - n = count; - - nd->nd_rx_byte += n + nd->nd_link.lk_header_size; - - rtn = copy_from_user(nd->nd_iobuf + nd->nd_remain, - (void __user *) buf + total, n); - if (rtn) { - rtn = -EFAULT; - goto unlock; - } - - *ppos += n; - - total += n; - - count -= n; - - if (nd->nd_mon_buf) - dgrp_monitor_data(nd, RPDUMP_SERVER, - nd->nd_iobuf + nd->nd_remain, n); - - nd->nd_remain += n; - - dgrp_receive(nd); - } - - rtn = total; - -unlock: - /* - * Release the NET lock. - */ - up(&nd->nd_net_semaphore); - - return rtn; -} - - -/* - * dgrp_net_select() - * Determine whether a device is ready to be read or written to, and - * sleep if not. - */ -static unsigned int dgrp_net_select(struct file *file, - struct poll_table_struct *table) -{ - unsigned int retval = 0; - struct nd_struct *nd = file->private_data; - - poll_wait(file, &nd->nd_tx_waitq, table); - - if (nd->nd_tx_ready) - retval |= POLLIN | POLLRDNORM; /* Conditionally readable */ - - retval |= POLLOUT | POLLWRNORM; /* Always writeable */ - - return retval; -} - -/* - * dgrp_net_ioctl - * - * Implement those functions which allow the network daemon to control - * the network parameters in the driver. The ioctls include ones to - * get and set the link speed parameters for the PortServer. - */ -static long dgrp_net_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct nd_struct *nd; - int rtn = 0; - long size = _IOC_SIZE(cmd); - struct link_struct link; - - nd = file->private_data; - - if (_IOC_DIR(cmd) & _IOC_READ) - rtn = access_ok(VERIFY_WRITE, (void __user *) arg, size); - else if (_IOC_DIR(cmd) & _IOC_WRITE) - rtn = access_ok(VERIFY_READ, (void __user *) arg, size); - - if (!rtn) - return rtn; - - switch (cmd) { - case DIGI_SETLINK: - if (size != sizeof(struct link_struct)) - return -EINVAL; - - if (copy_from_user(&link, (void __user *)arg, size)) - return -EFAULT; - - if (link.lk_fast_rate < 9600) - link.lk_fast_rate = 9600; - - if (link.lk_slow_rate < 2400) - link.lk_slow_rate = 2400; - - if (link.lk_fast_rate > 10000000) - link.lk_fast_rate = 10000000; - - if (link.lk_slow_rate > link.lk_fast_rate) - link.lk_slow_rate = link.lk_fast_rate; - - if (link.lk_fast_delay > 2000) - link.lk_fast_delay = 2000; - - if (link.lk_slow_delay > 10000) - link.lk_slow_delay = 10000; - - if (link.lk_fast_delay < 60) - link.lk_fast_delay = 60; - - if (link.lk_slow_delay < link.lk_fast_delay) - link.lk_slow_delay = link.lk_fast_delay; - - if (link.lk_header_size < 2) - link.lk_header_size = 2; - - if (link.lk_header_size > 128) - link.lk_header_size = 128; - - link.lk_fast_rate /= 8 * 1000 / dgrp_poll_tick; - link.lk_slow_rate /= 8 * 1000 / dgrp_poll_tick; - - link.lk_fast_delay /= dgrp_poll_tick; - link.lk_slow_delay /= dgrp_poll_tick; - - nd->nd_link = link; - - break; - - case DIGI_GETLINK: - if (size != sizeof(struct link_struct)) - return -EINVAL; - - if (copy_to_user((void __user *)arg, (void *)(&nd->nd_link), - size)) - return -EFAULT; - - break; - - default: - return -EINVAL; - - } - - return 0; -} - -/** - * dgrp_poll_handler() -- handler for poll timer - * - * As each timer expires, it determines (a) whether the "transmit" - * waiter needs to be woken up, and (b) whether the poller needs to - * be rescheduled. - */ -void dgrp_poll_handler(unsigned long arg) -{ - struct dgrp_poll_data *poll_data; - struct nd_struct *nd; - struct link_struct *lk; - ulong time; - ulong poll_time; - ulong freq; - ulong lock_flags; - - poll_data = (struct dgrp_poll_data *) arg; - freq = 1000 / poll_data->poll_tick; - poll_data->poll_round += 17; - - if (poll_data->poll_round >= freq) - poll_data->poll_round -= freq; - - /* - * Loop to process all open nodes. - * - * For each node, determine the rate at which it should - * be transmitting data. Then if the node should wake up - * and transmit data now, enable the net receive select - * to get the transmit going. - */ - - list_for_each_entry(nd, &nd_struct_list, list) { - - lk = &nd->nd_link; - - /* - * Decrement statistics. These are only for use with - * KME, so don't worry that the operations are done - * unlocked, and so the results are occasionally wrong. - */ - - nd->nd_read_count -= (nd->nd_read_count + - poll_data->poll_round) / freq; - nd->nd_write_count -= (nd->nd_write_count + - poll_data->poll_round) / freq; - nd->nd_send_count -= (nd->nd_send_count + - poll_data->poll_round) / freq; - nd->nd_tx_byte -= (nd->nd_tx_byte + - poll_data->poll_round) / freq; - nd->nd_rx_byte -= (nd->nd_rx_byte + - poll_data->poll_round) / freq; - - /* - * Wake the daemon to transmit data only when there is - * enough byte credit to send data. - * - * The results are approximate because the operations - * are performed unlocked, and we are inspecting - * data asynchronously updated elsewhere. The whole - * thing is just approximation anyway, so that should - * be okay. - */ - - if (lk->lk_slow_rate >= UIO_MAX) { - - nd->nd_delay = 0; - nd->nd_rate = UIO_MAX; - - nd->nd_tx_deposit = nd->nd_tx_charge + 3 * UIO_MAX; - nd->nd_tx_credit = 3 * UIO_MAX; - - } else { - - long rate; - long delay; - long deposit; - long charge; - long size; - long excess; - - long seq_in = nd->nd_seq_in; - long seq_out = nd->nd_seq_out; - - /* - * If there are no outstanding packets, run at the - * fastest rate. - */ - - if (seq_in == seq_out) { - delay = 0; - rate = lk->lk_fast_rate; - } - - /* - * Otherwise compute the transmit rate based on the - * delay since the oldest packet. - */ - - else { - /* - * The actual delay is computed as the - * time since the oldest unacknowledged - * packet was sent, minus the time it - * took to send that packet to the server. - */ - - delay = ((jiffies - nd->nd_seq_time[seq_out]) - - (nd->nd_seq_size[seq_out] / - lk->lk_fast_rate)); - - /* - * If the delay is less than the "fast" - * delay, transmit full speed. If greater - * than the "slow" delay, transmit at the - * "slow" speed. In between, interpolate - * between the fast and slow speeds. - */ - - rate = - (delay <= lk->lk_fast_delay ? - lk->lk_fast_rate : - delay >= lk->lk_slow_delay ? - lk->lk_slow_rate : - (lk->lk_slow_rate + - (lk->lk_slow_delay - delay) * - (lk->lk_fast_rate - lk->lk_slow_rate) / - (lk->lk_slow_delay - lk->lk_fast_delay) - ) - ); - } - - nd->nd_delay = delay; - nd->nd_rate = rate; - - /* - * Increase the transmit credit by depositing the - * current transmit rate. - */ - - deposit = nd->nd_tx_deposit; - charge = nd->nd_tx_charge; - - deposit += rate; - - /* - * If the available transmit credit becomes too large, - * reduce the deposit to correct the value. - * - * Too large is the max of: - * 6 times the header size - * 3 times the current transmit rate. - */ - - size = 2 * nd->nd_link.lk_header_size; - - if (size < rate) - size = rate; - - size *= 3; - - excess = deposit - charge - size; - - if (excess > 0) - deposit -= excess; - - nd->nd_tx_deposit = deposit; - nd->nd_tx_credit = deposit - charge; - - /* - * Wake the transmit task only if the transmit credit - * is at least 3 times the transmit header size. - */ - - size = 3 * lk->lk_header_size; - - if (nd->nd_tx_credit < size) - continue; - } - - - /* - * Enable the READ select to wake the daemon if there - * is useful work for the drp_read routine to perform. - */ - - if (waitqueue_active(&nd->nd_tx_waitq) && - (nd->nd_tx_work != 0 || - (ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX)) { - nd->nd_tx_ready = 1; - - wake_up_interruptible(&nd->nd_tx_waitq); - - /* not needed */ - /* nd->nd_flag &= ~ND_SELECT; */ - } - } - - - /* - * Schedule ourself back at the nominal wakeup interval. - */ - spin_lock_irqsave(&poll_data->poll_lock, lock_flags); - - poll_data->node_active_count--; - if (poll_data->node_active_count > 0) { - poll_data->node_active_count++; - poll_time = poll_data->timer.expires + - poll_data->poll_tick * HZ / 1000; - - time = poll_time - jiffies; - - if (time >= 2 * poll_data->poll_tick) - poll_time = jiffies + dgrp_poll_tick * HZ / 1000; - - poll_data->timer.expires = poll_time; - add_timer(&poll_data->timer); - } - - spin_unlock_irqrestore(&poll_data->poll_lock, lock_flags); -} diff --git a/drivers/staging/dgrp/dgrp_ports_ops.c b/drivers/staging/dgrp/dgrp_ports_ops.c deleted file mode 100644 index 4ce030815f27..000000000000 --- a/drivers/staging/dgrp/dgrp_ports_ops.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * - * Copyright 1999-2000 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* - * - * Filename: - * - * dgrp_ports_ops.c - * - * Description: - * - * Handle the file operations required for the /proc/dgrp/ports/... - * devices. Basically gathers tty status for the node and returns it. - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include -#include - -#include "dgrp_common.h" - -/* File operation declarations */ -static int dgrp_ports_open(struct inode *, struct file *); - -const struct file_operations dgrp_ports_ops = { - .owner = THIS_MODULE, - .open = dgrp_ports_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -static void *dgrp_ports_seq_start(struct seq_file *seq, loff_t *pos) -{ - if (*pos == 0) - seq_puts(seq, "#num tty_open pr_open tot_wait MSTAT IFLAG OFLAG CFLAG BPS DIGIFLAGS\n"); - - return pos; -} - -static void *dgrp_ports_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct nd_struct *nd = seq->private; - - if (*pos >= nd->nd_chan_count) - return NULL; - - *pos += 1; - - return pos; -} - -static void dgrp_ports_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int dgrp_ports_seq_show(struct seq_file *seq, void *v) -{ - loff_t *pos = v; - struct nd_struct *nd; - struct ch_struct *ch; - struct un_struct *tun, *pun; - unsigned int totcnt; - - nd = seq->private; - if (!nd) - return 0; - - if (*pos >= nd->nd_chan_count) - return 0; - - ch = &nd->nd_chan[*pos]; - tun = &ch->ch_tun; - pun = &ch->ch_pun; - - /* - * If port is not open and no one is waiting to - * open it, the modem signal values can't be - * trusted, and will be zeroed. - */ - totcnt = tun->un_open_count + - pun->un_open_count + - ch->ch_wait_count[0] + - ch->ch_wait_count[1] + - ch->ch_wait_count[2]; - - seq_printf(seq, "%02d %02d %02d %02d 0x%04X 0x%04X 0x%04X 0x%04X %-6d 0x%04X\n", - (int) *pos, - tun->un_open_count, - pun->un_open_count, - ch->ch_wait_count[0] + - ch->ch_wait_count[1] + - ch->ch_wait_count[2], - (totcnt ? ch->ch_s_mlast : 0), - ch->ch_s_iflag, - ch->ch_s_oflag, - ch->ch_s_cflag, - (ch->ch_s_brate ? (1843200 / ch->ch_s_brate) : 0), - ch->ch_digi.digi_flags); - - return 0; -} - -static const struct seq_operations ports_seq_ops = { - .start = dgrp_ports_seq_start, - .next = dgrp_ports_seq_next, - .stop = dgrp_ports_seq_stop, - .show = dgrp_ports_seq_show, -}; - -/** - * dgrp_ports_open -- open the /proc/dgrp/ports/... device - * @inode: struct inode * - * @file: struct file * - * - * Open function to open the /proc/dgrp/ports device for a PortServer. - * This is the open function for struct file_operations - */ -static int dgrp_ports_open(struct inode *inode, struct file *file) -{ - struct seq_file *seq; - int rtn; - - rtn = seq_open(file, &ports_seq_ops); - if (!rtn) { - seq = file->private_data; - seq->private = PDE_DATA(inode); - } - - return rtn; -} diff --git a/drivers/staging/dgrp/dgrp_specproc.c b/drivers/staging/dgrp/dgrp_specproc.c deleted file mode 100644 index 205d80ef4455..000000000000 --- a/drivers/staging/dgrp/dgrp_specproc.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * James Puzzo - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_specproc.c - * - * Description: - * - * Handle the "config" proc entry for the linux realport device driver - * and provide slots for the "net" and "mon" devices - * - * Author: - * - * James A. Puzzo - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dgrp_common.h" - -static struct proc_dir_entry *dgrp_proc_dir_entry; - -static int dgrp_add_id(long id); -static int dgrp_remove_nd(struct nd_struct *nd); -static struct proc_dir_entry *add_proc_file(struct nd_struct *node, - struct proc_dir_entry *root, - const struct file_operations *fops); - -/* File operation declarations */ -static int parse_write_config(char *); - -static ssize_t dgrp_config_proc_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *pos); - -static int dgrp_nodeinfo_proc_open(struct inode *inode, struct file *file); -static int dgrp_info_proc_open(struct inode *inode, struct file *file); -static int dgrp_config_proc_open(struct inode *inode, struct file *file); - -static const struct file_operations config_proc_file_ops = { - .owner = THIS_MODULE, - .open = dgrp_config_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, - .write = dgrp_config_proc_write, -}; - -static const struct file_operations info_proc_file_ops = { - .owner = THIS_MODULE, - .open = dgrp_info_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations nodeinfo_proc_file_ops = { - .owner = THIS_MODULE, - .open = dgrp_nodeinfo_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static struct proc_dir_entry *net_entry_pointer; -static struct proc_dir_entry *mon_entry_pointer; -static struct proc_dir_entry *dpa_entry_pointer; -static struct proc_dir_entry *ports_entry_pointer; - -static void remove_files(struct nd_struct *nd) -{ - char buf[3]; - ID_TO_CHAR(nd->nd_ID, buf); - dgrp_remove_node_class_sysfs_files(nd); - if (nd->nd_net_de) - remove_proc_entry(buf, net_entry_pointer); - if (nd->nd_mon_de) - remove_proc_entry(buf, mon_entry_pointer); - if (nd->nd_dpa_de) - remove_proc_entry(buf, dpa_entry_pointer); - if (nd->nd_ports_de) - remove_proc_entry(buf, ports_entry_pointer); -} - -void dgrp_unregister_proc(void) -{ - net_entry_pointer = NULL; - mon_entry_pointer = NULL; - dpa_entry_pointer = NULL; - ports_entry_pointer = NULL; - - if (dgrp_proc_dir_entry) { - struct nd_struct *nd; - list_for_each_entry(nd, &nd_struct_list, list) - remove_files(nd); - remove_proc_entry("dgrp/config", NULL); - remove_proc_entry("dgrp/info", NULL); - remove_proc_entry("dgrp/nodeinfo", NULL); - remove_proc_entry("dgrp/net", NULL); - remove_proc_entry("dgrp/mon", NULL); - remove_proc_entry("dgrp/dpa", NULL); - remove_proc_entry("dgrp/ports", NULL); - remove_proc_entry("dgrp", NULL); - dgrp_proc_dir_entry = NULL; - } -} - -void dgrp_register_proc(void) -{ - /* - * Register /proc/dgrp - */ - dgrp_proc_dir_entry = proc_mkdir("dgrp", NULL); - if (!dgrp_proc_dir_entry) - return; - proc_create("dgrp/config", 0644, NULL, &config_proc_file_ops); - proc_create("dgrp/info", 0644, NULL, &info_proc_file_ops); - proc_create("dgrp/nodeinfo", 0644, NULL, &nodeinfo_proc_file_ops); - net_entry_pointer = proc_mkdir_mode("dgrp/net", 0500, NULL); - mon_entry_pointer = proc_mkdir_mode("dgrp/mon", 0500, NULL); - dpa_entry_pointer = proc_mkdir_mode("dgrp/dpa", 0500, NULL); - ports_entry_pointer = proc_mkdir_mode("dgrp/ports", 0500, NULL); -} - -static void *dgrp_config_proc_start(struct seq_file *m, loff_t *pos) -{ - return seq_list_start_head(&nd_struct_list, *pos); -} - -static void *dgrp_config_proc_next(struct seq_file *p, void *v, loff_t *pos) -{ - return seq_list_next(v, &nd_struct_list, pos); -} - -static void dgrp_config_proc_stop(struct seq_file *m, void *v) -{ -} - -static int dgrp_config_proc_show(struct seq_file *m, void *v) -{ - struct nd_struct *nd; - char tmp_id[4]; - - if (v == &nd_struct_list) { - seq_puts(m, "#-----------------------------------------------------------------------------\n"); - seq_puts(m, "# Avail\n"); - seq_puts(m, "# ID Major State Ports\n"); - return 0; - } - - nd = list_entry(v, struct nd_struct, list); - - ID_TO_CHAR(nd->nd_ID, tmp_id); - - seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n", - tmp_id, - nd->nd_major, - ND_STATE_STR(nd->nd_state), - nd->nd_chan_count); - - return 0; -} - -static const struct seq_operations proc_config_ops = { - .start = dgrp_config_proc_start, - .next = dgrp_config_proc_next, - .stop = dgrp_config_proc_stop, - .show = dgrp_config_proc_show, -}; - -static int dgrp_config_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_config_ops); -} - - -/* - * When writing configuration information, each "record" (i.e. each - * write) is treated as an independent request. See the "parse" - * description for more details. - */ -static ssize_t dgrp_config_proc_write(struct file *file, - const char __user *buffer, - size_t count, loff_t *pos) -{ - ssize_t retval; - char *inbuf, *sp; - char *line, *ldelim; - - if (count > 32768) - return -EINVAL; - - inbuf = sp = vzalloc(count + 1); - if (!inbuf) - return -ENOMEM; - - if (copy_from_user(inbuf, buffer, count)) { - retval = -EFAULT; - goto done; - } - - inbuf[count] = 0; - - ldelim = "\n"; - - line = strpbrk(sp, ldelim); - while (line) { - *line = 0; - retval = parse_write_config(sp); - if (retval) - goto done; - - sp = line + 1; - line = strpbrk(sp, ldelim); - } - - retval = count; -done: - vfree(inbuf); - return retval; -} - -/* - * ------------------------------------------------------------------------ - * - * The following are the functions to parse input - * - * ------------------------------------------------------------------------ - */ -static inline char *skip_past_ws(const char *str) -{ - while ((*str) && !isspace(*str)) - ++str; - - return skip_spaces(str); -} - -static int parse_id(char **c, char *cID) -{ - int tmp = **c; - - if (isalnum(tmp) || (tmp == '_')) - cID[0] = tmp; - else - return -EINVAL; - - (*c)++; tmp = **c; - - if (isalnum(tmp) || (tmp == '_')) { - cID[1] = tmp; - (*c)++; - } else - cID[1] = 0; - - return 0; -} - -static int parse_add_config(char *buf) -{ - char *c = buf; - int retval; - char cID[2]; - long ID; - - c = skip_past_ws(c); - - retval = parse_id(&c, cID); - if (retval < 0) - return retval; - - ID = CHAR_TO_ID(cID); - - c = skip_past_ws(c); - - return dgrp_add_id(ID); -} - -static int parse_del_config(char *buf) -{ - char *c = buf; - int retval; - struct nd_struct *nd; - char cID[2]; - long ID; - long major; - - c = skip_past_ws(c); - - retval = parse_id(&c, cID); - if (retval < 0) - return retval; - - ID = CHAR_TO_ID(cID); - - c = skip_past_ws(c); - - retval = kstrtol(c, 10, &major); - if (retval) - return retval; - - nd = nd_struct_get(major); - if (!nd) - return -EINVAL; - - if ((nd->nd_major != major) || (nd->nd_ID != ID)) - return -EINVAL; - - return dgrp_remove_nd(nd); -} - -static int parse_chg_config(char *buf) -{ - return -EINVAL; -} - -/* - * The passed character buffer represents a single configuration request. - * If the first character is a "+", it is parsed as a request to add a - * PortServer - * If the first character is a "-", it is parsed as a request to delete a - * PortServer - * If the first character is a "*", it is parsed as a request to change a - * PortServer - * Any other character (including whitespace) causes the record to be - * ignored. - */ -static int parse_write_config(char *buf) -{ - int retval; - - switch (buf[0]) { - case '+': - retval = parse_add_config(buf); - break; - case '-': - retval = parse_del_config(buf); - break; - case '*': - retval = parse_chg_config(buf); - break; - default: - retval = -EINVAL; - } - - return retval; -} - -static int dgrp_info_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "version: %s\n", DIGI_VERSION); - seq_puts(m, "register_with_sysfs: 1\n"); - seq_printf(m, "pollrate: 0x%08x\t(%d)\n", - dgrp_poll_tick, dgrp_poll_tick); - - return 0; -} - -static int dgrp_info_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, dgrp_info_proc_show, NULL); -} - - -static void *dgrp_nodeinfo_start(struct seq_file *m, loff_t *pos) -{ - return seq_list_start_head(&nd_struct_list, *pos); -} - -static void *dgrp_nodeinfo_next(struct seq_file *p, void *v, loff_t *pos) -{ - return seq_list_next(v, &nd_struct_list, pos); -} - -static void dgrp_nodeinfo_stop(struct seq_file *m, void *v) -{ -} - -static int dgrp_nodeinfo_show(struct seq_file *m, void *v) -{ - struct nd_struct *nd; - char hwver[8]; - char swver[8]; - char tmp_id[4]; - - if (v == &nd_struct_list) { - seq_puts(m, "#-----------------------------------------------------------------------------\n"); - seq_puts(m, "# HW HW SW\n"); - seq_puts(m, "# ID State Version ID Version Description\n"); - return 0; - } - - nd = list_entry(v, struct nd_struct, list); - - ID_TO_CHAR(nd->nd_ID, tmp_id); - - if (nd->nd_state == NS_READY) { - sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff, - nd->nd_hw_ver & 0xff); - sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff, - nd->nd_sw_ver & 0xff); - seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n", - tmp_id, - ND_STATE_STR(nd->nd_state), - hwver, - nd->nd_hw_id, - swver, - nd->nd_ps_desc); - - } else { - seq_printf(m, " %-2.2s %-10.10s\n", - tmp_id, - ND_STATE_STR(nd->nd_state)); - } - - return 0; -} - - -static const struct seq_operations nodeinfo_ops = { - .start = dgrp_nodeinfo_start, - .next = dgrp_nodeinfo_next, - .stop = dgrp_nodeinfo_stop, - .show = dgrp_nodeinfo_show, -}; - -static int dgrp_nodeinfo_proc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &nodeinfo_ops); -} - -/** - * dgrp_add_id() -- creates new nd struct and adds it to list - * @id: id of device to add - */ -static int dgrp_add_id(long id) -{ - struct nd_struct *nd; - int ret; - int i; - - nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL); - if (!nd) - return -ENOMEM; - - nd->nd_major = 0; - nd->nd_ID = id; - - spin_lock_init(&nd->nd_lock); - - init_waitqueue_head(&nd->nd_tx_waitq); - init_waitqueue_head(&nd->nd_mon_wqueue); - init_waitqueue_head(&nd->nd_dpa_wqueue); - sema_init(&nd->nd_mon_semaphore, 1); - sema_init(&nd->nd_net_semaphore, 1); - spin_lock_init(&nd->nd_dpa_lock); - nd->nd_state = NS_CLOSED; - for (i = 0; i < SEQ_MAX; i++) - init_waitqueue_head(&nd->nd_seq_wque[i]); - - /* setup the structures to get the major number */ - ret = dgrp_tty_init(nd); - if (ret) - goto error_out; - - nd->nd_major = nd->nd_serial_ttdriver->major; - - ret = nd_struct_add(nd); - if (ret) - goto error_out; - - dgrp_create_node_class_sysfs_files(nd); - nd->nd_net_de = add_proc_file(nd, net_entry_pointer, &dgrp_net_ops); - nd->nd_mon_de = add_proc_file(nd, mon_entry_pointer, &dgrp_mon_ops); - nd->nd_dpa_de = add_proc_file(nd, dpa_entry_pointer, &dgrp_dpa_ops); - nd->nd_ports_de = add_proc_file(nd, ports_entry_pointer, - &dgrp_ports_ops); - return 0; - - /* FIXME this guy should free the tty driver stored in nd and destroy - * all channel ports */ -error_out: - kfree(nd); - return ret; - -} - -static int dgrp_remove_nd(struct nd_struct *nd) -{ - int ret; - - /* Check to see if the selected structure is in use */ - if (nd->nd_tty_ref_cnt) - return -EBUSY; - - remove_files(nd); - - dgrp_tty_uninit(nd); - - ret = nd_struct_del(nd); - if (ret) - return ret; - - kfree(nd); - return 0; -} - -static struct proc_dir_entry *add_proc_file(struct nd_struct *node, - struct proc_dir_entry *root, - const struct file_operations *fops) -{ - char buf[3]; - ID_TO_CHAR(node->nd_ID, buf); - return proc_create_data(buf, 0600, root, fops, node); -} diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c deleted file mode 100644 index 2f9345ff0abb..000000000000 --- a/drivers/staging/dgrp/dgrp_sysfs.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright 2004 Digi International (www.digi.com) - * Scott H Kilau - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -#include "dgrp_common.h" - -#include -#include -#include -#include -#include -#include -#include - - -#define PORTSERVER_DIVIDEND 1843200 -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 -#define SERIAL_TYPE_XPRINT 3 - - -static struct class *dgrp_class; -static struct device *dgrp_class_nodes_dev; -static struct device *dgrp_class_global_settings_dev; - - -static ssize_t dgrp_class_version_show(struct class *class, - struct class_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", DIGI_VERSION); -} -static CLASS_ATTR(driver_version, 0400, dgrp_class_version_show, NULL); - - -static ssize_t dgrp_class_register_with_sysfs_show(struct device *c, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "1\n"); -} -static DEVICE_ATTR(register_with_sysfs, 0400, - dgrp_class_register_with_sysfs_show, NULL); - - -static ssize_t dgrp_class_pollrate_show(struct device *c, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_poll_tick); -} - -static ssize_t dgrp_class_pollrate_store(struct device *c, - struct device_attribute *attr, - const char *buf, size_t count) -{ - if (sscanf(buf, "0x%x\n", &dgrp_poll_tick) != 1) - return -EINVAL; - - return count; -} -static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show, - dgrp_class_pollrate_store); - -static struct attribute *dgrp_sysfs_global_settings_entries[] = { - &dev_attr_pollrate.attr, - &dev_attr_register_with_sysfs.attr, - NULL -}; - - -static struct attribute_group dgrp_global_settings_attribute_group = { - .name = NULL, - .attrs = dgrp_sysfs_global_settings_entries, -}; - - - -int dgrp_create_class_sysfs_files(void) -{ - int ret = 0; - int max_majors = 1U << (32 - MINORBITS); - - dgrp_class = class_create(THIS_MODULE, "digi_realport"); - if (IS_ERR(dgrp_class)) - return PTR_ERR(dgrp_class); - ret = class_create_file(dgrp_class, &class_attr_driver_version); - if (ret) - goto err_class; - - dgrp_class_global_settings_dev = device_create(dgrp_class, NULL, - MKDEV(0, max_majors + 1), NULL, "driver_settings"); - if (IS_ERR(dgrp_class_global_settings_dev)) { - ret = PTR_ERR(dgrp_class_global_settings_dev); - goto err_file; - } - ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj, - &dgrp_global_settings_attribute_group); - if (ret) { - pr_alert("%s: failed to create sysfs global settings device attributes.\n", - __func__); - goto err_dev1; - } - - dgrp_class_nodes_dev = device_create(dgrp_class, NULL, - MKDEV(0, max_majors + 2), NULL, "nodes"); - if (IS_ERR(dgrp_class_nodes_dev)) { - ret = PTR_ERR(dgrp_class_nodes_dev); - goto err_group; - } - - return 0; -err_group: - sysfs_remove_group(&dgrp_class_global_settings_dev->kobj, - &dgrp_global_settings_attribute_group); -err_dev1: - device_destroy(dgrp_class, MKDEV(0, max_majors + 1)); -err_file: - class_remove_file(dgrp_class, &class_attr_driver_version); -err_class: - class_destroy(dgrp_class); - return ret; -} - - -void dgrp_remove_class_sysfs_files(void) -{ - struct nd_struct *nd; - int max_majors = 1U << (32 - MINORBITS); - - list_for_each_entry(nd, &nd_struct_list, list) - dgrp_remove_node_class_sysfs_files(nd); - - sysfs_remove_group(&dgrp_class_global_settings_dev->kobj, - &dgrp_global_settings_attribute_group); - - class_remove_file(dgrp_class, &class_attr_driver_version); - - device_destroy(dgrp_class, MKDEV(0, max_majors + 1)); - device_destroy(dgrp_class, MKDEV(0, max_majors + 2)); - class_destroy(dgrp_class); -} - -static ssize_t dgrp_node_state_show(struct device *c, - struct device_attribute *attr, char *buf) -{ - struct nd_struct *nd; - - if (!c) - return 0; - nd = dev_get_drvdata(c); - if (!nd) - return 0; - - return snprintf(buf, PAGE_SIZE, "%s\n", ND_STATE_STR(nd->nd_state)); -} - -static DEVICE_ATTR(state, 0600, dgrp_node_state_show, NULL); - -static ssize_t dgrp_node_description_show(struct device *c, - struct device_attribute *attr, - char *buf) -{ - struct nd_struct *nd; - - if (!c) - return 0; - nd = dev_get_drvdata(c); - if (!nd) - return 0; - - if (nd->nd_state == NS_READY) - return snprintf(buf, PAGE_SIZE, "%s\n", nd->nd_ps_desc); - return 0; -} -static DEVICE_ATTR(description_info, 0600, dgrp_node_description_show, NULL); - -static ssize_t dgrp_node_hw_version_show(struct device *c, - struct device_attribute *attr, - char *buf) -{ - struct nd_struct *nd; - - if (!c) - return 0; - nd = dev_get_drvdata(c); - if (!nd) - return 0; - - if (nd->nd_state == NS_READY) - return snprintf(buf, PAGE_SIZE, "%d.%d\n", - (nd->nd_hw_ver >> 8) & 0xff, - nd->nd_hw_ver & 0xff); - - return 0; -} -static DEVICE_ATTR(hw_version_info, 0600, dgrp_node_hw_version_show, NULL); - -static ssize_t dgrp_node_hw_id_show(struct device *c, - struct device_attribute *attr, char *buf) -{ - struct nd_struct *nd; - - if (!c) - return 0; - nd = dev_get_drvdata(c); - if (!nd) - return 0; - - - if (nd->nd_state == NS_READY) - return snprintf(buf, PAGE_SIZE, "%d\n", nd->nd_hw_id); - return 0; -} -static DEVICE_ATTR(hw_id_info, 0600, dgrp_node_hw_id_show, NULL); - -static ssize_t dgrp_node_sw_version_show(struct device *c, - struct device_attribute *attr, - char *buf) -{ - struct nd_struct *nd; - - if (!c) - return 0; - - nd = dev_get_drvdata(c); - if (!nd) - return 0; - - if (nd->nd_state == NS_READY) - return snprintf(buf, PAGE_SIZE, "%d.%d\n", - (nd->nd_sw_ver >> 8) & 0xff, - nd->nd_sw_ver & 0xff); - - return 0; -} -static DEVICE_ATTR(sw_version_info, 0600, dgrp_node_sw_version_show, NULL); - - -static struct attribute *dgrp_sysfs_node_entries[] = { - &dev_attr_state.attr, - &dev_attr_description_info.attr, - &dev_attr_hw_version_info.attr, - &dev_attr_hw_id_info.attr, - &dev_attr_sw_version_info.attr, - NULL -}; - - -static struct attribute_group dgrp_node_attribute_group = { - .name = NULL, - .attrs = dgrp_sysfs_node_entries, -}; - - -void dgrp_create_node_class_sysfs_files(struct nd_struct *nd) -{ - int ret; - char name[10]; - - if (nd->nd_ID) - ID_TO_CHAR(nd->nd_ID, name); - else - sprintf(name, "node%ld", nd->nd_major); - - nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev, - MKDEV(0, nd->nd_major), NULL, "%s", name); - - ret = sysfs_create_group(&nd->nd_class_dev->kobj, - &dgrp_node_attribute_group); - - if (ret) { - pr_alert("%s: failed to create sysfs node device attributes.\n", - __func__); - sysfs_remove_group(&nd->nd_class_dev->kobj, - &dgrp_node_attribute_group); - return; - } - - dev_set_drvdata(nd->nd_class_dev, nd); - -} - - -void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd) -{ - if (nd->nd_class_dev) { - sysfs_remove_group(&nd->nd_class_dev->kobj, - &dgrp_node_attribute_group); - - device_destroy(dgrp_class, MKDEV(0, nd->nd_major)); - nd->nd_class_dev = NULL; - } -} - - - -static ssize_t dgrp_tty_state_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - - return snprintf(buf, PAGE_SIZE, "%s\n", - un->un_open_count ? "Open" : "Closed"); -} -static DEVICE_ATTR(state_info, 0600, dgrp_tty_state_show, NULL); - -static ssize_t dgrp_tty_baud_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", - un->un_open_count ? (PORTSERVER_DIVIDEND / ch->ch_s_brate) : 0); -} -static DEVICE_ATTR(baud_info, 0400, dgrp_tty_baud_show, NULL); - - -static ssize_t dgrp_tty_msignals_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - - if (ch->ch_open_count) { - return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", - (ch->ch_s_mlast & DM_RTS) ? "RTS" : "", - (ch->ch_s_mlast & DM_CTS) ? "CTS" : "", - (ch->ch_s_mlast & DM_DTR) ? "DTR" : "", - (ch->ch_s_mlast & DM_DSR) ? "DSR" : "", - (ch->ch_s_mlast & DM_CD) ? "DCD" : "", - (ch->ch_s_mlast & DM_RI) ? "RI" : ""); - } - return 0; -} -static DEVICE_ATTR(msignals_info, 0400, dgrp_tty_msignals_show, NULL); - - -static ssize_t dgrp_tty_iflag_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_iflag); -} -static DEVICE_ATTR(iflag_info, 0600, dgrp_tty_iflag_show, NULL); - - -static ssize_t dgrp_tty_cflag_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_cflag); -} -static DEVICE_ATTR(cflag_info, 0600, dgrp_tty_cflag_show, NULL); - - -static ssize_t dgrp_tty_oflag_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_oflag); -} -static DEVICE_ATTR(oflag_info, 0600, dgrp_tty_oflag_show, NULL); - - -static ssize_t dgrp_tty_digi_flag_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); -} -static DEVICE_ATTR(digi_flag_info, 0600, dgrp_tty_digi_flag_show, NULL); - - -static ssize_t dgrp_tty_rxcount_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_rxcount); -} -static DEVICE_ATTR(rxcount_info, 0600, dgrp_tty_rxcount_show, NULL); - - -static ssize_t dgrp_tty_txcount_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct ch_struct *ch; - struct un_struct *un; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_txcount); -} -static DEVICE_ATTR(txcount_info, 0600, dgrp_tty_txcount_show, NULL); - - -static ssize_t dgrp_tty_name_show(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct nd_struct *nd; - struct ch_struct *ch; - struct un_struct *un; - char name[10]; - - if (!d) - return 0; - un = dev_get_drvdata(d); - if (!un) - return 0; - ch = un->un_ch; - if (!ch) - return 0; - nd = ch->ch_nd; - if (!nd) - return 0; - - ID_TO_CHAR(nd->nd_ID, name); - - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - un->un_type == SERIAL_TYPE_XPRINT ? "pr" : "tty", - name, ch->ch_portnum); -} -static DEVICE_ATTR(custom_name, 0600, dgrp_tty_name_show, NULL); - - -static struct attribute *dgrp_sysfs_tty_entries[] = { - &dev_attr_state_info.attr, - &dev_attr_baud_info.attr, - &dev_attr_msignals_info.attr, - &dev_attr_iflag_info.attr, - &dev_attr_cflag_info.attr, - &dev_attr_oflag_info.attr, - &dev_attr_digi_flag_info.attr, - &dev_attr_rxcount_info.attr, - &dev_attr_txcount_info.attr, - &dev_attr_custom_name.attr, - NULL -}; - - -static struct attribute_group dgrp_tty_attribute_group = { - .name = NULL, - .attrs = dgrp_sysfs_tty_entries, -}; - - -void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c) -{ - int ret; - - ret = sysfs_create_group(&c->kobj, &dgrp_tty_attribute_group); - if (ret) { - pr_alert("%s: failed to create sysfs tty device attributes.\n", - __func__); - sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group); - return; - } - - dev_set_drvdata(c, un); - -} - - -void dgrp_remove_tty_sysfs(struct device *c) -{ - sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group); -} diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c deleted file mode 100644 index 30d26029b21e..000000000000 --- a/drivers/staging/dgrp/dgrp_tty.c +++ /dev/null @@ -1,3337 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * Gene Olson - * James Puzzo - * Jeff Randall - * Scott Kilau - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_tty.c - * - * Description: - * - * This file implements the tty driver functionality for the - * RealPort driver software. - * - * Author: - * - * James A. Puzzo - * Ann-Marie Westgate - * - */ - -#include -#include -#include -#include -#include -#include - -#include "dgrp_common.h" - -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE ('\0') -#endif - -/* - * forward declarations - */ - -static void drp_param(struct ch_struct *); -static void dgrp_tty_close(struct tty_struct *, struct file *); - -/* ioctl helper functions */ -static int set_modem_info(struct ch_struct *, unsigned int, unsigned int *); -static int get_modem_info(struct ch_struct *, unsigned int *); -static void dgrp_set_custom_speed(struct ch_struct *, int); -static int dgrp_tty_digigetedelay(struct tty_struct *, int *); -static int dgrp_tty_digisetedelay(struct tty_struct *, int *); -static int dgrp_send_break(struct ch_struct *, int); - -static ushort tty_to_ch_flags(struct tty_struct *, char); -static tcflag_t ch_to_tty_flags(unsigned short, char); - -static void dgrp_tty_input_start(struct tty_struct *); -static void dgrp_tty_input_stop(struct tty_struct *); - -static void drp_wmove(struct ch_struct *, int, void*, int); - -static int dgrp_tty_open(struct tty_struct *, struct file *); -static void dgrp_tty_close(struct tty_struct *, struct file *); -static int dgrp_tty_write(struct tty_struct *, const unsigned char *, int); -static int dgrp_tty_write_room(struct tty_struct *); -static void dgrp_tty_flush_buffer(struct tty_struct *); -static int dgrp_tty_chars_in_buffer(struct tty_struct *); -static int dgrp_tty_ioctl(struct tty_struct *, unsigned int, unsigned long); -static void dgrp_tty_set_termios(struct tty_struct *, struct ktermios *); -static void dgrp_tty_stop(struct tty_struct *); -static void dgrp_tty_start(struct tty_struct *); -static void dgrp_tty_throttle(struct tty_struct *); -static void dgrp_tty_unthrottle(struct tty_struct *); -static void dgrp_tty_hangup(struct tty_struct *); -static int dgrp_tty_put_char(struct tty_struct *, unsigned char); -static int dgrp_tty_tiocmget(struct tty_struct *); -static int dgrp_tty_tiocmset(struct tty_struct *, unsigned int, unsigned int); -static int dgrp_tty_send_break(struct tty_struct *, int); -static void dgrp_tty_send_xchar(struct tty_struct *, char); - -/* - * tty defines - */ -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 -#define SERIAL_TYPE_XPRINT 3 - - -/* - * tty globals/statics - */ - - -#define PORTSERVER_DIVIDEND 1843200 - -/* - * Default transparent print information. - */ -static struct digi_struct digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string */ - .digi_offstr = "\033[4i", /* ANSI printer off string */ - .digi_term = "ansi" /* default terminal type */ -}; - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. - * - * This defines a raw port at 9600 baud, 8 data bits, no parity, - * 1 stop bit. - */ -static struct ktermios DefaultTermios = { - .c_iflag = (ICRNL | IXON), - .c_oflag = (OPOST | ONLCR), - .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - .c_lflag = (ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL - | ECHOKE | IEXTEN), - .c_cc = INIT_C_CC, - .c_line = 0, -}; - -/* Define our tty operations struct */ -static const struct tty_operations dgrp_tty_ops = { - .open = dgrp_tty_open, - .close = dgrp_tty_close, - .write = dgrp_tty_write, - .write_room = dgrp_tty_write_room, - .flush_buffer = dgrp_tty_flush_buffer, - .chars_in_buffer = dgrp_tty_chars_in_buffer, - .flush_chars = NULL, - .ioctl = dgrp_tty_ioctl, - .set_termios = dgrp_tty_set_termios, - .stop = dgrp_tty_stop, - .start = dgrp_tty_start, - .throttle = dgrp_tty_throttle, - .unthrottle = dgrp_tty_unthrottle, - .hangup = dgrp_tty_hangup, - .put_char = dgrp_tty_put_char, - .tiocmget = dgrp_tty_tiocmget, - .tiocmset = dgrp_tty_tiocmset, - .break_ctl = dgrp_tty_send_break, - .send_xchar = dgrp_tty_send_xchar -}; - - -static int calc_baud_rate(struct un_struct *un) -{ - int i; - int brate; - - struct baud_rates { - unsigned int rate; - unsigned int cflag; - }; - - static struct baud_rates baud_rates[] = { - { 921600, B921600 }, - { 460800, B460800 }, - { 230400, B230400 }, - { 115200, B115200 }, - { 57600, B57600 }, - { 38400, B38400 }, - { 19200, B19200 }, - { 9600, B9600 }, - { 4800, B4800 }, - { 2400, B2400 }, - { 1200, B1200 }, - { 600, B600 }, - { 300, B300 }, - { 200, B200 }, - { 150, B150 }, - { 134, B134 }, - { 110, B110 }, - { 75, B75 }, - { 50, B50 }, - { 0, B9600 } - }; - - brate = C_BAUD(un->un_tty); - - for (i = 0; baud_rates[i].rate; i++) { - if (baud_rates[i].cflag == brate) - break; - } - - return baud_rates[i].rate; -} - -static int calc_fastbaud_rate(struct un_struct *un, struct ktermios *uts) -{ - int i; - int brate; - - ulong bauds[2][16] = { - { /* fastbaud*/ - 0, 57600, 76800, 115200, - 131657, 153600, 230400, 460800, - 921600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 } - }; - - brate = C_BAUD(un->un_tty) & 0xff; - - i = (uts->c_cflag & CBAUDEX) ? 1 : 0; - - - if ((i >= 0) && (i < 2) && (brate >= 0) && (brate < 16)) - brate = bauds[i][brate]; - else - brate = 0; - - return brate; -} - -/** - * drp_param() -- send parameter values to be sent to the node - * @ch: channel structure of port to modify - * - * Interprets the tty and modem changes made by an application - * program (by examining the termios structures) and sets up - * parameter values to be sent to the node. - */ -static void drp_param(struct ch_struct *ch) -{ - struct nd_struct *nd; - struct un_struct *un; - int brate; - int mflow; - int xflag; - int iflag; - struct ktermios *tts, *pts, *uts; - - nd = ch->ch_nd; - - /* - * If the terminal device is open, use it to set up all tty - * modes and functions. Otherwise use the printer device. - */ - - if (ch->ch_tun.un_open_count) { - - un = &ch->ch_tun; - tts = &ch->ch_tun.un_tty->termios; - - /* - * If both devices are open, copy critical line - * parameters from the tty device to the printer, - * so that if the tty is closed, the printer will - * continue without disruption. - */ - - if (ch->ch_pun.un_open_count) { - - pts = &ch->ch_pun.un_tty->termios; - - pts->c_cflag ^= - (pts->c_cflag ^ tts->c_cflag) & - (CBAUD | CSIZE | CSTOPB | CREAD | PARENB | - PARODD | HUPCL | CLOCAL); - - pts->c_iflag ^= - (pts->c_iflag ^ tts->c_iflag) & - (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | - ISTRIP | IXON | IXANY | IXOFF); - - pts->c_cc[VSTART] = tts->c_cc[VSTART]; - pts->c_cc[VSTOP] = tts->c_cc[VSTOP]; - } - } else if (ch->ch_pun.un_open_count == 0) { - pr_warn("%s - ch_pun.un_open_count shouldn't be 0\n", - __func__); - return; - } else { - un = &ch->ch_pun; - } - - uts = &un->un_tty->termios; - - /* - * Determine if FAST writes can be performed. - */ - - if ((ch->ch_digi.digi_flags & DIGI_COOK) != 0 && - (ch->ch_tun.un_open_count != 0) && - !((un->un_tty)->ldisc->ops->flags & LDISC_FLAG_DEFINED) && - !(L_XCASE(un->un_tty))) { - ch->ch_flag |= CH_FAST_WRITE; - } else { - ch->ch_flag &= ~CH_FAST_WRITE; - } - - /* - * If FAST writes can be performed, and OPOST is on in the - * terminal device, do OPOST handling in the server. - */ - - if ((ch->ch_flag & CH_FAST_WRITE) && - O_OPOST(un->un_tty) != 0) { - int oflag = tty_to_ch_flags(un->un_tty, 'o'); - - /* add to ch_ocook any processing flags set in the termio */ - ch->ch_ocook |= oflag & (OF_OLCUC | - OF_ONLCR | - OF_OCRNL | - OF_ONLRET | - OF_TABDLY); - - /* - * the hpux driver clears any flags set in ch_ocook - * from the termios oflag. It is STILL reported though - * by a TCGETA - */ - - oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); - uts->c_oflag &= ~oflag; - - } else { - /* clear the ch->ch_ocook flag */ - int oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); - uts->c_oflag |= oflag; - ch->ch_ocook = 0; - } - - ch->ch_oflag = ch->ch_ocook; - - - ch->ch_flag &= ~CH_FAST_READ; - - /* - * Generate channel flags - */ - - if (C_BAUD(un->un_tty) == B0) { - if (!(ch->ch_flag & CH_BAUD0)) { - /* TODO : the HPUX driver flushes line */ - /* TODO : discipline, I assume I don't have to */ - - ch->ch_tout = ch->ch_tin; - ch->ch_rout = ch->ch_rin; - - ch->ch_break_time = 0; - - ch->ch_send |= RR_TX_FLUSH | RR_RX_FLUSH; - - ch->ch_mout &= ~(DM_DTR | DM_RTS); - - ch->ch_flag |= CH_BAUD0; - } - } else if (ch->ch_custom_speed) { - ch->ch_brate = PORTSERVER_DIVIDEND / ch->ch_custom_speed; - - if (ch->ch_flag & CH_BAUD0) { - ch->ch_mout |= DM_DTR | DM_RTS; - - ch->ch_flag &= ~CH_BAUD0; - } - } else { - /* - * Baud rate mapping. - * - * If FASTBAUD isn't on, we can scan the new baud rate list - * as required. - * - * However, if FASTBAUD is on, we must go to the old - * baud rate mapping that existed many many moons ago, - * for compatibility reasons. - */ - - if (!(ch->ch_digi.digi_flags & DIGI_FAST)) - brate = calc_baud_rate(un); - else - brate = calc_fastbaud_rate(un, uts); - - if (brate == 0) - brate = 9600; - - ch->ch_brate = PORTSERVER_DIVIDEND / brate; - - if (ch->ch_flag & CH_BAUD0) { - ch->ch_mout |= DM_DTR | DM_RTS; - - ch->ch_flag &= ~CH_BAUD0; - } - } - - /* - * Generate channel cflags from the termio. - */ - - ch->ch_cflag = tty_to_ch_flags(un->un_tty, 'c'); - - /* - * Generate channel iflags from the termio. - */ - - iflag = (int) tty_to_ch_flags(un->un_tty, 'i'); - - if (START_CHAR(un->un_tty) == _POSIX_VDISABLE || - STOP_CHAR(un->un_tty) == _POSIX_VDISABLE) { - iflag &= ~(IF_IXON | IF_IXANY | IF_IXOFF); - } - - ch->ch_iflag = iflag; - - /* - * Generate flow control characters - */ - - /* - * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE} - * is defined for the terminal device file, and the value - * of one of the changeable special control characters (see - * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be - * disabled, that is, no input data shall be recognized as - * the disabled special character." - * - * OK, so we don't ever assign S/DXB XON or XOFF to _POSIX_VDISABLE. - */ - - if (uts->c_cc[VSTART] != _POSIX_VDISABLE) - ch->ch_xon = uts->c_cc[VSTART]; - if (uts->c_cc[VSTOP] != _POSIX_VDISABLE) - ch->ch_xoff = uts->c_cc[VSTOP]; - - ch->ch_lnext = (uts->c_cc[VLNEXT] == _POSIX_VDISABLE ? 0 : - uts->c_cc[VLNEXT]); - - /* - * Also, if either c_cc[START] or c_cc[STOP] is set to - * _POSIX_VDISABLE, we can't really do software flow - * control--in either direction--so we turn it off as - * far as S/DXB is concerned. In essence, if you disable - * one, you disable the other too. - */ - if ((uts->c_cc[VSTART] == _POSIX_VDISABLE) || - (uts->c_cc[VSTOP] == _POSIX_VDISABLE)) - ch->ch_iflag &= ~(IF_IXOFF | IF_IXON); - - /* - * Update xflags. - */ - - xflag = 0; - - if (ch->ch_digi.digi_flags & DIGI_AIXON) - xflag = XF_XIXON; - - if ((ch->ch_xxon == _POSIX_VDISABLE) || - (ch->ch_xxoff == _POSIX_VDISABLE)) - xflag &= ~XF_XIXON; - - ch->ch_xflag = xflag; - - - /* - * Figure effective DCD value. - */ - - if (C_CLOCAL(un->un_tty)) - ch->ch_flag |= CH_CLOCAL; - else - ch->ch_flag &= ~CH_CLOCAL; - - /* - * Check modem signals - */ - - dgrp_carrier(ch); - - /* - * Get hardware handshake value. - */ - - mflow = 0; - - if (C_CRTSCTS(un->un_tty)) - mflow |= (DM_RTS | DM_CTS); - - if (ch->ch_digi.digi_flags & RTSPACE) - mflow |= DM_RTS; - - if (ch->ch_digi.digi_flags & DTRPACE) - mflow |= DM_DTR; - - if (ch->ch_digi.digi_flags & CTSPACE) - mflow |= DM_CTS; - - if (ch->ch_digi.digi_flags & DSRPACE) - mflow |= DM_DSR; - - if (ch->ch_digi.digi_flags & DCDPACE) - mflow |= DM_CD; - - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) - mflow |= DM_RTS_TOGGLE; - - ch->ch_mflow = mflow; - - /* - * Send the changes to the server. - */ - - ch->ch_flag |= CH_PARAM; - (ch->ch_nd)->nd_tx_work = 1; - - if (waitqueue_active(&ch->ch_flag_wait)) - wake_up_interruptible(&ch->ch_flag_wait); -} - -/* - * This function is just used as a callback for timeouts - * waiting on the ch_sleep flag. - */ -static void wake_up_drp_sleep_timer(unsigned long ptr) -{ - struct ch_struct *ch = (struct ch_struct *) ptr; - if (ch) - wake_up(&ch->ch_sleep); -} - - -/* - * Set up our own sleep that can't be cancelled - * until our timeout occurs. - */ -static void drp_my_sleep(struct ch_struct *ch) -{ - struct timer_list drp_wakeup_timer; - DECLARE_WAITQUEUE(wait, current); - - /* - * First make sure we're ready to receive the wakeup. - */ - - add_wait_queue(&ch->ch_sleep, &wait); - current->state = TASK_UNINTERRUPTIBLE; - - /* - * Since we are uninterruptible, set a timer to - * unset the uninterruptable state in 1 second. - */ - - init_timer(&drp_wakeup_timer); - drp_wakeup_timer.function = wake_up_drp_sleep_timer; - drp_wakeup_timer.data = (unsigned long) ch; - drp_wakeup_timer.expires = jiffies + (1 * HZ); - add_timer(&drp_wakeup_timer); - - schedule(); - - del_timer(&drp_wakeup_timer); - - remove_wait_queue(&ch->ch_sleep, &wait); -} - -/* - * dgrp_tty_open() - * - * returns: - * -EBUSY - this is a callout device and the normal device is active - * - there is an error in opening the tty - * -ENODEV - the channel does not exist - * -EAGAIN - we are in the middle of hanging up or closing - * - IMMEDIATE_OPEN fails - * -ENXIO or -EAGAIN - * - if the port is outside physical range - * -EINTR - the open is interrupted - * - */ -static int dgrp_tty_open(struct tty_struct *tty, struct file *file) -{ - int retval = 0; - struct nd_struct *nd; - struct ch_struct *ch; - struct un_struct *un; - int port; - int delay_error; - int otype; - int unf; - int wait_carrier; - int category; - int counts_were_incremented = 0; - ulong lock_flags; - DECLARE_WAITQUEUE(wait, current); - - /* - * Do some initial checks to see if the node and port exist - */ - - nd = nd_struct_get(MAJOR(tty_devnum(tty))); - port = PORT_NUM(MINOR(tty_devnum(tty))); - category = OPEN_CATEGORY(MINOR(tty_devnum(tty))); - - if (!nd) - return -ENODEV; - - if (port >= CHAN_MAX) - return -ENODEV; - - /* - * The channel exists. - */ - - ch = nd->nd_chan + port; - - un = IS_PRINT(MINOR(tty_devnum(tty))) ? &ch->ch_pun : &ch->ch_tun; - un->un_tty = tty; - tty->driver_data = un; - - /* - * If we are in the middle of hanging up, - * then return an error - */ - if (tty_hung_up_p(file)) { - retval = ((un->un_flag & UN_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto done; - } - - /* - * If the port is in the middle of closing, then block - * until it is done, then try again. - */ - retval = wait_event_interruptible(un->un_close_wait, - ((un->un_flag & UN_CLOSING) == 0)); - - if (retval) - goto done; - - /* - * If the port is in the middle of a reopen after a network disconnect, - * wait until it is done, then try again. - */ - retval = wait_event_interruptible(ch->ch_flag_wait, - ((ch->ch_flag & CH_PORT_GONE) == 0)); - - if (retval) - goto done; - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (un->un_flag & UN_NORMAL_ACTIVE) { - retval = -EBUSY; - goto done; - } else { - un->un_flag |= UN_CALLOUT_ACTIVE; - } - } - - /* - * Loop waiting until the open can be successfully completed. - */ - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - nd->nd_tx_work = 1; - - for (;;) { - wait_carrier = 0; - - /* - * Determine the open type from the flags provided. - */ - - /* - * If the port is not enabled, then exit - */ - if (test_bit(TTY_IO_ERROR, &tty->flags)) { - /* there was an error in opening the tty */ - if (un->un_flag & UN_CALLOUT_ACTIVE) - retval = -EBUSY; - else - un->un_flag |= UN_NORMAL_ACTIVE; - goto unlock; - } - - if (file->f_flags & O_NONBLOCK) { - - /* - * if the O_NONBLOCK is set, errors on read and write - * must return -EAGAIN immediately and NOT sleep - * on the waitqs. - */ - otype = OTYPE_IMMEDIATE; - delay_error = -EAGAIN; - - } else if (!OPEN_WAIT_AVAIL(category) || - (file->f_flags & O_NDELAY) != 0) { - otype = OTYPE_IMMEDIATE; - delay_error = -EBUSY; - - } else if (!OPEN_WAIT_CARRIER(category) || - ((ch->ch_digi.digi_flags & DIGI_FORCEDCD) != 0) || - C_CLOCAL(tty)) { - otype = OTYPE_PERSISTENT; - delay_error = 0; - - } else { - otype = OTYPE_INCOMING; - delay_error = 0; - } - - /* - * Handle port currently outside physical port range. - */ - - if (port >= nd->nd_chan_count) { - if (otype == OTYPE_IMMEDIATE) { - retval = (nd->nd_state == NS_READY) ? - -ENXIO : -EAGAIN; - goto unlock; - } - } - - /* - * Handle port not currently open. - */ - - else if (ch->ch_open_count == 0) { - /* - * Return an error when an Incoming Open - * response indicates the port is busy. - */ - - if (ch->ch_open_error != 0 && otype == ch->ch_otype) { - retval = (ch->ch_open_error <= 2) ? - delay_error : -ENXIO; - goto unlock; - } - - /* - * Fail any new Immediate open if we do not have - * a normal connection to the server. - */ - - if (nd->nd_state != NS_READY && - otype == OTYPE_IMMEDIATE) { - retval = -EAGAIN; - goto unlock; - } - - /* - * If a Realport open of the correct type has - * succeeded, complete the open. - */ - - if (ch->ch_state == CS_READY && ch->ch_otype == otype) - break; - } - - /* - * Handle port already open and active as a device - * of same category. - */ - - else if ((ch->ch_category == category) || - IS_PRINT(MINOR(tty_devnum(tty)))) { - /* - * Fail if opening the device now would - * violate exclusive use. - */ - unf = ch->ch_tun.un_flag | ch->ch_pun.un_flag; - - if ((file->f_flags & O_EXCL) || (unf & UN_EXCL)) { - retval = -EBUSY; - goto unlock; - } - - /* - * If the open device is in the hangup state, all - * system calls fail except close(). - */ - - /* TODO : check on hangup_p calls */ - - if (ch->ch_flag & CH_HANGUP) { - retval = -ENXIO; - goto unlock; - } - - /* - * If the port is ready, and carrier is ignored - * or present, then complete the open. - */ - - if (ch->ch_state == CS_READY && - (otype != OTYPE_INCOMING || - ch->ch_flag & CH_VIRT_CD)) - break; - - wait_carrier = 1; - } - - /* - * Handle port active with a different category device. - */ - - else { - if (otype == OTYPE_IMMEDIATE) { - retval = delay_error; - goto unlock; - } - } - - /* - * Wait until conditions change, then take another - * try at the open. - */ - - ch->ch_wait_count[otype]++; - - if (wait_carrier) - ch->ch_wait_carrier++; - - /* - * Prepare the task to accept the wakeup, then - * release our locks and release control. - */ - - add_wait_queue(&ch->ch_flag_wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - /* - * Give up control, we'll come back if we're - * interrupted or are woken up. - */ - schedule(); - remove_wait_queue(&ch->ch_flag_wait, &wait); - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - current->state = TASK_RUNNING; - - ch->ch_wait_count[otype]--; - - if (wait_carrier) - ch->ch_wait_carrier--; - - nd->nd_tx_work = 1; - - if (signal_pending(current)) { - retval = -EINTR; - goto unlock; - } - } /* end for(;;) */ - - /* - * The open has succeeded. No turning back. - */ - counts_were_incremented = 1; - un->un_open_count++; - ch->ch_open_count++; - - /* - * Initialize the channel, if it's not already open. - */ - - if (ch->ch_open_count == 1) { - ch->ch_flag = 0; - ch->ch_inwait = 0; - ch->ch_category = category; - ch->ch_pscan_state = 0; - - /* TODO : find out what PS-1 bug Gene was referring to */ - /* TODO : in the following comment. */ - - ch->ch_send = RR_TX_START | RR_RX_START; /* PS-1 bug */ - - if (C_CLOCAL(tty) || - ch->ch_s_mlast & DM_CD || - ch->ch_digi.digi_flags & DIGI_FORCEDCD) - ch->ch_flag |= CH_VIRT_CD; - else if (OPEN_FORCES_CARRIER(category)) - ch->ch_flag |= CH_VIRT_CD; - - } - - /* - * Initialize the unit, if it is not already open. - */ - - if (un->un_open_count == 1) { - /* - * Since all terminal options are always sticky in Linux, - * we don't need the UN_STICKY flag to be handled specially. - */ - /* clears all the digi flags, leaves serial flags */ - un->un_flag &= ~UN_DIGI_MASK; - - if (file->f_flags & O_EXCL) - un->un_flag |= UN_EXCL; - - /* TODO : include "session" and "pgrp" */ - - /* - * In Linux, all terminal parameters are intended to be sticky. - * as a result, we "remove" the code which once reset the ports - * to sane values. - */ - - drp_param(ch); - - } - - un->un_flag |= UN_INITIALIZED; - - retval = 0; - -unlock: - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - -done: - /* - * Linux does a close for every open, even failed ones! - */ - if (!counts_were_incremented) { - un->un_open_count++; - ch->ch_open_count++; - } - - if (retval) - dev_err(tty->dev, "tty open bad return (%i)\n", retval); - - return retval; -} - - - - -/* - * dgrp_tty_close() -- close function for tty_operations - */ -static void dgrp_tty_close(struct tty_struct *tty, struct file *file) -{ - struct ch_struct *ch; - struct un_struct *un; - struct nd_struct *nd; - int tpos; - int port; - int err = 0; - int s = 0; - ulong waketime; - ulong lock_flags; - int sent_printer_offstr = 0; - - port = PORT_NUM(MINOR(tty_devnum(tty))); - - un = tty->driver_data; - - if (!un) - return; - - ch = un->un_ch; - - if (!ch) - return; - - nd = ch->ch_nd; - - if (!nd) - return; - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - - /* Used to be on channel basis, now we check on a unit basis. */ - if (un->un_open_count != 1) - goto unlock; - - /* - * OK, its the last close on the unit - */ - un->un_flag |= UN_CLOSING; - - /* - * Notify the discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - - /* - * Wait for output to drain only if this is - * the last close against the channel - */ - - if (ch->ch_open_count == 1) { - /* - * If its the print device, we need to ensure at all costs that - * the offstr will fit. If it won't, flush our tbuf. - */ - if (IS_PRINT(MINOR(tty_devnum(tty))) && - (((ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK) < - ch->ch_digi.digi_offlen)) - ch->ch_tin = ch->ch_tout; - - /* - * Turn off the printer. Don't bother checking to see if its - * IS_PRINT... Since this is the last close the flag is going - * to be cleared, so we MUST make sure the offstr gets inserted - * into tbuf. - */ - - if ((ch->ch_flag & CH_PRON) != 0) { - drp_wmove(ch, 0, ch->ch_digi.digi_offstr, - ch->ch_digi.digi_offlen); - ch->ch_flag &= ~CH_PRON; - sent_printer_offstr = 1; - } - } - - /* - * Wait until either the output queue has drained, or we see - * absolutely no progress for 15 seconds. - */ - - tpos = ch->ch_s_tpos; - - waketime = jiffies + 15 * HZ; - - for (;;) { - - /* - * Make sure the port still exists. - */ - - if (port >= nd->nd_chan_count) { - err = 1; - break; - } - - if (signal_pending(current)) { - err = 1; - break; - } - - /* - * If the port is idle (not opened on the server), we have - * no way of draining/flushing/closing the port on that server. - * So break out of loop. - */ - if (ch->ch_state == CS_IDLE) - break; - - nd->nd_tx_work = 1; - - /* - * Exit if the queues for this unit are empty, - * and either the other unit is still open or all - * data has drained. - */ - - if ((un->un_tty)->ops->chars_in_buffer ? - ((un->un_tty)->ops->chars_in_buffer)(un->un_tty) == 0 : 1) { - - /* - * We don't need to wait for a buffer to drain - * if the other unit is open. - */ - - if (ch->ch_open_count != un->un_open_count) - break; - - /* - * The wait is complete when all queues are - * drained, and any break in progress is complete. - */ - - if (ch->ch_tin == ch->ch_tout && - ch->ch_s_tin == ch->ch_s_tpos && - (ch->ch_send & RR_TX_BREAK) == 0) { - break; - } - } - - /* - * Flush TX data and exit the wait if NDELAY is set, - * or this is not a DIGI printer, and the close timeout - * expires. - */ - - if ((file->f_flags & (O_NDELAY | O_NONBLOCK)) || - ((long)(jiffies - waketime) >= 0 && - (ch->ch_digi.digi_flags & DIGI_PRINTER) == 0)) { - - /* - * If we sent the printer off string, we cannot - * flush our internal buffers, or we might lose - * the offstr. - */ - if (!sent_printer_offstr) - dgrp_tty_flush_buffer(tty); - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - tty_ldisc_flush(tty); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - break; - } - - /* - * Otherwise take a short nap. - */ - - ch->ch_flag |= CH_DRAIN; - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - schedule_timeout_interruptible(1); - s = signal_pending(current); - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - if (s) { - /* - * If we had sent the printer off string, we now have - * some problems. - * - * The system won't let us sleep since we got an error - * back from sleep, presumably because the user did - * a ctrl-c... - * But we need to ensure that the offstr gets sent! - * Thus, we have to do something else besides sleeping. - * The plan: - * 1) Make this task uninterruptable. - * 2) Set up a timer to go off in 1 sec. - * 3) Act as tho we just got out of the sleep above. - * - * Thankfully, in the real world, this just - * never happens. - */ - - if (sent_printer_offstr) { - spin_unlock_irqrestore(&nd->nd_lock, - lock_flags); - drp_my_sleep(ch); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - } else { - err = 1; - break; - } - } - - /* - * Restart the wait if any progress is seen. - */ - - if (ch->ch_s_tpos != tpos) { - tpos = ch->ch_s_tpos; - - /* TODO: this gives us timeout problems with nist ?? */ - waketime = jiffies + 15 * HZ; - } - } - - /* - * Close the line discipline - */ - - /* this is done in tty_io.c */ - /* if ((un->un_tty)->ldisc.close) - * ((un->un_tty)->ldisc.close)(un->un_tty); - */ - - /* don't do this here */ - /* un->un_flag = 0; */ - - /* - * Flush the receive buffer on terminal unit close only. - */ - - if (!IS_PRINT(MINOR(tty_devnum(tty)))) - ch->ch_rout = ch->ch_rin; - - - /* - * Don't permit the close to happen until we get any pending - * sync request responses. - * There could be other ports depending upon the response as well. - * - * Also, don't permit the close to happen until any parameter - * changes have been sent out from the state machine as well. - * This is required because of a ditty -a race with -HUPCL - * We MUST make sure all channel parameters have been sent to the - * Portserver before sending a close. - */ - - if ((err != 1) && (ch->ch_state != CS_IDLE)) { - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - s = wait_event_interruptible(ch->ch_flag_wait, - ((ch->ch_flag & (CH_WAITING_SYNC | CH_PARAM)) == 0)); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - } - - /* - * Cleanup the channel if last unit open. - */ - - if (ch->ch_open_count == 1) { - ch->ch_flag = 0; - ch->ch_category = 0; - ch->ch_send = 0; - ch->ch_expect = 0; - ch->ch_tout = ch->ch_tin; - /* (un->un_tty)->device = 0; */ - - if (ch->ch_state == CS_READY) - ch->ch_state = CS_SEND_CLOSE; - } - - /* - * Send the changes to the server - */ - if (ch->ch_state != CS_IDLE) { - ch->ch_flag |= CH_PARAM; - wake_up_interruptible(&ch->ch_flag_wait); - } - - nd->nd_tx_work = 1; - nd->nd_tx_ready = 1; - -unlock: - tty->closing = 0; - - if (ch->ch_open_count <= 0) - dev_info(tty->dev, - "%s - unexpected value for ch->ch_open_count: %i\n", - __func__, ch->ch_open_count); - else - ch->ch_open_count--; - - if (un->un_open_count <= 0) - dev_info(tty->dev, - "%s - unexpected value for un->un_open_count: %i\n", - __func__, un->un_open_count); - else - un->un_open_count--; - - un->un_flag &= ~(UN_NORMAL_ACTIVE | UN_CALLOUT_ACTIVE | UN_CLOSING); - if (waitqueue_active(&un->un_close_wait)) - wake_up_interruptible(&un->un_close_wait); - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - return; - -} - -static void drp_wmove(struct ch_struct *ch, int from_user, void *buf, int count) -{ - int n; - int ret = 0; - - ch->ch_nd->nd_tx_work = 1; - - n = TBUF_MAX - ch->ch_tin; - - if (count >= n) { - if (from_user) - ret = copy_from_user(ch->ch_tbuf + ch->ch_tin, - (void __user *) buf, n); - else - memcpy(ch->ch_tbuf + ch->ch_tin, buf, n); - - buf = (char *) buf + n; - count -= n; - ch->ch_tin = 0; - } - - if (from_user) - ret = copy_from_user(ch->ch_tbuf + ch->ch_tin, - (void __user *) buf, count); - else - memcpy(ch->ch_tbuf + ch->ch_tin, buf, count); - - ch->ch_tin += count; -} - - -static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space, - int *un_flag) -{ - clock_t tt; - clock_t mt; - unsigned short tmax = 0; - - /* - * If the terminal device is busy, reschedule when - * the terminal device becomes idle. - */ - - if (ch->ch_tun.un_open_count != 0 && - ch->ch_tun.un_tty->ops->chars_in_buffer && - ((ch->ch_tun.un_tty->ops->chars_in_buffer) - (ch->ch_tun.un_tty) != 0)) { - *un_flag = UN_PWAIT; - return 0; - } - - /* - * Assure that whenever there is printer data in the output - * buffer, there always remains enough space after it to - * turn the printer off. - */ - space -= ch->ch_digi.digi_offlen; - - if (space <= 0) { - *un_flag = UN_EMPTY; - return 0; - } - - /* - * We measure printer CPS speed by incrementing - * ch_cpstime by (HZ / digi_maxcps) for every - * character we output, restricting output so - * that ch_cpstime never exceeds lbolt. - * - * However if output has not been done for some - * time, lbolt will grow to very much larger than - * ch_cpstime, which would allow essentially - * unlimited amounts of output until ch_cpstime - * finally caught up. To avoid this, we adjust - * cps_time when necessary so the difference - * between lbolt and ch_cpstime never results - * in sending more than digi_bufsize characters. - * - * This nicely models a printer with an internal - * buffer of digi_bufsize characters. - * - * Get the time between lbolt and ch->ch_cpstime; - */ - - tt = jiffies - ch->ch_cpstime; - - /* - * Compute the time required to send digi_bufsize - * characters. - */ - - mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps; - - /* - * Compute the number of characters that can be sent - * without violating the time constraint. If the - * direct calculation of this number is bigger than - * digi_bufsize, limit the number to digi_bufsize, - * and adjust cpstime to match. - */ - - if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) { - tmax = ch->ch_digi.digi_bufsize; - ch->ch_cpstime = jiffies - mt; - } else { - tmax = ch->ch_digi.digi_maxcps * tt / HZ; - } - - /* - * If the time constraint now binds, limit the transmit - * count accordingly, and tentatively arrange to be - * rescheduled based on time. - */ - - if (tmax < space) { - *un_flag = UN_TIME; - space = tmax; - } - - /* - * Compute the total number of characters we can - * output before the total number of characters known - * to be in the output queue exceeds digi_maxchar. - */ - - tmax = (ch->ch_digi.digi_maxchar - - ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) - - ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff)); - - - /* - * If the digi_maxchar constraint now holds, limit - * the transmit count accordingly, and arrange to - * be rescheduled when the queue becomes empty. - */ - - if (space > tmax) { - *un_flag = UN_EMPTY; - space = tmax; - } - - if (space <= 0) - *un_flag |= UN_EMPTY; - - return space; -} - - -static int dgrp_tty_write(struct tty_struct *tty, - const unsigned char *buf, - int count) -{ - struct nd_struct *nd; - struct un_struct *un; - struct ch_struct *ch; - int space; - int n; - int t; - int sendcount; - int un_flag; - ulong lock_flags; - - if (tty == NULL) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - nd = ch->ch_nd; - if (!nd) - return 0; - - /* - * Ignore the request if the channel is not ready. - */ - if (ch->ch_state != CS_READY) - return 0; - - spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); - - /* - * Ignore the request if output is blocked. - */ - if ((un->un_flag & (UN_EMPTY | UN_LOW | UN_TIME | UN_PWAIT)) != 0) { - count = 0; - goto out; - } - - /* - * Also ignore the request if DPA has this port open, - * and is flow controlled on reading more data. - */ - if (nd->nd_dpa_debug && nd->nd_dpa_flag & DPA_WAIT_SPACE && - nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))) { - count = 0; - goto out; - } - - /* - * Limit amount we will write to the amount of space - * available in the channel buffer. - */ - sendcount = 0; - - space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; - - /* - * Handle the printer device. - */ - - un_flag = UN_LOW; - - if (IS_PRINT(MINOR(tty_devnum(tty)))) { - clock_t tt; - clock_t mt; - unsigned short tmax = 0; - - /* - * If the terminal device is busy, reschedule when - * the terminal device becomes idle. - */ - - if (ch->ch_tun.un_open_count != 0 && - ((ch->ch_tun.un_tty->ops->chars_in_buffer) - (ch->ch_tun.un_tty) != 0)) { - un->un_flag |= UN_PWAIT; - count = 0; - goto out; - } - - /* - * Assure that whenever there is printer data in the output - * buffer, there always remains enough space after it to - * turn the printer off. - */ - space -= ch->ch_digi.digi_offlen; - - /* - * Output the printer on string. - */ - - if ((ch->ch_flag & CH_PRON) == 0) { - space -= ch->ch_digi.digi_onlen; - - if (space < 0) { - un->un_flag |= UN_EMPTY; - (ch->ch_nd)->nd_tx_work = 1; - count = 0; - goto out; - } - - drp_wmove(ch, 0, ch->ch_digi.digi_onstr, - ch->ch_digi.digi_onlen); - - ch->ch_flag |= CH_PRON; - } - - /* - * We measure printer CPS speed by incrementing - * ch_cpstime by (HZ / digi_maxcps) for every - * character we output, restricting output so - * that ch_cpstime never exceeds lbolt. - * - * However if output has not been done for some - * time, lbolt will grow to very much larger than - * ch_cpstime, which would allow essentially - * unlimited amounts of output until ch_cpstime - * finally caught up. To avoid this, we adjust - * cps_time when necessary so the difference - * between lbolt and ch_cpstime never results - * in sending more than digi_bufsize characters. - * - * This nicely models a printer with an internal - * buffer of digi_bufsize characters. - * - * Get the time between lbolt and ch->ch_cpstime; - */ - - tt = jiffies - ch->ch_cpstime; - - /* - * Compute the time required to send digi_bufsize - * characters. - */ - - mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps; - - /* - * Compute the number of characters that can be sent - * without violating the time constraint. If the - * direct calculation of this number is bigger than - * digi_bufsize, limit the number to digi_bufsize, - * and adjust cpstime to match. - */ - - if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) { - tmax = ch->ch_digi.digi_bufsize; - ch->ch_cpstime = jiffies - mt; - } else { - tmax = ch->ch_digi.digi_maxcps * tt / HZ; - } - - /* - * If the time constraint now binds, limit the transmit - * count accordingly, and tentatively arrange to be - * rescheduled based on time. - */ - - if (tmax < space) { - space = tmax; - un_flag = UN_TIME; - } - - /* - * Compute the total number of characters we can - * output before the total number of characters known - * to be in the output queue exceeds digi_maxchar. - */ - - tmax = (ch->ch_digi.digi_maxchar - - ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) - - ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff)); - - - /* - * If the digi_maxchar constraint now holds, limit - * the transmit count accordingly, and arrange to - * be rescheduled when the queue becomes empty. - */ - - if (space > tmax) { - space = tmax; - un_flag = UN_EMPTY; - } - - } - /* - * Handle the terminal device. - */ - else { - - /* - * If the printer device is on, turn it off. - */ - - if ((ch->ch_flag & CH_PRON) != 0) { - - space -= ch->ch_digi.digi_offlen; - - drp_wmove(ch, 0, ch->ch_digi.digi_offstr, - ch->ch_digi.digi_offlen); - - ch->ch_flag &= ~CH_PRON; - } - } - - /* - * If space is 0 and its because the ch->tbuf - * is full, then Linux will handle a callback when queue - * space becomes available. - * tty_write returns count = 0 - */ - - if (space <= 0) { - /* the linux tty_io.c handles this if we return 0 */ - /* if (fp->flags & O_NONBLOCK) return -EAGAIN; */ - - un->un_flag |= UN_EMPTY; - (ch->ch_nd)->nd_tx_work = 1; - count = 0; - goto out; - } - - count = min(count, space); - - if (count > 0) { - - un->un_tbusy++; - - /* - * Copy the buffer contents to the ch_tbuf - * being careful to wrap around the circular queue - */ - - t = TBUF_MAX - ch->ch_tin; - n = count; - - if (n >= t) { - memcpy(ch->ch_tbuf + ch->ch_tin, buf, t); - if (nd->nd_dpa_debug && nd->nd_dpa_port == - PORT_NUM(MINOR(tty_devnum(un->un_tty)))) - dgrp_dpa_data(nd, 0, (char *) buf, t); - buf += t; - n -= t; - ch->ch_tin = 0; - sendcount += n; - } - - memcpy(ch->ch_tbuf + ch->ch_tin, buf, n); - if (nd->nd_dpa_debug && nd->nd_dpa_port == - PORT_NUM(MINOR(tty_devnum(un->un_tty)))) - dgrp_dpa_data(nd, 0, (char *) buf, n); - buf += n; - ch->ch_tin += n; - sendcount += n; - - un->un_tbusy--; - (ch->ch_nd)->nd_tx_work = 1; - if (ch->ch_edelay != DGRP_RTIME) { - (ch->ch_nd)->nd_tx_ready = 1; - wake_up_interruptible(&nd->nd_tx_waitq); - } - } - - ch->ch_txcount += count; - - if (IS_PRINT(MINOR(tty_devnum(tty)))) { - - /* - * Adjust ch_cpstime to account - * for the characters just output. - */ - - if (sendcount > 0) { - int cc = HZ * sendcount + ch->ch_cpsrem; - - ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps; - ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps; - } - - /* - * If we are now waiting on time, schedule ourself - * back when we'll be able to send a block of - * digi_maxchar characters. - */ - - if ((un_flag & UN_TIME) != 0) { - ch->ch_waketime = (ch->ch_cpstime + - (ch->ch_digi.digi_maxchar * HZ / - ch->ch_digi.digi_maxcps)); - } - } - - /* - * If the printer unit is waiting for completion - * of terminal output, get him going again. - */ - - if ((ch->ch_pun.un_flag & UN_PWAIT) != 0) - (ch->ch_nd)->nd_tx_work = 1; - -out: - spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); - - return count; -} - - -/* - * Put a character into ch->ch_buf - * - * - used by the line discipline for OPOST processing - */ - -static int dgrp_tty_put_char(struct tty_struct *tty, unsigned char new_char) -{ - struct un_struct *un; - struct ch_struct *ch; - ulong lock_flags; - int space; - int retval = 0; - - if (tty == NULL) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - if (ch->ch_state != CS_READY) - return 0; - - spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); - - - /* - * If space is 0 and its because the ch->tbuf - * Warn and dump the character, there isn't anything else - * we can do about it. David_Fries@digi.com - */ - - space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; - - un->un_tbusy++; - - /* - * Output the printer on string if device is TXPrint. - */ - if (IS_PRINT(MINOR(tty_devnum(tty))) && (ch->ch_flag & CH_PRON) == 0) { - if (space < ch->ch_digi.digi_onlen) { - un->un_tbusy--; - goto out; - } - space -= ch->ch_digi.digi_onlen; - drp_wmove(ch, 0, ch->ch_digi.digi_onstr, - ch->ch_digi.digi_onlen); - ch->ch_flag |= CH_PRON; - } - - /* - * Output the printer off string if device is NOT TXPrint. - */ - - if (!IS_PRINT(MINOR(tty_devnum(tty))) && - ((ch->ch_flag & CH_PRON) != 0)) { - if (space < ch->ch_digi.digi_offlen) { - un->un_tbusy--; - goto out; - } - - space -= ch->ch_digi.digi_offlen; - drp_wmove(ch, 0, ch->ch_digi.digi_offstr, - ch->ch_digi.digi_offlen); - ch->ch_flag &= ~CH_PRON; - } - - if (!space) { - un->un_tbusy--; - goto out; - } - - /* - * Copy the character to the ch_tbuf being - * careful to wrap around the circular queue - */ - ch->ch_tbuf[ch->ch_tin] = new_char; - ch->ch_tin = (1 + ch->ch_tin) & TBUF_MASK; - - if (IS_PRINT(MINOR(tty_devnum(tty)))) { - - /* - * Adjust ch_cpstime to account - * for the character just output. - */ - - int cc = HZ + ch->ch_cpsrem; - - ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps; - ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps; - - /* - * If we are now waiting on time, schedule ourself - * back when we'll be able to send a block of - * digi_maxchar characters. - */ - - ch->ch_waketime = (ch->ch_cpstime + - (ch->ch_digi.digi_maxchar * HZ / - ch->ch_digi.digi_maxcps)); - } - - - un->un_tbusy--; - (ch->ch_nd)->nd_tx_work = 1; - - retval = 1; -out: - spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); - return retval; -} - - - -/* - * Flush TX buffer (make in == out) - * - * check tty_ioctl.c -- this is called after TCOFLUSH - */ -static void dgrp_tty_flush_buffer(struct tty_struct *tty) -{ - struct un_struct *un; - struct ch_struct *ch; - - if (!tty) - return; - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - ch->ch_tout = ch->ch_tin; - /* do NOT do this here! */ - /* ch->ch_s_tpos = ch->ch_s_tin = 0; */ - - /* send the flush output command now */ - ch->ch_send |= RR_TX_FLUSH; - (ch->ch_nd)->nd_tx_ready = 1; - (ch->ch_nd)->nd_tx_work = 1; - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - tty_wakeup(tty); - -} - -/* - * Return space available in Tx buffer - * count = ( ch->ch_tout - ch->ch_tin ) mod (TBUF_MAX - 1) - */ -static int dgrp_tty_write_room(struct tty_struct *tty) -{ - struct un_struct *un; - struct ch_struct *ch; - int count; - - if (!tty) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - count = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; - - /* We *MUST* check this, and return 0 if the Printer Unit cannot - * take any more data within its time constraints... If we don't - * return 0 and the printer has hit it time constraint, the ld will - * call us back doing a put_char, which cannot be rejected!!! - */ - if (IS_PRINT(MINOR(tty_devnum(tty)))) { - int un_flag = 0; - count = dgrp_calculate_txprint_bounds(ch, count, &un_flag); - if (count <= 0) - count = 0; - - ch->ch_pun.un_flag |= un_flag; - (ch->ch_nd)->nd_tx_work = 1; - } - - return count; -} - -/* - * Return number of characters that have not been transmitted yet. - * chars_in_buffer = ( ch->ch_tin - ch->ch_tout ) mod (TBUF_MAX - 1) - * + ( ch->ch_s_tin - ch->ch_s_tout ) mod (0xffff) - * = number of characters "in transit" - * - * Remember that sequence number math is always with a sixteen bit - * mask, not the TBUF_MASK. - */ - -static int dgrp_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct un_struct *un; - struct ch_struct *ch; - int count; - int count1; - - if (!tty) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - count1 = count = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; - count += (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff; - /* one for tbuf, one for the PS */ - - /* - * If we are busy transmitting add 1 - */ - count += un->un_tbusy; - - return count; -} - - -/***************************************************************************** - * - * Helper applications for dgrp_tty_ioctl() - * - ***************************************************************************** - */ - - -/** - * ch_to_tty_flags() -- convert channel flags to termio flags - * @ch_flag: Digi channel flags - * @flagtype: type of ch_flag (iflag, oflag or cflag) - * - * take the channel flags of the specified type and return the - * corresponding termio flag - */ -static tcflag_t ch_to_tty_flags(ushort ch_flag, char flagtype) -{ - tcflag_t retval = 0; - - switch (flagtype) { - case 'i': - retval = ((ch_flag & IF_IGNBRK) ? IGNBRK : 0) - | ((ch_flag & IF_BRKINT) ? BRKINT : 0) - | ((ch_flag & IF_IGNPAR) ? IGNPAR : 0) - | ((ch_flag & IF_PARMRK) ? PARMRK : 0) - | ((ch_flag & IF_INPCK) ? INPCK : 0) - | ((ch_flag & IF_ISTRIP) ? ISTRIP : 0) - | ((ch_flag & IF_IXON) ? IXON : 0) - | ((ch_flag & IF_IXANY) ? IXANY : 0) - | ((ch_flag & IF_IXOFF) ? IXOFF : 0); - break; - - case 'o': - retval = ((ch_flag & OF_OLCUC) ? OLCUC : 0) - | ((ch_flag & OF_ONLCR) ? ONLCR : 0) - | ((ch_flag & OF_OCRNL) ? OCRNL : 0) - | ((ch_flag & OF_ONOCR) ? ONOCR : 0) - | ((ch_flag & OF_ONLRET) ? ONLRET : 0) - /* | ((ch_flag & OF_OTAB3) ? OFILL : 0) */ - | ((ch_flag & OF_TABDLY) ? TABDLY : 0); - break; - - case 'c': - retval = ((ch_flag & CF_CSTOPB) ? CSTOPB : 0) - | ((ch_flag & CF_CREAD) ? CREAD : 0) - | ((ch_flag & CF_PARENB) ? PARENB : 0) - | ((ch_flag & CF_PARODD) ? PARODD : 0) - | ((ch_flag & CF_HUPCL) ? HUPCL : 0); - - switch (ch_flag & CF_CSIZE) { - case CF_CS5: - retval |= CS5; - break; - case CF_CS6: - retval |= CS6; - break; - case CF_CS7: - retval |= CS7; - break; - case CF_CS8: - retval |= CS8; - break; - default: - retval |= CS8; - break; - } - break; - case 'x': - break; - case 'l': - break; - default: - return 0; - } - - return retval; -} - - -/** - * tty_to_ch_flags() -- convert termio flags to digi channel flags - * @tty: pointer to a TTY structure holding flag to be converted - * @flagtype: identifies which flag (iflags, oflags, or cflags) should - * be converted - * - * take the termio flag of the specified type and return the - * corresponding Digi version of the flags - */ -static ushort tty_to_ch_flags(struct tty_struct *tty, char flagtype) -{ - ushort retval = 0; - tcflag_t tflag = 0; - - switch (flagtype) { - case 'i': - tflag = tty->termios.c_iflag; - retval = (I_IGNBRK(tty) ? IF_IGNBRK : 0) - | (I_BRKINT(tty) ? IF_BRKINT : 0) - | (I_IGNPAR(tty) ? IF_IGNPAR : 0) - | (I_PARMRK(tty) ? IF_PARMRK : 0) - | (I_INPCK(tty) ? IF_INPCK : 0) - | (I_ISTRIP(tty) ? IF_ISTRIP : 0) - | (I_IXON(tty) ? IF_IXON : 0) - | (I_IXANY(tty) ? IF_IXANY : 0) - | (I_IXOFF(tty) ? IF_IXOFF : 0); - break; - case 'o': - tflag = tty->termios.c_oflag; - /* - * If OPOST is set, then do the post processing in the - * firmware by setting all the processing flags on. - * If ~OPOST, then make sure we are not doing any - * output processing!! - */ - if (!O_OPOST(tty)) - retval = 0; - else - retval = (O_OLCUC(tty) ? OF_OLCUC : 0) - | (O_ONLCR(tty) ? OF_ONLCR : 0) - | (O_OCRNL(tty) ? OF_OCRNL : 0) - | (O_ONOCR(tty) ? OF_ONOCR : 0) - | (O_ONLRET(tty) ? OF_ONLRET : 0) - /* | (O_OFILL(tty) ? OF_TAB3 : 0) */ - | (O_TABDLY(tty) ? OF_TABDLY : 0); - break; - case 'c': - tflag = tty->termios.c_cflag; - retval = (C_CSTOPB(tty) ? CF_CSTOPB : 0) - | (C_CREAD(tty) ? CF_CREAD : 0) - | (C_PARENB(tty) ? CF_PARENB : 0) - | (C_PARODD(tty) ? CF_PARODD : 0) - | (C_HUPCL(tty) ? CF_HUPCL : 0); - switch (C_CSIZE(tty)) { - case CS8: - retval |= CF_CS8; - break; - case CS7: - retval |= CF_CS7; - break; - case CS6: - retval |= CF_CS6; - break; - case CS5: - retval |= CF_CS5; - break; - default: - retval |= CF_CS8; - break; - } - break; - case 'x': - break; - case 'l': - break; - default: - return 0; - } - - return retval; -} - - -static int dgrp_tty_send_break(struct tty_struct *tty, int msec) -{ - struct un_struct *un; - struct ch_struct *ch; - int ret = -EIO; - - if (!tty) - return ret; - - un = tty->driver_data; - if (!un) - return ret; - - ch = un->un_ch; - if (!ch) - return ret; - - dgrp_send_break(ch, msec); - return 0; -} - - -/* - * This routine sends a break character out the serial port. - * - * duration is in 1/1000's of a second - */ -static int dgrp_send_break(struct ch_struct *ch, int msec) -{ - ulong x; - - wait_event_interruptible(ch->ch_flag_wait, - ((ch->ch_flag & CH_TX_BREAK) == 0)); - ch->ch_break_time += max(msec, 250); - ch->ch_send |= RR_TX_BREAK; - ch->ch_flag |= CH_TX_BREAK; - (ch->ch_nd)->nd_tx_work = 1; - - x = (msec * HZ) / 1000; - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - - return 0; -} - - -/* - * Return modem signals to ld. - */ -static int dgrp_tty_tiocmget(struct tty_struct *tty) -{ - unsigned int mlast; - struct un_struct *un = tty->driver_data; - struct ch_struct *ch; - - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) | - (ch->ch_mout & (DM_RTS | DM_DTR))); - - /* defined in /usr/include/asm/termios.h */ - mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0) - | ((mlast & DM_DTR) ? TIOCM_DTR : 0) - | ((mlast & DM_CD) ? TIOCM_CAR : 0) - | ((mlast & DM_RI) ? TIOCM_RNG : 0) - | ((mlast & DM_DSR) ? TIOCM_DSR : 0) - | ((mlast & DM_CTS) ? TIOCM_CTS : 0); - - return mlast; -} - - -/* - * Set modem lines - */ -static int dgrp_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - ulong lock_flags; - struct un_struct *un = tty->driver_data; - struct ch_struct *ch; - - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - if (set & TIOCM_RTS) - ch->ch_mout |= DM_RTS; - - if (set & TIOCM_DTR) - ch->ch_mout |= DM_DTR; - - if (clear & TIOCM_RTS) - ch->ch_mout &= ~(DM_RTS); - - if (clear & TIOCM_DTR) - ch->ch_mout &= ~(DM_DTR); - - spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags); - ch->ch_flag |= CH_PARAM; - (ch->ch_nd)->nd_tx_work = 1; - wake_up_interruptible(&ch->ch_flag_wait); - - spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags); - - return 0; -} - - - -/* - * Get current modem status - */ -static int get_modem_info(struct ch_struct *ch, unsigned int *value) -{ - unsigned int mlast; - - mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) | - (ch->ch_mout & (DM_RTS | DM_DTR))); - - /* defined in /usr/include/asm/termios.h */ - mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0) - | ((mlast & DM_DTR) ? TIOCM_DTR : 0) - | ((mlast & DM_CD) ? TIOCM_CAR : 0) - | ((mlast & DM_RI) ? TIOCM_RNG : 0) - | ((mlast & DM_DSR) ? TIOCM_DSR : 0) - | ((mlast & DM_CTS) ? TIOCM_CTS : 0); - return put_user(mlast, (unsigned int __user *) value); -} - -/* - * Set modem lines - */ -static int set_modem_info(struct ch_struct *ch, unsigned int command, - unsigned int *value) -{ - int error; - unsigned int arg; - int mval = 0; - ulong lock_flags; - - error = access_ok(VERIFY_READ, (void __user *) value, sizeof(int)); - if (error == 0) - return -EFAULT; - - if (get_user(arg, (unsigned int __user *) value)) - return -EFAULT; - mval |= ((arg & TIOCM_RTS) ? DM_RTS : 0) - | ((arg & TIOCM_DTR) ? DM_DTR : 0); - - switch (command) { - case TIOCMBIS: /* set flags */ - ch->ch_mout |= mval; - break; - case TIOCMBIC: /* clear flags */ - ch->ch_mout &= ~mval; - break; - case TIOCMSET: - ch->ch_mout = mval; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags); - - ch->ch_flag |= CH_PARAM; - (ch->ch_nd)->nd_tx_work = 1; - wake_up_interruptible(&ch->ch_flag_wait); - - spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags); - - return 0; -} - - -/* - * Assign the custom baud rate to the channel structure - */ -static void dgrp_set_custom_speed(struct ch_struct *ch, int newrate) -{ - int testdiv; - int testrate_high; - int testrate_low; - - int deltahigh, deltalow; - - if (newrate < 0) - newrate = 0; - - /* - * Since the divisor is stored in a 16-bit integer, we make sure - * we don't allow any rates smaller than a 16-bit integer would allow. - * And of course, rates above the dividend won't fly. - */ - if (newrate && newrate < ((PORTSERVER_DIVIDEND / 0xFFFF) + 1)) - newrate = ((PORTSERVER_DIVIDEND / 0xFFFF) + 1); - if (newrate && newrate > PORTSERVER_DIVIDEND) - newrate = PORTSERVER_DIVIDEND; - - while (newrate > 0) { - testdiv = PORTSERVER_DIVIDEND / newrate; - - /* - * If we try to figure out what rate the PortServer would use - * with the test divisor, it will be either equal or higher - * than the requested baud rate. If we then determine the - * rate with a divisor one higher, we will get the next lower - * supported rate below the requested. - */ - testrate_high = PORTSERVER_DIVIDEND / testdiv; - testrate_low = PORTSERVER_DIVIDEND / (testdiv + 1); - - /* - * If the rate for the requested divisor is correct, just - * use it and be done. - */ - if (testrate_high == newrate) - break; - - /* - * Otherwise, pick the rate that is closer (i.e. whichever rate - * has a smaller delta). - */ - deltahigh = testrate_high - newrate; - deltalow = newrate - testrate_low; - - if (deltahigh < deltalow) - newrate = testrate_high; - else - newrate = testrate_low; - - break; - } - - ch->ch_custom_speed = newrate; - - drp_param(ch); - - return; -} - - -/* - # dgrp_tty_digiseta() - * - * Ioctl to set the information from ditty. - * - * NOTE: DIGI_IXON, DSRPACE, DCDPACE, and DTRPACE are unsupported. JAR 990922 - */ -static int dgrp_tty_digiseta(struct tty_struct *tty, - struct digi_struct *new_info) -{ - struct un_struct *un = tty->driver_data; - struct ch_struct *ch; - - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - if (copy_from_user(&ch->ch_digi, (void __user *) new_info, - sizeof(struct digi_struct))) - return -EFAULT; - - if ((ch->ch_digi.digi_flags & RTSPACE) || - (ch->ch_digi.digi_flags & CTSPACE)) - tty->termios.c_cflag |= CRTSCTS; - else - tty->termios.c_cflag &= ~CRTSCTS; - - if (ch->ch_digi.digi_maxcps < 1) - ch->ch_digi.digi_maxcps = 1; - - if (ch->ch_digi.digi_maxcps > 10000) - ch->ch_digi.digi_maxcps = 10000; - - if (ch->ch_digi.digi_bufsize < 10) - ch->ch_digi.digi_bufsize = 10; - - if (ch->ch_digi.digi_maxchar < 1) - ch->ch_digi.digi_maxchar = 1; - - if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) - ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; - - if (ch->ch_digi.digi_onlen > DIGI_PLEN) - ch->ch_digi.digi_onlen = DIGI_PLEN; - - if (ch->ch_digi.digi_offlen > DIGI_PLEN) - ch->ch_digi.digi_offlen = DIGI_PLEN; - - /* make the changes now */ - drp_param(ch); - - return 0; -} - - - -/* - * dgrp_tty_digigetedelay() - * - * Ioctl to get the current edelay setting. - * - * - * - */ -static int dgrp_tty_digigetedelay(struct tty_struct *tty, int *retinfo) -{ - struct un_struct *un; - struct ch_struct *ch; - int tmp; - - if (!retinfo) - return -EFAULT; - - if (!tty || tty->magic != TTY_MAGIC) - return -EFAULT; - - un = tty->driver_data; - - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - tmp = ch->ch_edelay; - - if (copy_to_user((void __user *) retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - - -/* - * dgrp_tty_digisetedelay() - * - * Ioctl to set the EDELAY setting - * - */ -static int dgrp_tty_digisetedelay(struct tty_struct *tty, int *new_info) -{ - struct un_struct *un; - struct ch_struct *ch; - int new_digi; - - if (!tty || tty->magic != TTY_MAGIC) - return -EFAULT; - - un = tty->driver_data; - - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - if (copy_from_user(&new_digi, (void __user *)new_info, sizeof(int))) - return -EFAULT; - - ch->ch_edelay = new_digi; - - /* make the changes now */ - drp_param(ch); - - return 0; -} - - -/* - * The usual assortment of ioctl's - * - * note: use tty_check_change to make sure that we are not - * changing the state of a terminal when we are not a process - * in the forground. See tty_io.c - * rc = tty_check_change(tty); - * if (rc) return rc; - */ -static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct un_struct *un; - struct ch_struct *ch; - int rc; - struct digiflow_struct dflow; - - if (!tty) - return -ENODEV; - - un = tty->driver_data; - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - switch (cmd) { - - /* - * Here are all the standard ioctl's that we MUST implement - */ - - case TCSBRK: - /* - * TCSBRK is SVID version: non-zero arg --> no break - * this behaviour is exploited by tcdrain(). - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds - */ - - rc = tty_check_change(tty); - if (rc) - return rc; - tty_wait_until_sent(tty, 0); - - if (!arg) - rc = dgrp_send_break(ch, 250); /* 1/4 second */ - - if (dgrp_tty_chars_in_buffer(tty) != 0) - return -EINTR; - - return 0; - - case TCSBRKP: - /* support for POSIX tcsendbreak() - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - if (rc) - return rc; - tty_wait_until_sent(tty, 0); - - rc = dgrp_send_break(ch, arg ? arg*250 : 250); - - if (dgrp_tty_chars_in_buffer(tty) != 0) - return -EINTR; - return 0; - - case TIOCSBRK: - rc = tty_check_change(tty); - if (rc) - return rc; - tty_wait_until_sent(tty, 0); - - /* - * RealPort doesn't support turning on a break unconditionally. - * The RealPort device will stop sending a break automatically - * after the specified time value that we send in. - */ - rc = dgrp_send_break(ch, 250); /* 1/4 second */ - - if (dgrp_tty_chars_in_buffer(tty) != 0) - return -EINTR; - return 0; - - case TIOCCBRK: - /* - * RealPort doesn't support turning off a break unconditionally. - * The RealPort device will stop sending a break automatically - * after the specified time value that was sent when turning on - * the break. - */ - return 0; - - case TIOCMGET: - rc = access_ok(VERIFY_WRITE, (void __user *) arg, - sizeof(unsigned int)); - if (rc == 0) - return -EFAULT; - return get_modem_info(ch, (unsigned int *) arg); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(ch, cmd, (unsigned int *) arg); - - /* - * Here are any additional ioctl's that we want to implement - */ - - case TCFLSH: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - rc = tty_check_change(tty); - if (rc) - return rc; - - switch (arg) { - case TCIFLUSH: - case TCIOFLUSH: - /* only flush input if this is the only open unit */ - if (!IS_PRINT(MINOR(tty_devnum(tty)))) { - ch->ch_rout = ch->ch_rin; - ch->ch_send |= RR_RX_FLUSH; - (ch->ch_nd)->nd_tx_work = 1; - (ch->ch_nd)->nd_tx_ready = 1; - wake_up_interruptible( - &(ch->ch_nd)->nd_tx_waitq); - } - if (arg == TCIFLUSH) - break; - - case TCOFLUSH: /* flush output, or the receive buffer */ - /* - * This is handled in the tty_ioctl.c code - * calling tty_flush_buffer - */ - break; - - default: - /* POSIX.1 says return EINVAL if we got a bad arg */ - return -EINVAL; - } - /* pretend we didn't recognize this IOCTL */ - return -ENOIOCTLCMD; - -#ifdef TIOCGETP - case TIOCGETP: -#endif - /***************************************** - Linux HPUX Function - TCSETA TCSETA - set the termios - TCSETAF TCSETAF - wait for drain first, then set termios - TCSETAW TCSETAW - wait for drain, - flush the input queue, then set termios - - looking at the tty_ioctl code, these command all call our - tty_set_termios at the driver's end, when a TCSETA* is sent, - it is expecting the tty to have a termio structure, - NOT a termios structure. These two structures differ in size - and the tty_ioctl code does a conversion before processing them both. - - we should treat the TCSETAW TCSETAF ioctls the same, and let - the tty_ioctl code do the conversion stuff. - - TCSETS - TCSETSF (none) - TCSETSW - - the associated tty structure has a termios structure. - *****************************************/ - - case TCGETS: - case TCGETA: - return -ENOIOCTLCMD; - - case TCSETAW: - case TCSETAF: - case TCSETSF: - case TCSETSW: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - - /* - * Also, now that we have TXPrint, we have to check - * if this is the TXPrint device and the terminal - * device is open. If so, do NOT run check_change, - * as the terminal device is ALWAYS the parent. - */ - if (!IS_PRINT(MINOR(tty_devnum(tty))) || - !ch->ch_tun.un_open_count) { - rc = tty_check_change(tty); - if (rc) - return rc; - } - - /* wait for all the characters in tbuf to drain */ - tty_wait_until_sent(tty, 0); - - if ((cmd == TCSETSF) || (cmd == TCSETAF)) { - /* flush the contents of the rbuf queue */ - /* TODO: check if this is print device? */ - ch->ch_send |= RR_RX_FLUSH; - (ch->ch_nd)->nd_tx_ready = 1; - (ch->ch_nd)->nd_tx_work = 1; - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - /* do we need to do this? just to be safe! */ - ch->ch_rout = ch->ch_rin; - } - - /* pretend we didn't recognize this */ - return -ENOIOCTLCMD; - - case TCXONC: - /* - * The Linux Line Discipline (LD) would do this for us if we - * let it, but we have the special firmware options to do this - * the "right way" regardless of hardware or software flow - * control so we'll do it outselves instead of letting the LD - * do it. - */ - rc = tty_check_change(tty); - if (rc) - return rc; - - switch (arg) { - case TCOON: - dgrp_tty_start(tty); - return 0; - case TCOOFF: - dgrp_tty_stop(tty); - return 0; - case TCION: - dgrp_tty_input_start(tty); - return 0; - case TCIOFF: - dgrp_tty_input_stop(tty); - return 0; - default: - return -EINVAL; - } - - case DIGI_GETA: - /* get information for ditty */ - if (copy_to_user((struct digi_struct __user *) arg, - &ch->ch_digi, sizeof(struct digi_struct))) - return -EFAULT; - break; - - case DIGI_SETAW: - case DIGI_SETAF: - /* wait for all the characters in tbuf to drain */ - tty_wait_until_sent(tty, 0); - - if (cmd == DIGI_SETAF) { - /* flush the contents of the rbuf queue */ - /* send down a packet with RR_RX_FLUSH set */ - ch->ch_send |= RR_RX_FLUSH; - (ch->ch_nd)->nd_tx_ready = 1; - (ch->ch_nd)->nd_tx_work = 1; - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - /* do we need to do this? just to be safe! */ - ch->ch_rout = ch->ch_rin; - } - - /* pretend we didn't recognize this */ - /* fall-through */ - - case DIGI_SETA: - return dgrp_tty_digiseta(tty, (struct digi_struct *) arg); - - case DIGI_SEDELAY: - return dgrp_tty_digisetedelay(tty, (int *) arg); - - case DIGI_GEDELAY: - return dgrp_tty_digigetedelay(tty, (int *) arg); - - case DIGI_GETFLOW: - case DIGI_GETAFLOW: - if (cmd == (DIGI_GETFLOW)) { - dflow.startc = tty->termios.c_cc[VSTART]; - dflow.stopc = tty->termios.c_cc[VSTOP]; - } else { - dflow.startc = ch->ch_xxon; - dflow.stopc = ch->ch_xxoff; - } - - if (copy_to_user((char __user *)arg, &dflow, sizeof(dflow))) - return -EFAULT; - break; - - case DIGI_SETFLOW: - case DIGI_SETAFLOW: - - if (copy_from_user(&dflow, (char __user *)arg, sizeof(dflow))) - return -EFAULT; - - if (cmd == (DIGI_SETFLOW)) { - tty->termios.c_cc[VSTART] = dflow.startc; - tty->termios.c_cc[VSTOP] = dflow.stopc; - } else { - ch->ch_xxon = dflow.startc; - ch->ch_xxoff = dflow.stopc; - } - break; - - case DIGI_GETCUSTOMBAUD: - if (put_user(ch->ch_custom_speed, (unsigned int __user *) arg)) - return -EFAULT; - break; - - case DIGI_SETCUSTOMBAUD: - { - int new_rate; - - if (get_user(new_rate, (unsigned int __user *) arg)) - return -EFAULT; - dgrp_set_custom_speed(ch, new_rate); - - break; - } - - default: - return -ENOIOCTLCMD; - } - - return 0; -} - -/* - * This routine allows the tty driver to be notified when - * the device's termios setting have changed. Note that we - * should be prepared to accept the case where old == NULL - * and try to do something rational. - * - * So we need to make sure that our copies of ch_oflag, - * ch_clag, and ch_iflag reflect the tty->termios flags. - */ -static void dgrp_tty_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct ktermios *ts; - struct ch_struct *ch; - struct un_struct *un; - - /* seems silly, but we have to check all these! */ - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ts = &tty->termios; - - ch = un->un_ch; - if (!ch) - return; - - drp_param(ch); - - /* the CLOCAL flag has just been set */ - if (!(old->c_cflag & CLOCAL) && C_CLOCAL(tty)) - wake_up_interruptible(&un->un_open_wait); -} - - -/* - * Throttle receiving data. We just set a bit and stop reading - * data out of the channel buffer. It will back up and the - * FEP will do whatever is necessary to stop the far end. - */ -static void dgrp_tty_throttle(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - ch->ch_flag |= CH_RXSTOP; -} - - -static void dgrp_tty_unthrottle(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - ch->ch_flag &= ~CH_RXSTOP; -} - -/* - * Stop the transmitter - */ -static void dgrp_tty_stop(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - ch->ch_send |= RR_TX_STOP; - ch->ch_send &= ~RR_TX_START; - - /* make the change NOW! */ - (ch->ch_nd)->nd_tx_ready = 1; - if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); -} - -/* - * Start the transmitter - */ -static void dgrp_tty_start(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - /* TODO: don't do anything if the transmitter is not stopped */ - - ch->ch_send |= RR_TX_START; - ch->ch_send &= ~RR_TX_STOP; - - /* make the change NOW! */ - (ch->ch_nd)->nd_tx_ready = 1; - (ch->ch_nd)->nd_tx_work = 1; - if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - -} - -/* - * Stop the receiver - */ -static void dgrp_tty_input_stop(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - ch->ch_send |= RR_RX_STOP; - ch->ch_send &= ~RR_RX_START; - (ch->ch_nd)->nd_tx_ready = 1; - if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - -} - - -static void dgrp_tty_send_xchar(struct tty_struct *tty, char c) -{ - struct un_struct *un; - struct ch_struct *ch; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - if (c == STOP_CHAR(tty)) - ch->ch_send |= RR_RX_STOP; - else if (c == START_CHAR(tty)) - ch->ch_send |= RR_RX_START; - - ch->ch_nd->nd_tx_ready = 1; - ch->ch_nd->nd_tx_work = 1; - - return; -} - - -static void dgrp_tty_input_start(struct tty_struct *tty) -{ - struct ch_struct *ch; - - if (!tty) - return; - - ch = ((struct un_struct *) tty->driver_data)->un_ch; - if (!ch) - return; - - ch->ch_send |= RR_RX_START; - ch->ch_send &= ~RR_RX_STOP; - (ch->ch_nd)->nd_tx_ready = 1; - (ch->ch_nd)->nd_tx_work = 1; - if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) - wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); - -} - - -/* - * Hangup the port. Like a close, but don't wait for output - * to drain. - * - * How do we close all the channels that are open? - */ -static void dgrp_tty_hangup(struct tty_struct *tty) -{ - struct ch_struct *ch; - struct nd_struct *nd; - struct un_struct *un; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - nd = ch->ch_nd; - - if (C_HUPCL(tty)) { - /* LOWER DTR */ - ch->ch_mout &= ~DM_DTR; - /* Don't do this here */ - /* ch->ch_flag |= CH_HANGUP; */ - ch->ch_nd->nd_tx_ready = 1; - ch->ch_nd->nd_tx_work = 1; - if (waitqueue_active(&ch->ch_flag_wait)) - wake_up_interruptible(&ch->ch_flag_wait); - } - -} - -/************************************************************************/ -/* */ -/* TTY Initialization/Cleanup Functions */ -/* */ -/************************************************************************/ - -/* - * Uninitialize the TTY portion of the supplied node. Free all - * memory and resources associated with this node. Do it in reverse - * allocation order: this might possibly result in less fragmentation - * of memory, though I don't know this for sure. - */ -void -dgrp_tty_uninit(struct nd_struct *nd) -{ - unsigned int i; - char id[3]; - - ID_TO_CHAR(nd->nd_ID, id); - - if (nd->nd_ttdriver_flags & SERIAL_TTDRV_REG) { - tty_unregister_driver(nd->nd_serial_ttdriver); - - kfree(nd->nd_serial_ttdriver->ttys); - nd->nd_serial_ttdriver->ttys = NULL; - - put_tty_driver(nd->nd_serial_ttdriver); - nd->nd_ttdriver_flags &= ~SERIAL_TTDRV_REG; - } - - if (nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG) { - tty_unregister_driver(nd->nd_callout_ttdriver); - - kfree(nd->nd_callout_ttdriver->ttys); - nd->nd_callout_ttdriver->ttys = NULL; - - put_tty_driver(nd->nd_callout_ttdriver); - nd->nd_ttdriver_flags &= ~CALLOUT_TTDRV_REG; - } - - if (nd->nd_ttdriver_flags & XPRINT_TTDRV_REG) { - tty_unregister_driver(nd->nd_xprint_ttdriver); - - kfree(nd->nd_xprint_ttdriver->ttys); - nd->nd_xprint_ttdriver->ttys = NULL; - - put_tty_driver(nd->nd_xprint_ttdriver); - nd->nd_ttdriver_flags &= ~XPRINT_TTDRV_REG; - } - for (i = 0; i < CHAN_MAX; i++) - tty_port_destroy(&nd->nd_chan[i].port); -} - - - -/* - * Initialize the TTY portion of the supplied node. - */ -int -dgrp_tty_init(struct nd_struct *nd) -{ - char id[3]; - int rc; - int i; - - ID_TO_CHAR(nd->nd_ID, id); - - /* - * Initialize the TTDRIVER structures. - */ - - nd->nd_serial_ttdriver = alloc_tty_driver(CHAN_MAX); - if (!nd->nd_serial_ttdriver) - return -ENOMEM; - - sprintf(nd->nd_serial_name, "tty_dgrp_%s_", id); - - nd->nd_serial_ttdriver->owner = THIS_MODULE; - nd->nd_serial_ttdriver->name = nd->nd_serial_name; - nd->nd_serial_ttdriver->name_base = 0; - nd->nd_serial_ttdriver->major = 0; - nd->nd_serial_ttdriver->minor_start = 0; - nd->nd_serial_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; - nd->nd_serial_ttdriver->subtype = SERIAL_TYPE_NORMAL; - nd->nd_serial_ttdriver->init_termios = DefaultTermios; - nd->nd_serial_ttdriver->driver_name = "dgrp"; - nd->nd_serial_ttdriver->flags = (TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs. */ - nd->nd_serial_ttdriver->ttys = - kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); - if (!nd->nd_serial_ttdriver->ttys) - return -ENOMEM; - - tty_set_operations(nd->nd_serial_ttdriver, &dgrp_tty_ops); - - if (!(nd->nd_ttdriver_flags & SERIAL_TTDRV_REG)) { - /* - * Register tty devices - */ - rc = tty_register_driver(nd->nd_serial_ttdriver); - if (rc < 0) { - /* - * If errno is EBUSY, this means there are no more - * slots available to have us auto-majored. - * (Which is currently supported up to 256) - * - * We can still request majors above 256, - * we just have to do it manually. - */ - if (rc == -EBUSY) { - int i; - int max_majors = 1U << (32 - MINORBITS); - for (i = 256; i < max_majors; i++) { - nd->nd_serial_ttdriver->major = i; - rc = tty_register_driver - (nd->nd_serial_ttdriver); - if (rc >= 0) - break; - } - /* Really fail now, since we ran out - * of majors to try. */ - if (i == max_majors) - return rc; - - } else { - return rc; - } - } - nd->nd_ttdriver_flags |= SERIAL_TTDRV_REG; - } - - nd->nd_callout_ttdriver = alloc_tty_driver(CHAN_MAX); - if (!nd->nd_callout_ttdriver) - return -ENOMEM; - - sprintf(nd->nd_callout_name, "cu_dgrp_%s_", id); - - nd->nd_callout_ttdriver->owner = THIS_MODULE; - nd->nd_callout_ttdriver->name = nd->nd_callout_name; - nd->nd_callout_ttdriver->name_base = 0; - nd->nd_callout_ttdriver->major = nd->nd_serial_ttdriver->major; - nd->nd_callout_ttdriver->minor_start = 0x40; - nd->nd_callout_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; - nd->nd_callout_ttdriver->subtype = SERIAL_TYPE_CALLOUT; - nd->nd_callout_ttdriver->init_termios = DefaultTermios; - nd->nd_callout_ttdriver->driver_name = "dgrp"; - nd->nd_callout_ttdriver->flags = (TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs. */ - nd->nd_callout_ttdriver->ttys = - kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); - if (!nd->nd_callout_ttdriver->ttys) - return -ENOMEM; - - tty_set_operations(nd->nd_callout_ttdriver, &dgrp_tty_ops); - - if (dgrp_register_cudevices) { - if (!(nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG)) { - /* - * Register cu devices - */ - rc = tty_register_driver(nd->nd_callout_ttdriver); - if (rc < 0) - return rc; - nd->nd_ttdriver_flags |= CALLOUT_TTDRV_REG; - } - } - - - nd->nd_xprint_ttdriver = alloc_tty_driver(CHAN_MAX); - if (!nd->nd_xprint_ttdriver) - return -ENOMEM; - - sprintf(nd->nd_xprint_name, "pr_dgrp_%s_", id); - - nd->nd_xprint_ttdriver->owner = THIS_MODULE; - nd->nd_xprint_ttdriver->name = nd->nd_xprint_name; - nd->nd_xprint_ttdriver->name_base = 0; - nd->nd_xprint_ttdriver->major = nd->nd_serial_ttdriver->major; - nd->nd_xprint_ttdriver->minor_start = 0x80; - nd->nd_xprint_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; - nd->nd_xprint_ttdriver->subtype = SERIAL_TYPE_XPRINT; - nd->nd_xprint_ttdriver->init_termios = DefaultTermios; - nd->nd_xprint_ttdriver->driver_name = "dgrp"; - nd->nd_xprint_ttdriver->flags = (TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs. */ - nd->nd_xprint_ttdriver->ttys = - kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); - if (!nd->nd_xprint_ttdriver->ttys) - return -ENOMEM; - - tty_set_operations(nd->nd_xprint_ttdriver, &dgrp_tty_ops); - - if (dgrp_register_prdevices) { - if (!(nd->nd_ttdriver_flags & XPRINT_TTDRV_REG)) { - /* - * Register transparent print devices - */ - rc = tty_register_driver(nd->nd_xprint_ttdriver); - if (rc < 0) - return rc; - nd->nd_ttdriver_flags |= XPRINT_TTDRV_REG; - } - } - - for (i = 0; i < CHAN_MAX; i++) { - struct ch_struct *ch = nd->nd_chan + i; - - ch->ch_nd = nd; - ch->ch_digi = digi_init; - ch->ch_edelay = 100; - ch->ch_custom_speed = 0; - ch->ch_portnum = i; - ch->ch_tun.un_ch = ch; - ch->ch_pun.un_ch = ch; - ch->ch_tun.un_type = SERIAL_TYPE_NORMAL; - ch->ch_pun.un_type = SERIAL_TYPE_XPRINT; - - init_waitqueue_head(&(ch->ch_flag_wait)); - init_waitqueue_head(&(ch->ch_sleep)); - - init_waitqueue_head(&(ch->ch_tun.un_open_wait)); - init_waitqueue_head(&(ch->ch_tun.un_close_wait)); - - init_waitqueue_head(&(ch->ch_pun.un_open_wait)); - init_waitqueue_head(&(ch->ch_pun.un_close_wait)); - tty_port_init(&ch->port); - } - return 0; -} diff --git a/drivers/staging/dgrp/digirp.h b/drivers/staging/dgrp/digirp.h deleted file mode 100644 index 33c1394fade7..000000000000 --- a/drivers/staging/dgrp/digirp.h +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************ - * HP-UX Realport Daemon interface file. - * - * Copyright (C) 1998, by Digi International. All Rights Reserved. - ************************************************************************/ - -#ifndef _DIGIDRP_H -#define _DIGIDRP_H - -/************************************************************************ - * This file contains defines for the ioctl() interface to - * the realport driver. This ioctl() interface is used by the - * daemon to set speed setup parameters honored by the driver. - ************************************************************************/ - -struct link_struct { - int lk_fast_rate; /* Fast line rate to be used - when the delay is less-equal - to lk_fast_delay */ - - int lk_fast_delay; /* Fast line rate delay in - milliseconds */ - - int lk_slow_rate; /* Slow line rate to be used when - the delay is greater-equal - to lk_slow_delay */ - - int lk_slow_delay; /* Slow line rate delay in - milliseconds */ - - int lk_header_size; /* Estimated packet header size - when sent across the slowest - link. */ -}; - -#define DIGI_GETLINK _IOW('e', 103, struct link_struct) /* Get link parameters */ -#define DIGI_SETLINK _IOW('e', 104, struct link_struct) /* Set link parameters */ - - -/************************************************************************ - * This module provides application access to special Digi - * serial line enhancements which are not standard UNIX(tm) features. - ************************************************************************/ - -struct digiflow_struct { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ -}; - -/************************************************************************ - * Values for digi_flags - ************************************************************************/ -#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DSRPACE 0x0010 /* DSR output flow control */ -#define DCDPACE 0x0020 /* DCD output flow control */ -#define DTRPACE 0x0040 /* DTR input flow control */ -#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ -#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl */ -#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input */ -#define DIGI_422 0x4000 /* Change parallel port to input */ -#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ - - -/************************************************************************ - * Values associated with transparent print - ************************************************************************/ -#define DIGI_PLEN 8 /* String length */ -#define DIGI_TSIZ 10 /* Terminal string len */ - - -/************************************************************************ - * Structure used with ioctl commands for DIGI parameters. - ************************************************************************/ -struct digi_struct { - unsigned short digi_flags; /* Flags (see above) */ - unsigned short digi_maxcps; /* Max printer CPS */ - unsigned short digi_maxchar; /* Max chars in print queue */ - unsigned short digi_bufsize; /* Buffer size */ - unsigned char digi_onlen; /* Length of ON string */ - unsigned char digi_offlen; /* Length of OFF string */ - char digi_onstr[DIGI_PLEN]; /* Printer on string */ - char digi_offstr[DIGI_PLEN]; /* Printer off string */ - char digi_term[DIGI_TSIZ]; /* terminal string */ -}; - -/************************************************************************ - * Ioctl command arguments for DIGI parameters. - ************************************************************************/ -/* Read params */ -#define DIGI_GETA _IOR('e', 94, struct digi_struct) - -/* Set params */ -#define DIGI_SETA _IOW('e', 95, struct digi_struct) - -/* Drain & set params */ -#define DIGI_SETAW _IOW('e', 96, struct digi_struct) - -/* Drain, flush & set params */ -#define DIGI_SETAF _IOW('e', 97, struct digi_struct) - -/* Get startc/stopc flow control characters */ -#define DIGI_GETFLOW _IOR('e', 99, struct digiflow_struct) - -/* Set startc/stopc flow control characters */ -#define DIGI_SETFLOW _IOW('e', 100, struct digiflow_struct) - -/* Get Aux. startc/stopc flow control chars */ -#define DIGI_GETAFLOW _IOR('e', 101, struct digiflow_struct) - -/* Set Aux. startc/stopc flow control chars */ -#define DIGI_SETAFLOW _IOW('e', 102, struct digiflow_struct) - -/* Set integer baud rate */ -#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) - -/* Get integer baud rate */ -#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) - -#define DIGI_GEDELAY _IOR('d', 246, int) /* Get edelay */ -#define DIGI_SEDELAY _IOW('d', 247, int) /* Get edelay */ - - -#endif /* _DIGIDRP_H */ diff --git a/drivers/staging/dgrp/drp.h b/drivers/staging/dgrp/drp.h deleted file mode 100644 index 4024b488eba9..000000000000 --- a/drivers/staging/dgrp/drp.h +++ /dev/null @@ -1,693 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * Gene Olson - * James Puzzo - * Scott Kilau - * - * 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, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/************************************************************************ - * Master include file for Linux Realport Driver. - ************************************************************************/ - -#ifndef __DRP_H -#define __DRP_H - -#include -#include -#include -#include - - -#include "digirp.h" - -/************************************************************************ - * Tuning parameters. - ************************************************************************/ - -#define CHAN_MAX 64 /* Max # ports per server */ - -#define SEQ_MAX 128 /* Max # transmit sequences (2^n) */ -#define SEQ_MASK (SEQ_MAX-1) /* Sequence buffer modulus mask */ - -#define TBUF_MAX 4096 /* Size of transmit buffer (2^n) */ -#define RBUF_MAX 4096 /* Size of receive buffer (2^n) */ - -#define TBUF_MASK (TBUF_MAX-1) /* Transmit buffer modulus mask */ -#define RBUF_MASK (RBUF_MAX-1) /* Receive buffer modulus mask */ - -#define TBUF_LOW 1000 /* Transmit low water mark */ - -#define UIO_BASE 1000 /* Base for write operations */ -#define UIO_MIN 2000 /* Minimum size application buffer */ -#define UIO_MAX 8100 /* Unix I/O buffer size */ - -#define MON_MAX 65536 /* Monitor buffer size (2^n) */ -#define MON_MASK (MON_MAX-1) /* Monitor wrap mask */ - -#define DPA_MAX 65536 /* DPA buffer size (2^n) */ -#define DPA_MASK (DPA_MAX-1) /* DPA wrap mask */ -#define DPA_HIGH_WATER 58000 /* Enforce flow control when - * over this amount - */ - -#define IDLE_MAX (20 * HZ) /* Max TCP link idle time */ - -#define MAX_DESC_LEN 100 /* Maximum length of stored PS - * description - */ - -#define WRITEBUFLEN ((4096) + 4) /* 4 extra for alignment play space */ - -#define VPDSIZE 512 - -/************************************************************************ - * Minor device decoding conventions. - ************************************************************************ - * - * For Linux, the net and mon devices are handled via "proc", so we - * only have to mux the "tty" devices. Since every PortServer will - * have an individual major number, the PortServer number does not - * need to be encoded, and in fact, does not need to exist. - * - */ - -/* - * Port device decoding conventions: - * - * Device 00 - 3f 64 dial-in modem devices. (tty) - * Device 40 - 7f 64 dial-out tty devices. (cu) - * Device 80 - bf 64 dial-out printer devices. - * - * IS_PRINT(dev) This is a printer device. - * - * OPEN_CATEGORY(dev) Specifies the device category. No two - * devices of different categories may be open - * at the same time. - * - * The following require the category returned by OPEN_CATEGORY(). - * - * OPEN_WAIT_AVAIL(cat) Waits on open until the device becomes - * available. Fails if NDELAY specified. - * - * OPEN_WAIT_CARRIER(cat) Waits on open if carrier is not present. - * Succeeds if NDELAY is given. - * - * OPEN_FORCES_CARRIER(cat) Carrier is forced high on open. - * - */ - -#define PORT_NUM(dev) ((dev) & 0x3f) - -#define OPEN_CATEGORY(dev) ((((dev) & 0x80) & 0x40)) -#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80) - -#define OPEN_WAIT_AVAIL(cat) (((cat) & 0x40) == 0x000) -#define OPEN_WAIT_CARRIER(cat) (((cat) & 0x40) == 0x000) -#define OPEN_FORCES_CARRIER(cat) (((cat) & 0x40) != 0x000) - - -/************************************************************************ - * Modem signal defines for 16450/16550 compatible FEP. - * set in ch_mout, ch_mflow, ch_mlast etc - ************************************************************************/ - -/* TODO : Re-verify that these modem signal definitions are correct */ - -#define DM_DTR 0x01 -#define DM_RTS 0x02 -#define DM_RTS_TOGGLE 0x04 - -#define DM_OUT1 0x04 -#define DM_OUT2 0x08 - -#define DM_CTS 0x10 -#define DM_DSR 0x20 -#define DM_RI 0x40 -#define DM_CD 0x80 /* This is the DCD flag */ - - -/************************************************************************ - * Realport Event Flags. - ************************************************************************/ - -#define EV_OPU 0x0001 /* Ouput paused by client */ -#define EV_OPS 0x0002 /* Output paused by XOFF */ -#define EV_OPX 0x0004 /* Output paused by XXOFF */ -#define EV_OPH 0x0008 /* Output paused by MFLOW */ -#define EV_IPU 0x0010 /* Input paused by client */ -#define EV_IPS 0x0020 /* Input paused by hi/low water */ -#define EV_TXB 0x0040 /* Transmit break pending */ -#define EV_TXI 0x0080 /* Transmit immediate pending */ -#define EV_TXF 0x0100 /* Transmit flow control pending */ -#define EV_RXB 0x0200 /* Break received */ - - -/************************************************************************ - * Realport CFLAGS. - ************************************************************************/ - -#define CF_CS5 0x0000 /* 5 bit characters */ -#define CF_CS6 0x0010 /* 6 bit characters */ -#define CF_CS7 0x0020 /* 7 bit characters */ -#define CF_CS8 0x0030 /* 8 bit characters */ -#define CF_CSIZE 0x0030 /* Character size */ -#define CF_CSTOPB 0x0040 /* Two stop bits */ -#define CF_CREAD 0x0080 /* Enable receiver */ -#define CF_PARENB 0x0100 /* Enable parity */ -#define CF_PARODD 0x0200 /* Odd parity */ -#define CF_HUPCL 0x0400 /* Drop DTR on close */ - - -/************************************************************************ - * Realport XFLAGS. - ************************************************************************/ - -#define XF_XPAR 0x0001 /* Enable Mark/Space Parity */ -#define XF_XMODEM 0x0002 /* Enable in-band modem signalling */ -#define XF_XCASE 0x0004 /* Convert special characters */ -#define XF_XEDATA 0x0008 /* Error data in stream */ -#define XF_XTOSS 0x0010 /* Toss IXANY characters */ -#define XF_XIXON 0x0020 /* xxon/xxoff enable */ - - -/************************************************************************ - * Realport IFLAGS. - ************************************************************************/ - -#define IF_IGNBRK 0x0001 /* Ignore input break */ -#define IF_BRKINT 0x0002 /* Break interrupt */ -#define IF_IGNPAR 0x0004 /* Ignore error characters */ -#define IF_PARMRK 0x0008 /* Error chars marked with 0xff */ -#define IF_INPCK 0x0010 /* Input parity checking enabled */ -#define IF_ISTRIP 0x0020 /* Input chars masked with 0x7F */ -#define IF_IXON 0x0400 /* Output software flow control */ -#define IF_IXANY 0x0800 /* Restart output on any char */ -#define IF_IXOFF 0x1000 /* Input software flow control */ -#define IF_DOSMODE 0x8000 /* 16450-compatible errors */ - - -/************************************************************************ - * Realport OFLAGS. - ************************************************************************/ - -#define OF_OLCUC 0x0002 /* Map lower to upper case */ -#define OF_ONLCR 0x0004 /* Map NL to CR-NL */ -#define OF_OCRNL 0x0008 /* Map CR to NL */ -#define OF_ONOCR 0x0010 /* No CR output at column 0 */ -#define OF_ONLRET 0x0020 /* Assume NL does NL/CR */ -#define OF_TAB3 0x1800 /* Tabs expand to 8 spaces */ -#define OF_TABDLY 0x1800 /* Tab delay */ - -/************************************************************************ - * Unit flag definitions for un_flag. - ************************************************************************/ - -/* These are the DIGI unit flags */ -#define UN_EXCL 0x00010000 /* Exclusive open */ -#define UN_STICKY 0x00020000 /* TTY Settings are now sticky */ -#define UN_BUSY 0x00040000 /* Some work this channel */ -#define UN_PWAIT 0x00080000 /* Printer waiting for terminal */ -#define UN_TIME 0x00100000 /* Waiting on time */ -#define UN_EMPTY 0x00200000 /* Waiting output queue empty */ -#define UN_LOW 0x00400000 /* Waiting output low water */ -#define UN_DIGI_MASK 0x00FF0000 /* Waiting output low water */ - -/* - * Definitions for async_struct (and serial_struct) flags field - * - * these are the ASYNC flags copied from serial.h - * - */ -#define UN_HUP_NOTIFY 0x0001 /* Notify getty on hangups and - * closes on the callout port - */ -#define UN_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define UN_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define UN_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define UN_SPD_MASK 0x0030 -#define UN_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ -#define UN_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define UN_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define UN_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define UN_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ - -#define UN_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define UN_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define UN_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define UN_FLAGS 0x0FFF /* Possible legal async flags */ -#define UN_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset - */ - -#define UN_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define UN_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define UN_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define UN_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define UN_CLOSING 0x08000000 /* Serial port is closing */ -#define UN_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define UN_CHECK_CD 0x02000000 /* i.e., CLOCAL */ -#define UN_SHARE_IRQ 0x01000000 /* for multifunction cards */ - - -/************************************************************************ - * Structure for terminal or printer unit. struct un_struct - * - * Note that in some places the code assumes the "tty_t" is placed - * first in the structure. - ************************************************************************/ - -struct un_struct { - struct tty_struct *un_tty; /* System TTY struct */ - struct ch_struct *un_ch; /* Associated channel */ - - ushort un_open_count; /* Successful open count */ - int un_flag; /* Unit flags */ - ushort un_tbusy; /* Busy transmit count */ - - wait_queue_head_t un_open_wait; - wait_queue_head_t un_close_wait; - ushort un_type; - struct device *un_sysfs; -}; - - -/************************************************************************ - * Channel State Numbers for ch_state. - ************************************************************************/ - -/* - * The ordering is important. - * - * state <= CS_WAIT_CANCEL implies the channel is definitely closed. - * - * state >= CS_WAIT_FAIL implies the channel is definitely open. - * - * state >= CS_READY implies data is allowed on the channel. - */ - -enum dgrp_ch_state_t { - CS_IDLE = 0, /* Channel is idle */ - CS_WAIT_OPEN = 1, /* Waiting for Immediate Open Resp */ - CS_WAIT_CANCEL = 2, /* Waiting for Per/Incom Cancel Resp */ - CS_WAIT_FAIL = 3, /* Waiting for Immed Open Failure */ - CS_SEND_QUERY = 4, /* Ready to send Port Query */ - CS_WAIT_QUERY = 5, /* Waiting for Port Query Response */ - CS_READY = 6, /* Ready to accept commands and data */ - CS_SEND_CLOSE = 7, /* Ready to send Close Request */ - CS_WAIT_CLOSE = 8 /* Waiting for Close Response */ -}; - -/************************************************************************ - * Device flag definitions for ch_flag. - ************************************************************************/ - -/* - * Note that the state of the two carrier based flags is key. When - * we check for carrier state transitions, we look at the current - * physical state of the DCD line and compare it with PHYS_CD (which - * was the state the last time we checked), and we also determine - * a new virtual state (composite of the physical state, FORCEDCD, - * CLOCAL, etc.) and compare it with VIRT_CD. - * - * VIRTUAL transitions high will have the side effect of waking blocked - * opens. - * - * PHYSICAL transitions low will cause hangups to occur _IF_ the virtual - * state is also low. We DON'T want to hangup on a PURE virtual drop. - */ - -#define CH_HANGUP 0x00002 /* Server port ready to close */ - -#define CH_VIRT_CD 0x00004 /* Carrier was virtually present */ -#define CH_PHYS_CD 0x00008 /* Carrier was physically present */ - -#define CH_CLOCAL 0x00010 /* CLOCAL set in cflags */ -#define CH_BAUD0 0x00020 /* Baud rate zero hangup */ - -#define CH_FAST_READ 0x00040 /* Fast reads are enabled */ -#define CH_FAST_WRITE 0x00080 /* Fast writes are enabled */ - -#define CH_PRON 0x00100 /* Printer on string active */ -#define CH_RX_FLUSH 0x00200 /* Flushing receive data */ -#define CH_LOW 0x00400 /* Thread waiting for LOW water */ -#define CH_EMPTY 0x00800 /* Thread waiting for EMPTY */ -#define CH_DRAIN 0x01000 /* Close is waiting to drain */ -#define CH_INPUT 0x02000 /* Thread waiting for INPUT */ -#define CH_RXSTOP 0x04000 /* Stop output to ldisc */ -#define CH_PARAM 0x08000 /* A parameter was updated */ -#define CH_WAITING_SYNC 0x10000 /* A pending sync was assigned - * to this port. - */ -#define CH_PORT_GONE 0x20000 /* Port has disappeared */ -#define CH_TX_BREAK 0x40000 /* TX Break to be sent, - * but has not yet. - */ - -/************************************************************************ - * Types of Open Requests for ch_otype. - ************************************************************************/ - -#define OTYPE_IMMEDIATE 0 /* Immediate Open */ -#define OTYPE_PERSISTENT 1 /* Persistent Open */ -#define OTYPE_INCOMING 2 /* Incoming Open */ - - -/************************************************************************ - * Request/Response flags. - ************************************************************************/ - -#define RR_SEQUENCE 0x0001 /* Get server RLAST, TIN */ -#define RR_STATUS 0x0002 /* Get server MINT, EINT */ -#define RR_BUFFER 0x0004 /* Get server RSIZE, TSIZE */ -#define RR_CAPABILITY 0x0008 /* Get server port capabilities */ - -#define RR_TX_FLUSH 0x0040 /* Flush output buffers */ -#define RR_RX_FLUSH 0x0080 /* Flush input buffers */ - -#define RR_TX_STOP 0x0100 /* Pause output */ -#define RR_RX_STOP 0x0200 /* Pause input */ -#define RR_TX_START 0x0400 /* Start output */ -#define RR_RX_START 0x0800 /* Start input */ - -#define RR_TX_BREAK 0x1000 /* Send BREAK */ -#define RR_TX_ICHAR 0x2000 /* Send character immediate */ - - -/************************************************************************ - * Channel information structure. struct ch_struct - ************************************************************************/ - -struct ch_struct { - struct digi_struct ch_digi; /* Digi variables */ - int ch_edelay; /* Digi edelay */ - - struct tty_port port; - struct un_struct ch_tun; /* Terminal unit info */ - struct un_struct ch_pun; /* Printer unit info */ - - struct nd_struct *ch_nd; /* Node pointer */ - u8 *ch_tbuf; /* Local Transmit Buffer */ - u8 *ch_rbuf; /* Local Receive Buffer */ - ulong ch_cpstime; /* Printer CPS time */ - ulong ch_waketime; /* Printer wake time */ - - ulong ch_flag; /* CH_* flags */ - - enum dgrp_ch_state_t ch_state; /* CS_* Protocol state */ - ushort ch_send; /* Bit vector of RR_* requests */ - ushort ch_expect; /* Bit vector of RR_* responses */ - ushort ch_wait_carrier; /* Thread count waiting for carrier */ - ushort ch_wait_count[3]; /* Thread count waiting by otype */ - - ushort ch_portnum; /* Port number */ - ushort ch_open_count; /* Successful open count */ - ushort ch_category; /* Device category */ - ushort ch_open_error; /* Last open error number */ - ushort ch_break_time; /* Pending break request time */ - ushort ch_cpsrem; /* Printer CPS remainder */ - ushort ch_ocook; /* Realport fastcook oflags */ - ushort ch_inwait; /* Thread count in CLIST input */ - - ushort ch_tin; /* Local transmit buffer in ptr */ - ushort ch_tout; /* Local transmit buffer out ptr */ - ushort ch_s_tin; /* Realport TIN */ - ushort ch_s_tpos; /* Realport TPOS */ - ushort ch_s_tsize; /* Realport TSIZE */ - ushort ch_s_treq; /* Realport TREQ */ - ushort ch_s_elast; /* Realport ELAST */ - - ushort ch_rin; /* Local receive buffer in ptr */ - ushort ch_rout; /* Local receive buffer out ptr */ - ushort ch_s_rin; /* Realport RIN */ - /* David Fries 7-13-2001, ch_s_rin should be renamed ch_s_rout because - * the variable we want to represent is the PortServer's ROUT, which is - * the sequence number for the next byte the PortServer will send us. - * RIN is the sequence number for the next byte the PortServer will - * receive from the uart. The port server will send data as long as - * ROUT is less than RWIN. What would happen is the port is opened, it - * receives data, it gives the value of RIN, we set the RWIN to - * RIN+RBUF_MAX-1, it sends us RWIN-ROUT bytes which overflows. ROUT - * is set to zero when the port is opened, so we start at zero and - * count up as data is received. - */ - ushort ch_s_rwin; /* Realport RWIN */ - ushort ch_s_rsize; /* Realport RSIZE */ - - ushort ch_tmax; /* Local TMAX */ - ushort ch_ttime; /* Local TTIME */ - ushort ch_rmax; /* Local RMAX */ - ushort ch_rtime; /* Local RTIME */ - ushort ch_rlow; /* Local RLOW */ - ushort ch_rhigh; /* Local RHIGH */ - - ushort ch_s_tmax; /* Realport TMAX */ - ushort ch_s_ttime; /* Realport TTIME */ - ushort ch_s_rmax; /* Realport RMAX */ - ushort ch_s_rtime; /* Realport RTIME */ - ushort ch_s_rlow; /* Realport RLOW */ - ushort ch_s_rhigh; /* Realport RHIGH */ - - ushort ch_brate; /* Local baud rate */ - ushort ch_cflag; /* Local tty cflags */ - ushort ch_iflag; /* Local tty iflags */ - ushort ch_oflag; /* Local tty oflags */ - ushort ch_xflag; /* Local tty xflags */ - - ushort ch_s_brate; /* Realport BRATE */ - ushort ch_s_cflag; /* Realport CFLAG */ - ushort ch_s_iflag; /* Realport IFLAG */ - ushort ch_s_oflag; /* Realport OFLAG */ - ushort ch_s_xflag; /* Realport XFLAG */ - - u8 ch_otype; /* Open request type */ - u8 ch_pscan_savechar; /* Last character read by parity scan */ - u8 ch_pscan_state; /* PScan State based on last 2 chars */ - u8 ch_otype_waiting; /* Type of open pending in server */ - u8 ch_flush_seq; /* Receive flush end sequence */ - u8 ch_s_mlast; /* Realport MLAST */ - - u8 ch_mout; /* Local MOUT */ - u8 ch_mflow; /* Local MFLOW */ - u8 ch_mctrl; /* Local MCTRL */ - u8 ch_xon; /* Local XON */ - u8 ch_xoff; /* Local XOFF */ - u8 ch_lnext; /* Local LNEXT */ - u8 ch_xxon; /* Local XXON */ - u8 ch_xxoff; /* Local XXOFF */ - - u8 ch_s_mout; /* Realport MOUT */ - u8 ch_s_mflow; /* Realport MFLOW */ - u8 ch_s_mctrl; /* Realport MCTRL */ - u8 ch_s_xon; /* Realport XON */ - u8 ch_s_xoff; /* Realport XOFF */ - u8 ch_s_lnext; /* Realport LNEXT */ - u8 ch_s_xxon; /* Realport XXON */ - u8 ch_s_xxoff; /* Realport XXOFF */ - - wait_queue_head_t ch_flag_wait; /* Wait queue for ch_flag changes */ - wait_queue_head_t ch_sleep; /* Wait queue for my_sleep() */ - - int ch_custom_speed; /* Realport custom speed */ - int ch_txcount; /* Running TX count */ - int ch_rxcount; /* Running RX count */ -}; - - -/************************************************************************ - * Node State definitions. - ************************************************************************/ - -enum dgrp_nd_state_t { - NS_CLOSED = 0, /* Network device is closed */ - NS_IDLE = 1, /* Network connection inactive */ - NS_SEND_QUERY = 2, /* Send server query */ - NS_WAIT_QUERY = 3, /* Wait for query response */ - NS_READY = 4, /* Network ready */ - NS_SEND_ERROR = 5 /* Must send error hangup */ -}; - -#define ND_STATE_STR(x) \ - ((x) == NS_CLOSED ? "CLOSED" : \ - ((x) == NS_IDLE ? "IDLE" : \ - ((x) == NS_SEND_QUERY ? "SEND_QUERY" : \ - ((x) == NS_WAIT_QUERY ? "WAIT_QUERY" : \ - ((x) == NS_READY ? "READY" : \ - ((x) == NS_SEND_ERROR ? "SEND_ERROR" : "UNKNOWN")))))) - -/************************************************************************ - * Node Flag definitions. - ************************************************************************/ - -#define ND_SELECT 0x0001 /* Multiple net read selects */ -#define ND_DEB_WAIT 0x0002 /* Debug Device waiting */ - - -/************************************************************************ - * Monitoring flag definitions. - ************************************************************************/ - -#define MON_WAIT_DATA 0x0001 /* Waiting for buffer data */ -#define MON_WAIT_SPACE 0x0002 /* Waiting for buffer space */ - -/************************************************************************ - * DPA flag definitions. - ************************************************************************/ - -#define DPA_WAIT_DATA 0x0001 /* Waiting for buffer data */ -#define DPA_WAIT_SPACE 0x0002 /* Waiting for buffer space */ - - -/************************************************************************ - * Definitions taken from Realport Dump. - ************************************************************************/ - -#define RPDUMP_MAGIC "Digi-RealPort-1.0" - -#define RPDUMP_MESSAGE 0xE2 /* Descriptive message */ -#define RPDUMP_RESET 0xE7 /* Connection reset */ -#define RPDUMP_CLIENT 0xE8 /* Client data */ -#define RPDUMP_SERVER 0xE9 /* Server data */ - - -/************************************************************************ - * Node request/response definitions. - ************************************************************************/ - -#define NR_ECHO 0x0001 /* Server echo packet */ -#define NR_IDENT 0x0002 /* Server Product ID */ -#define NR_CAPABILITY 0x0004 /* Server Capabilties */ -#define NR_VPD 0x0008 /* Server VPD, if any */ -#define NR_PASSWORD 0x0010 /* Server Password */ - -/************************************************************************ - * Registration status of the node's Linux struct tty_driver structures. - ************************************************************************/ -#define SERIAL_TTDRV_REG 0x0001 /* nd_serial_ttdriver registered */ -#define CALLOUT_TTDRV_REG 0x0002 /* nd_callout_ttdriver registered */ -#define XPRINT_TTDRV_REG 0x0004 /* nd_xprint_ttdriver registered */ - - -/************************************************************************ - * Node structure. There exists one of these for each associated - * realport server. - ************************************************************************/ - -struct nd_struct { - struct list_head list; - long nd_major; /* Node's major number */ - long nd_ID; /* Node's ID code */ - - char nd_serial_name[50]; /* "tty_dgrp__" + null */ - char nd_callout_name[50]; /* "cu_dgrp__" + null */ - char nd_xprint_name[50]; /* "pr_dgrp__" + null */ - - char password[16]; /* Password for server, if needed */ - int nd_tty_ref_cnt; /* Linux tty reference count */ - - struct proc_dir_entry *nd_net_de; /* Dir entry for /proc/dgrp/net */ - struct proc_dir_entry *nd_mon_de; /* Dir entry for /proc/dgrp/mon */ - struct proc_dir_entry *nd_ports_de; /* Dir entry for /proc/dgrp/ports*/ - struct proc_dir_entry *nd_dpa_de; /* Dir entry for /proc/dgrp/dpa */ - - spinlock_t nd_lock; /* General node lock */ - - struct semaphore nd_net_semaphore; /* Net read/write lock */ - struct semaphore nd_mon_semaphore; /* Monitor buffer lock */ - spinlock_t nd_dpa_lock; /* DPA buffer lock */ - - enum dgrp_nd_state_t nd_state; /* NS_* network state */ - int nd_chan_count; /* # active channels */ - int nd_flag; /* Node flags */ - int nd_send; /* Responses to send */ - int nd_expect; /* Responses we expect */ - - u8 *nd_iobuf; /* Network R/W Buffer */ - wait_queue_head_t nd_tx_waitq; /* Network select wait queue */ - - u8 *nd_inputbuf; /* Input Buffer */ - u8 *nd_inputflagbuf; /* Input Flags Buffer */ - - int nd_tx_deposit; /* Accumulated transmit deposits */ - int nd_tx_charge; /* Accumulated transmit charges */ - int nd_tx_credit; /* Current TX credit */ - int nd_tx_ready; /* Ready to transmit */ - int nd_tx_work; /* TX work waiting */ - ulong nd_tx_time; /* Last transmit time */ - ulong nd_poll_time; /* Next scheduled poll time */ - - int nd_delay; /* Current TX delay */ - int nd_rate; /* Current TX rate */ - struct link_struct nd_link; /* Link speed params. */ - - int nd_seq_in; /* TX seq in ptr */ - int nd_seq_out; /* TX seq out ptr */ - int nd_unack; /* Unacknowledged byte count */ - int nd_remain; /* Remaining receive bytes */ - int nd_tx_module; /* Current TX module # */ - int nd_rx_module; /* Current RX module # */ - char *nd_error; /* Protocol error message */ - - int nd_write_count; /* drp_write() call count */ - int nd_read_count; /* drp_read() count */ - int nd_send_count; /* TCP message sent */ - int nd_tx_byte; /* Transmit byte count */ - int nd_rx_byte; /* Receive byte count */ - - ulong nd_mon_lbolt; /* Monitor start time */ - int nd_mon_flag; /* Monitor flags */ - int nd_mon_in; /* Monitor in pointer */ - int nd_mon_out; /* Monitor out pointer */ - wait_queue_head_t nd_mon_wqueue; /* Monitor wait queue (on flags) */ - u8 *nd_mon_buf; /* Monitor buffer */ - - ulong nd_dpa_lbolt; /* DPA start time */ - int nd_dpa_flag; /* DPA flags */ - int nd_dpa_in; /* DPA in pointer */ - int nd_dpa_out; /* DPA out pointer */ - wait_queue_head_t nd_dpa_wqueue; /* DPA wait queue (on flags) */ - u8 *nd_dpa_buf; /* DPA buffer */ - - uint nd_dpa_debug; - uint nd_dpa_port; - - wait_queue_head_t nd_seq_wque[SEQ_MAX]; /* TX thread wait queues */ - u8 nd_seq_wait[SEQ_MAX]; /* Transmit thread wait count */ - - ushort nd_seq_size[SEQ_MAX]; /* Transmit seq packet size */ - ulong nd_seq_time[SEQ_MAX]; /* Transmit seq packet time */ - - ushort nd_hw_ver; /* HW version returned from PS */ - ushort nd_sw_ver; /* SW version returned from PS */ - uint nd_hw_id; /* HW ID returned from PS */ - u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */ - uint nd_vpd_len; /* VPD len, if any */ - u8 nd_vpd[VPDSIZE]; /* VPD, if any */ - - ulong nd_ttdriver_flags; /* Registration status */ - struct tty_driver *nd_serial_ttdriver; /* Linux TTYDRIVER structure */ - struct tty_driver *nd_callout_ttdriver; /* Linux TTYDRIVER structure */ - struct tty_driver *nd_xprint_ttdriver; /* Linux TTYDRIVER structure */ - - u8 *nd_writebuf; /* Used to cache data read - * from user - */ - struct ch_struct nd_chan[CHAN_MAX]; /* Channel array */ - struct device *nd_class_dev; /* Hang our sysfs stuff off of here */ -}; - -#endif /* __DRP_H */ -- cgit v1.2.3-58-ga151