Commit 0b52b749 authored by Bill Pemberton's avatar Bill Pemberton Committed by Greg Kroah-Hartman

staging: Add dgrp driver for Digi Realport devices

This is based on dgrp-1.9 available from
ftp://ftp1.digi.com/support/beta/linux/dgrp/dgrp-1.9.tgzSigned-off-by: default avatarBill Pemberton <wfp5p@virginia.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5de69349
config DGRP
tristate "Digi Realport driver"
default n
depends on SYSFS
---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.
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
The user space code to work with this driver is located at
https://github.com/wfp5p/dgrp-utils
- Use configfs for config stuff. This will require changes to the
user space code.
- Check the calls to tty_register_device. In particular, check to see
if there should be some handling for IS_ERR(classp).
- dgrp_send() and dgrp_receive() could use some refactoring
/*
*
* 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;
}
/**
* dgrp_chk_perm() -- check permissions for net device
* @inode: pointer to inode structure for the net communication device
* @op: operation to be tested
*
* The file permissions and ownerships are tested to determine whether
* the operation "op" is permitted on the file pointed to by the inode.
* Returns 0 if the operation is permitted, -EACCESS otherwise
*/
int dgrp_chk_perm(int mode, int op)
{
if (!current_euid())
mode >>= 6;
else if (in_egroup_p(0))
mode >>= 3;
if ((mode & op & 0007) == op)
return 0;
if (capable(CAP_SYS_ADMIN))
return 0;
return -EACCES;
}
/* dgrp_chk_perm wrapper for permission call in struct inode_operations */
int dgrp_inode_permission(struct inode *inode, int op)
{
return dgrp_chk_perm(inode->i_mode, op);
}
/*
*
* 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_rawreadok; /* Allow raw writing of input */
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 void dgrp_register_mon_hook(struct proc_dir_entry *de);
/* 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 void dgrp_register_ports_hook(struct proc_dir_entry *de);
/* from dgrp_net_ops.c */
extern void dgrp_register_net_hook(struct proc_dir_entry *de);
/* from dgrp_dpa_ops.c */
extern void dgrp_register_dpa_hook(struct proc_dir_entry *de);
extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int);
/* from dgrp_sysfs.c */
extern void 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 */
/*
* The list of DGRP entries with r/w capabilities. These
* magic numbers are used for identification purposes.
*/
enum {
DGRP_CONFIG = 1, /* Configure portservers */
DGRP_NETDIR = 2, /* Directory for "net" devices */
DGRP_MONDIR = 3, /* Directory for "mon" devices */
DGRP_PORTSDIR = 4, /* Directory for "ports" devices */
DGRP_INFO = 5, /* Get info. about the running module */
DGRP_NODEINFO = 6, /* Get info. about the configured nodes */
DGRP_DPADIR = 7, /* Directory for the "dpa" devices */
};
/*
* Directions for proc handlers
*/
enum {
INBOUND = 1, /* Data being written to kernel */
OUTBOUND = 2, /* Data being read from the kernel */
};
/**
* dgrp_proc_entry: structure for dgrp proc dirs
* @id: ID number associated with this particular entry. Should be
* unique across all of DGRP.
* @name: text name associated with the /proc entry
* @mode: file access permisssions for the /proc entry
* @child: pointer to table describing a subdirectory for this entry
* @de: pointer to directory entry for this object once registered. Used
* to grab the handle of the object for unregistration
* @excl_sem: semaphore to provide exclusive to struct
* @excl_cnt: counter of current accesses
*
* Each entry in a DGRP proc directory is described with a
* dgrp_proc_entry structure. A collection of these
* entries (in an array) represents the members associated
* with a particular /proc directory, and is referred to
* as a table. All tables are terminated by an entry with
* zeros for every member.
*/
struct dgrp_proc_entry {
int id; /* Integer identifier */
const char *name; /* ASCII identifier */
mode_t mode; /* File access permissions */
struct dgrp_proc_entry *child; /* Child pointer */
/* file ops to use, pass NULL to use default */
struct file_operations *proc_file_ops;
struct proc_dir_entry *de; /* proc entry pointer */
struct semaphore excl_sem; /* Protects exclusive access var */
int excl_cnt; /* Counts number of curr accesses */
};
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);
extern int dgrp_inode_permission(struct inode *inode, int op);
extern int dgrp_chk_perm(int mode, int op);
/*
* 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 */
This diff is collapsed.
/*
*
* 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>
#include <linux/init.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_rawreadok = 1; /* Bypass flipbuf on input */
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(rawreadok, dgrp_rawreadok, int, 0644);
MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input");
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");
/* Driver load/unload functions */
static int dgrp_init_module(void);
static void dgrp_cleanup_module(void);
module_init(dgrp_init_module);
module_exit(dgrp_cleanup_module);
/*
* init_module()
*
* Module load. This is where it all starts.
*/
static int dgrp_init_module(void)
{
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;
dgrp_create_class_sysfs_files();
dgrp_register_proc();
return 0;
}
/*
* Module unload. This is where it all ends.
*/
static void 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);
}
}
/*****************************************************************************
*
* 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/proc_fs.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);
static const struct file_operations mon_ops = {
.owner = THIS_MODULE,
.read = dgrp_mon_read,
.unlocked_ioctl = dgrp_mon_ioctl,
.open = dgrp_mon_open,
.release = dgrp_mon_release,
};
static struct inode_operations mon_inode_ops = {
.permission = dgrp_inode_permission
};
void dgrp_register_mon_hook(struct proc_dir_entry *de)
{
struct nd_struct *node = de->data;
de->proc_iops = &mon_inode_ops;
de->proc_fops = &mon_ops;
node->nd_mon_de = de;
sema_init(&node->nd_mon_semaphore, 1);
}
/**
* 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 proc_dir_entry *de;
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.
*/
de = PDE(inode);
if (!de) {
rtn = -ENXIO;
goto done;
}
nd = (struct nd_struct *)de->data;
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;
}
This diff is collapsed.
/*
*
* 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 *);
static const struct file_operations ports_ops = {
.owner = THIS_MODULE,
.open = dgrp_ports_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
static struct inode_operations ports_inode_ops = {
.permission = dgrp_inode_permission
};
void dgrp_register_ports_hook(struct proc_dir_entry *de)
{
struct nd_struct *node = de->data;
de->proc_iops = &ports_inode_ops;
de->proc_fops = &ports_ops;
node->nd_ports_de = de;
}
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(inode)->data;
}
return rtn;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/************************************************************************
* 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 */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment