source "drivers/staging/imx-drm/Kconfig"
-source "drivers/staging/dgrp/Kconfig"
-
source "drivers/staging/fwserial/Kconfig"
source "drivers/staging/goldfish/Kconfig"
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/
+++ /dev/null
-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.
+++ /dev/null
-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
+++ /dev/null
-The user space code to work with this driver is located at
-https://github.com/wfp5p/dgrp-utils
+++ /dev/null
-- 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
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/cred.h>
-
-#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;
-
-}
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/fs.h>
-#include <linux/timer.h>
-#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 */
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/tty.h>
-#include <linux/poll.h>
-#include <linux/cred.h>
-#include <linux/sched.h>
-#include <linux/ratelimit.h>
-#include <linux/slab.h>
-#include <asm/unaligned.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * Copyright 1999-2003 Digi International (www.digi.com)
- * Jeff Randall
- * James Puzzo <jamesp at digi dot com>
- * Scott Kilau <Scott_Kilau at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-
-/*
- * 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);
+++ /dev/null
-/*****************************************************************************
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <asm/unaligned.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/uaccess.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/spinlock.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/ratelimit.h>
-#include <asm/unaligned.h>
-
-#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);
-}
+++ /dev/null
-/*
- *
- * Copyright 1999-2000 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-
-#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;
-}
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * James Puzzo <jamesp at digi dot com>
- *
- * 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 <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/cred.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/seq_file.h>
-#include <linux/uaccess.h>
-#include <linux/vmalloc.h>
-
-#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);
-}
+++ /dev/null
-/*
- * Copyright 2004 Digi International (www.digi.com)
- * Scott H Kilau <Scott_Kilau at digi dot com>
- *
- * 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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/serial_reg.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-
-
-#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);
-}
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * Gene Olson <Gene_Olson at digi dot com>
- * James Puzzo <jamesp at digi dot com>
- * Jeff Randall
- * Scott Kilau <scottk at digi dot com>
- *
- * 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 <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/device.h>
-#include <linux/sched.h>
-#include <linux/uaccess.h>
-
-#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;
-}
+++ /dev/null
-/************************************************************************
- * 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 */
+++ /dev/null
-/*
- *
- * Copyright 1999 Digi International (www.digi.com)
- * Gene Olson <gene at digi dot com>
- * James Puzzo <jamesp at digi dot com>
- * Scott Kilau <scottk at digi dot com>
- *
- * 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 <linux/types.h>
-#include <linux/wait.h>
-#include <linux/semaphore.h>
-#include <linux/tty.h>
-
-
-#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_<id>_" + null */
- char nd_callout_name[50]; /* "cu_dgrp_<id>_" + null */
- char nd_xprint_name[50]; /* "pr_dgrp_<id>_" + 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 */