linux/drivers/staging/dgnc/dgnc_mgmt.c
<<
>>
Prefs
   1/*
   2 * Copyright 2003 Digi International (www.digi.com)
   3 *      Scott H Kilau <Scott_Kilau at digi dot com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2, or (at your option)
   8 * any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
  12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13 * PURPOSE.  See the GNU General Public License for more details.
  14 */
  15
  16/************************************************************************
  17 *
  18 * This file implements the mgmt functionality for the
  19 * Neo and ClassicBoard based product lines.
  20 *
  21 ************************************************************************
  22 */
  23#include <linux/kernel.h>
  24#include <linux/ctype.h>
  25#include <linux/sched.h>        /* For jiffies, task states */
  26#include <linux/interrupt.h>    /* For tasklet and interrupt structs/defines */
  27#include <linux/serial_reg.h>
  28#include <linux/termios.h>
  29#include <linux/uaccess.h>      /* For copy_from_user/copy_to_user */
  30
  31#include "dgnc_driver.h"
  32#include "dgnc_pci.h"
  33#include "dgnc_mgmt.h"
  34
  35/* Our "in use" variables, to enforce 1 open only */
  36static int dgnc_mgmt_in_use[MAXMGMTDEVICES];
  37
  38/*
  39 * dgnc_mgmt_open()
  40 *
  41 * Open the mgmt/downld/dpa device
  42 */
  43int dgnc_mgmt_open(struct inode *inode, struct file *file)
  44{
  45        unsigned long flags;
  46        unsigned int minor = iminor(inode);
  47
  48        spin_lock_irqsave(&dgnc_global_lock, flags);
  49
  50        /* mgmt device */
  51        if (minor < MAXMGMTDEVICES) {
  52                /* Only allow 1 open at a time on mgmt device */
  53                if (dgnc_mgmt_in_use[minor]) {
  54                        spin_unlock_irqrestore(&dgnc_global_lock, flags);
  55                        return -EBUSY;
  56                }
  57                dgnc_mgmt_in_use[minor]++;
  58        } else {
  59                spin_unlock_irqrestore(&dgnc_global_lock, flags);
  60                return -ENXIO;
  61        }
  62
  63        spin_unlock_irqrestore(&dgnc_global_lock, flags);
  64
  65        return 0;
  66}
  67
  68/*
  69 * dgnc_mgmt_close()
  70 *
  71 * Open the mgmt/dpa device
  72 */
  73int dgnc_mgmt_close(struct inode *inode, struct file *file)
  74{
  75        unsigned long flags;
  76        unsigned int minor = iminor(inode);
  77
  78        spin_lock_irqsave(&dgnc_global_lock, flags);
  79
  80        /* mgmt device */
  81        if (minor < MAXMGMTDEVICES) {
  82                if (dgnc_mgmt_in_use[minor])
  83                        dgnc_mgmt_in_use[minor] = 0;
  84        }
  85        spin_unlock_irqrestore(&dgnc_global_lock, flags);
  86
  87        return 0;
  88}
  89
  90/*
  91 * dgnc_mgmt_ioctl()
  92 *
  93 * ioctl the mgmt/dpa device
  94 */
  95
  96long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  97{
  98        unsigned long flags;
  99        void __user *uarg = (void __user *)arg;
 100
 101        switch (cmd) {
 102        case DIGI_GETDD:
 103        {
 104                /*
 105                 * This returns the total number of boards
 106                 * in the system, as well as driver version
 107                 * and has space for a reserved entry
 108                 */
 109                struct digi_dinfo ddi;
 110
 111                spin_lock_irqsave(&dgnc_global_lock, flags);
 112
 113                memset(&ddi, 0, sizeof(ddi));
 114                ddi.dinfo_nboards = dgnc_NumBoards;
 115                sprintf(ddi.dinfo_version, "%s", DG_PART);
 116
 117                spin_unlock_irqrestore(&dgnc_global_lock, flags);
 118
 119                if (copy_to_user(uarg, &ddi, sizeof(ddi)))
 120                        return -EFAULT;
 121
 122                break;
 123        }
 124
 125        case DIGI_GETBD:
 126        {
 127                int brd;
 128
 129                struct digi_info di;
 130
 131                if (copy_from_user(&brd, uarg, sizeof(int)))
 132                        return -EFAULT;
 133
 134                if (brd < 0 || brd >= dgnc_NumBoards)
 135                        return -ENODEV;
 136
 137                memset(&di, 0, sizeof(di));
 138
 139                di.info_bdnum = brd;
 140
 141                spin_lock_irqsave(&dgnc_Board[brd]->bd_lock, flags);
 142
 143                di.info_bdtype = dgnc_Board[brd]->dpatype;
 144                di.info_bdstate = dgnc_Board[brd]->dpastatus;
 145                di.info_ioport = 0;
 146                di.info_physaddr = (ulong)dgnc_Board[brd]->membase;
 147                di.info_physsize = (ulong)dgnc_Board[brd]->membase
 148                        - dgnc_Board[brd]->membase_end;
 149                if (dgnc_Board[brd]->state != BOARD_FAILED)
 150                        di.info_nports = dgnc_Board[brd]->nasync;
 151                else
 152                        di.info_nports = 0;
 153
 154                spin_unlock_irqrestore(&dgnc_Board[brd]->bd_lock, flags);
 155
 156                if (copy_to_user(uarg, &di, sizeof(di)))
 157                        return -EFAULT;
 158
 159                break;
 160        }
 161
 162        case DIGI_GET_NI_INFO:
 163        {
 164                struct channel_t *ch;
 165                struct ni_info ni;
 166                unsigned char mstat = 0;
 167                uint board = 0;
 168                uint channel = 0;
 169
 170                if (copy_from_user(&ni, uarg, sizeof(ni)))
 171                        return -EFAULT;
 172
 173                board = ni.board;
 174                channel = ni.channel;
 175
 176                /* Verify boundaries on board */
 177                if (board >= dgnc_NumBoards)
 178                        return -ENODEV;
 179
 180                /* Verify boundaries on channel */
 181                if (channel >= dgnc_Board[board]->nasync)
 182                        return -ENODEV;
 183
 184                ch = dgnc_Board[board]->channels[channel];
 185
 186                if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
 187                        return -ENODEV;
 188
 189                memset(&ni, 0, sizeof(ni));
 190                ni.board = board;
 191                ni.channel = channel;
 192
 193                spin_lock_irqsave(&ch->ch_lock, flags);
 194
 195                mstat = ch->ch_mostat | ch->ch_mistat;
 196
 197                if (mstat & UART_MCR_DTR) {
 198                        ni.mstat |= TIOCM_DTR;
 199                        ni.dtr = TIOCM_DTR;
 200                }
 201                if (mstat & UART_MCR_RTS) {
 202                        ni.mstat |= TIOCM_RTS;
 203                        ni.rts = TIOCM_RTS;
 204                }
 205                if (mstat & UART_MSR_CTS) {
 206                        ni.mstat |= TIOCM_CTS;
 207                        ni.cts = TIOCM_CTS;
 208                }
 209                if (mstat & UART_MSR_RI) {
 210                        ni.mstat |= TIOCM_RI;
 211                        ni.ri = TIOCM_RI;
 212                }
 213                if (mstat & UART_MSR_DCD) {
 214                        ni.mstat |= TIOCM_CD;
 215                        ni.dcd = TIOCM_CD;
 216                }
 217                if (mstat & UART_MSR_DSR)
 218                        ni.mstat |= TIOCM_DSR;
 219
 220                ni.iflag = ch->ch_c_iflag;
 221                ni.oflag = ch->ch_c_oflag;
 222                ni.cflag = ch->ch_c_cflag;
 223                ni.lflag = ch->ch_c_lflag;
 224
 225                if (ch->ch_digi.digi_flags & CTSPACE ||
 226                    ch->ch_c_cflag & CRTSCTS)
 227                        ni.hflow = 1;
 228                else
 229                        ni.hflow = 0;
 230
 231                if ((ch->ch_flags & CH_STOPI) ||
 232                    (ch->ch_flags & CH_FORCED_STOPI))
 233                        ni.recv_stopped = 1;
 234                else
 235                        ni.recv_stopped = 0;
 236
 237                if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP))
 238                        ni.xmit_stopped = 1;
 239                else
 240                        ni.xmit_stopped = 0;
 241
 242                ni.curtx = ch->ch_txcount;
 243                ni.currx = ch->ch_rxcount;
 244
 245                ni.baud = ch->ch_old_baud;
 246
 247                spin_unlock_irqrestore(&ch->ch_lock, flags);
 248
 249                if (copy_to_user(uarg, &ni, sizeof(ni)))
 250                        return -EFAULT;
 251
 252                break;
 253        }
 254        }
 255
 256        return 0;
 257}
 258