Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 *
 * 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;
}