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 36/* Our "in use" variables, to enforce 1 open only */ 37static int dgnc_mgmt_in_use[MAXMGMTDEVICES]; 38 39 40/* 41 * dgnc_mgmt_open() 42 * 43 * Open the mgmt/downld/dpa device 44 */ 45int dgnc_mgmt_open(struct inode *inode, struct file *file) 46{ 47 unsigned long flags; 48 unsigned int minor = iminor(inode); 49 50 spin_lock_irqsave(&dgnc_global_lock, flags); 51 52 /* mgmt device */ 53 if (minor < MAXMGMTDEVICES) { 54 /* Only allow 1 open at a time on mgmt device */ 55 if (dgnc_mgmt_in_use[minor]) { 56 spin_unlock_irqrestore(&dgnc_global_lock, flags); 57 return -EBUSY; 58 } 59 dgnc_mgmt_in_use[minor]++; 60 } else { 61 spin_unlock_irqrestore(&dgnc_global_lock, flags); 62 return -ENXIO; 63 } 64 65 spin_unlock_irqrestore(&dgnc_global_lock, flags); 66 67 return 0; 68} 69 70 71/* 72 * dgnc_mgmt_close() 73 * 74 * Open the mgmt/dpa device 75 */ 76int dgnc_mgmt_close(struct inode *inode, struct file *file) 77{ 78 unsigned long flags; 79 unsigned int minor = iminor(inode); 80 81 spin_lock_irqsave(&dgnc_global_lock, flags); 82 83 /* mgmt device */ 84 if (minor < MAXMGMTDEVICES) { 85 if (dgnc_mgmt_in_use[minor]) 86 dgnc_mgmt_in_use[minor] = 0; 87 } 88 spin_unlock_irqrestore(&dgnc_global_lock, flags); 89 90 return 0; 91} 92 93 94/* 95 * dgnc_mgmt_ioctl() 96 * 97 * ioctl the mgmt/dpa device 98 */ 99 100long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 101{ 102 unsigned long flags; 103 void __user *uarg = (void __user *) arg; 104 105 switch (cmd) { 106 107 case DIGI_GETDD: 108 { 109 /* 110 * This returns the total number of boards 111 * in the system, as well as driver version 112 * and has space for a reserved entry 113 */ 114 struct digi_dinfo ddi; 115 116 spin_lock_irqsave(&dgnc_global_lock, flags); 117 118 ddi.dinfo_nboards = dgnc_NumBoards; 119 sprintf(ddi.dinfo_version, "%s", DG_PART); 120 121 spin_unlock_irqrestore(&dgnc_global_lock, flags); 122 123 if (copy_to_user(uarg, &ddi, sizeof(ddi))) 124 return -EFAULT; 125 126 break; 127 } 128 129 case DIGI_GETBD: 130 { 131 int brd; 132 133 struct digi_info di; 134 135 if (copy_from_user(&brd, uarg, sizeof(int))) 136 return -EFAULT; 137 138 if (brd < 0 || brd >= dgnc_NumBoards) 139 return -ENODEV; 140 141 memset(&di, 0, sizeof(di)); 142 143 di.info_bdnum = brd; 144 145 spin_lock_irqsave(&dgnc_Board[brd]->bd_lock, flags); 146 147 di.info_bdtype = dgnc_Board[brd]->dpatype; 148 di.info_bdstate = dgnc_Board[brd]->dpastatus; 149 di.info_ioport = 0; 150 di.info_physaddr = (ulong) dgnc_Board[brd]->membase; 151 di.info_physsize = (ulong) dgnc_Board[brd]->membase - dgnc_Board[brd]->membase_end; 152 if (dgnc_Board[brd]->state != BOARD_FAILED) 153 di.info_nports = dgnc_Board[brd]->nasync; 154 else 155 di.info_nports = 0; 156 157 spin_unlock_irqrestore(&dgnc_Board[brd]->bd_lock, flags); 158 159 if (copy_to_user(uarg, &di, sizeof(di))) 160 return -EFAULT; 161 162 break; 163 } 164 165 case DIGI_GET_NI_INFO: 166 { 167 struct channel_t *ch; 168 struct ni_info ni; 169 unsigned char mstat = 0; 170 uint board = 0; 171 uint channel = 0; 172 173 if (copy_from_user(&ni, uarg, sizeof(ni))) 174 return -EFAULT; 175 176 board = ni.board; 177 channel = ni.channel; 178 179 /* Verify boundaries on board */ 180 if (board >= dgnc_NumBoards) 181 return -ENODEV; 182 183 /* Verify boundaries on channel */ 184 if (channel >= dgnc_Board[board]->nasync) 185 return -ENODEV; 186 187 ch = dgnc_Board[board]->channels[channel]; 188 189 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC) 190 return -ENODEV; 191 192 memset(&ni, 0, sizeof(ni)); 193 ni.board = board; 194 ni.channel = channel; 195 196 spin_lock_irqsave(&ch->ch_lock, flags); 197 198 mstat = (ch->ch_mostat | ch->ch_mistat); 199 200 if (mstat & UART_MCR_DTR) { 201 ni.mstat |= TIOCM_DTR; 202 ni.dtr = TIOCM_DTR; 203 } 204 if (mstat & UART_MCR_RTS) { 205 ni.mstat |= TIOCM_RTS; 206 ni.rts = TIOCM_RTS; 207 } 208 if (mstat & UART_MSR_CTS) { 209 ni.mstat |= TIOCM_CTS; 210 ni.cts = TIOCM_CTS; 211 } 212 if (mstat & UART_MSR_RI) { 213 ni.mstat |= TIOCM_RI; 214 ni.ri = TIOCM_RI; 215 } 216 if (mstat & UART_MSR_DCD) { 217 ni.mstat |= TIOCM_CD; 218 ni.dcd = TIOCM_CD; 219 } 220 if (mstat & UART_MSR_DSR) 221 ni.mstat |= TIOCM_DSR; 222 223 ni.iflag = ch->ch_c_iflag; 224 ni.oflag = ch->ch_c_oflag; 225 ni.cflag = ch->ch_c_cflag; 226 ni.lflag = ch->ch_c_lflag; 227 228 if (ch->ch_digi.digi_flags & CTSPACE || 229 ch->ch_c_cflag & CRTSCTS) 230 ni.hflow = 1; 231 else 232 ni.hflow = 0; 233 234 if ((ch->ch_flags & CH_STOPI) || 235 (ch->ch_flags & CH_FORCED_STOPI)) 236 ni.recv_stopped = 1; 237 else 238 ni.recv_stopped = 0; 239 240 if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP)) 241 ni.xmit_stopped = 1; 242 else 243 ni.xmit_stopped = 0; 244 245 ni.curtx = ch->ch_txcount; 246 ni.currx = ch->ch_rxcount; 247 248 ni.baud = ch->ch_old_baud; 249 250 spin_unlock_irqrestore(&ch->ch_lock, flags); 251 252 if (copy_to_user(uarg, &ni, sizeof(ni))) 253 return -EFAULT; 254 255 break; 256 } 257 258 259 } 260 261 return 0; 262} 263