1/* $Id: command.c,v 1.4.10.1 2001/09/23 22:24:59 kai Exp $ 2 * 3 * Copyright (C) 1996 SpellCaster Telecommunications Inc. 4 * 5 * This software may be used and distributed according to the terms 6 * of the GNU General Public License, incorporated herein by reference. 7 * 8 * For more information, please contact gpl-info@spellcast.com or write: 9 * 10 * SpellCaster Telecommunications Inc. 11 * 5621 Finch Avenue East, Unit #3 12 * Scarborough, Ontario Canada 13 * M1B 2T9 14 * +1 (416) 297-8565 15 * +1 (416) 297-6433 Facsimile 16 */ 17 18#include <linux/module.h> 19#include "includes.h" /* This must be first */ 20#include "hardware.h" 21#include "message.h" 22#include "card.h" 23#include "scioc.h" 24 25static int dial(int card, unsigned long channel, setup_parm setup); 26static int hangup(int card, unsigned long channel); 27static int answer(int card, unsigned long channel); 28static int clreaz(int card, unsigned long channel); 29static int seteaz(int card, unsigned long channel, char *); 30static int setl2(int card, unsigned long arg); 31static int setl3(int card, unsigned long arg); 32static int acceptb(int card, unsigned long channel); 33 34#ifdef DEBUG 35/* 36 * Translate command codes to strings 37 */ 38static char *commands[] = { "ISDN_CMD_IOCTL", 39 "ISDN_CMD_DIAL", 40 "ISDN_CMD_ACCEPTB", 41 "ISDN_CMD_ACCEPTB", 42 "ISDN_CMD_HANGUP", 43 "ISDN_CMD_CLREAZ", 44 "ISDN_CMD_SETEAZ", 45 NULL, 46 NULL, 47 NULL, 48 "ISDN_CMD_SETL2", 49 NULL, 50 "ISDN_CMD_SETL3", 51 NULL, 52 NULL, 53 NULL, 54 NULL, 55 NULL, }; 56 57/* 58 * Translates ISDN4Linux protocol codes to strings for debug messages 59 */ 60static char *l3protos[] = { "ISDN_PROTO_L3_TRANS" }; 61static char *l2protos[] = { "ISDN_PROTO_L2_X75I", 62 "ISDN_PROTO_L2_X75UI", 63 "ISDN_PROTO_L2_X75BUI", 64 "ISDN_PROTO_L2_HDLC", 65 "ISDN_PROTO_L2_TRANS" }; 66#endif 67 68int get_card_from_id(int driver) 69{ 70 int i; 71 72 for (i = 0; i < cinst; i++) { 73 if (sc_adapter[i]->driverId == driver) 74 return i; 75 } 76 return -ENODEV; 77} 78 79/* 80 * command 81 */ 82 83int command(isdn_ctrl *cmd) 84{ 85 int card; 86 87 card = get_card_from_id(cmd->driver); 88 if (!IS_VALID_CARD(card)) { 89 pr_debug("Invalid param: %d is not a valid card id\n", card); 90 return -ENODEV; 91 } 92 93 /* 94 * Dispatch the command 95 */ 96 switch (cmd->command) { 97 case ISDN_CMD_IOCTL: 98 { 99 unsigned long cmdptr; 100 scs_ioctl ioc; 101 102 memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long)); 103 if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr, 104 sizeof(scs_ioctl))) { 105 pr_debug("%s: Failed to verify user space 0x%lx\n", 106 sc_adapter[card]->devicename, cmdptr); 107 return -EFAULT; 108 } 109 return sc_ioctl(card, &ioc); 110 } 111 case ISDN_CMD_DIAL: 112 return dial(card, cmd->arg, cmd->parm.setup); 113 case ISDN_CMD_HANGUP: 114 return hangup(card, cmd->arg); 115 case ISDN_CMD_ACCEPTD: 116 return answer(card, cmd->arg); 117 case ISDN_CMD_ACCEPTB: 118 return acceptb(card, cmd->arg); 119 case ISDN_CMD_CLREAZ: 120 return clreaz(card, cmd->arg); 121 case ISDN_CMD_SETEAZ: 122 return seteaz(card, cmd->arg, cmd->parm.num); 123 case ISDN_CMD_SETL2: 124 return setl2(card, cmd->arg); 125 case ISDN_CMD_SETL3: 126 return setl3(card, cmd->arg); 127 default: 128 return -EINVAL; 129 } 130 return 0; 131} 132 133/* 134 * start the onboard firmware 135 */ 136int startproc(int card) 137{ 138 int status; 139 140 if (!IS_VALID_CARD(card)) { 141 pr_debug("Invalid param: %d is not a valid card id\n", card); 142 return -ENODEV; 143 } 144 145 /* 146 * send start msg 147 */ 148 status = sendmessage(card, CMPID, cmReqType2, 149 cmReqClass0, 150 cmReqStartProc, 151 0, 0, NULL); 152 pr_debug("%s: Sent startProc\n", sc_adapter[card]->devicename); 153 154 return status; 155} 156 157 158/* 159 * Dials the number passed in 160 */ 161static int dial(int card, unsigned long channel, setup_parm setup) 162{ 163 int status; 164 char Phone[48]; 165 166 if (!IS_VALID_CARD(card)) { 167 pr_debug("Invalid param: %d is not a valid card id\n", card); 168 return -ENODEV; 169 } 170 171 /*extract ISDN number to dial from eaz/msn string*/ 172 strcpy(Phone, setup.phone); 173 174 /*send the connection message*/ 175 status = sendmessage(card, CEPID, ceReqTypePhy, 176 ceReqClass1, 177 ceReqPhyConnect, 178 (unsigned char)channel + 1, 179 strlen(Phone), 180 (unsigned int *)Phone); 181 182 pr_debug("%s: Dialing %s on channel %lu\n", 183 sc_adapter[card]->devicename, Phone, channel + 1); 184 185 return status; 186} 187 188/* 189 * Answer an incoming call 190 */ 191static int answer(int card, unsigned long channel) 192{ 193 if (!IS_VALID_CARD(card)) { 194 pr_debug("Invalid param: %d is not a valid card id\n", card); 195 return -ENODEV; 196 } 197 198 if (setup_buffers(card, channel + 1)) { 199 hangup(card, channel + 1); 200 return -ENOBUFS; 201 } 202 203 indicate_status(card, ISDN_STAT_BCONN, channel, NULL); 204 pr_debug("%s: Answered incoming call on channel %lu\n", 205 sc_adapter[card]->devicename, channel + 1); 206 return 0; 207} 208 209/* 210 * Hangup up the call on specified channel 211 */ 212static int hangup(int card, unsigned long channel) 213{ 214 int status; 215 216 if (!IS_VALID_CARD(card)) { 217 pr_debug("Invalid param: %d is not a valid card id\n", card); 218 return -ENODEV; 219 } 220 221 status = sendmessage(card, CEPID, ceReqTypePhy, 222 ceReqClass1, 223 ceReqPhyDisconnect, 224 (unsigned char)channel + 1, 225 0, 226 NULL); 227 pr_debug("%s: Sent HANGUP message to channel %lu\n", 228 sc_adapter[card]->devicename, channel + 1); 229 return status; 230} 231 232/* 233 * Set the layer 2 protocol (X.25, HDLC, Raw) 234 */ 235static int setl2(int card, unsigned long arg) 236{ 237 int status = 0; 238 int protocol, channel; 239 240 if (!IS_VALID_CARD(card)) { 241 pr_debug("Invalid param: %d is not a valid card id\n", card); 242 return -ENODEV; 243 } 244 protocol = arg >> 8; 245 channel = arg & 0xff; 246 sc_adapter[card]->channel[channel].l2_proto = protocol; 247 248 /* 249 * check that the adapter is also set to the correct protocol 250 */ 251 pr_debug("%s: Sending GetFrameFormat for channel %d\n", 252 sc_adapter[card]->devicename, channel + 1); 253 status = sendmessage(card, CEPID, ceReqTypeCall, 254 ceReqClass0, 255 ceReqCallGetFrameFormat, 256 (unsigned char)channel + 1, 257 1, 258 (unsigned int *)protocol); 259 if (status) 260 return status; 261 return 0; 262} 263 264/* 265 * Set the layer 3 protocol 266 */ 267static int setl3(int card, unsigned long channel) 268{ 269 int protocol = channel >> 8; 270 271 if (!IS_VALID_CARD(card)) { 272 pr_debug("Invalid param: %d is not a valid card id\n", card); 273 return -ENODEV; 274 } 275 276 sc_adapter[card]->channel[channel].l3_proto = protocol; 277 return 0; 278} 279 280static int acceptb(int card, unsigned long channel) 281{ 282 if (!IS_VALID_CARD(card)) { 283 pr_debug("Invalid param: %d is not a valid card id\n", card); 284 return -ENODEV; 285 } 286 287 if (setup_buffers(card, channel + 1)) 288 { 289 hangup(card, channel + 1); 290 return -ENOBUFS; 291 } 292 293 pr_debug("%s: B-Channel connection accepted on channel %lu\n", 294 sc_adapter[card]->devicename, channel + 1); 295 indicate_status(card, ISDN_STAT_BCONN, channel, NULL); 296 return 0; 297} 298 299static int clreaz(int card, unsigned long arg) 300{ 301 if (!IS_VALID_CARD(card)) { 302 pr_debug("Invalid param: %d is not a valid card id\n", card); 303 return -ENODEV; 304 } 305 306 strcpy(sc_adapter[card]->channel[arg].eazlist, ""); 307 sc_adapter[card]->channel[arg].eazclear = 1; 308 pr_debug("%s: EAZ List cleared for channel %lu\n", 309 sc_adapter[card]->devicename, arg + 1); 310 return 0; 311} 312 313static int seteaz(int card, unsigned long arg, char *num) 314{ 315 if (!IS_VALID_CARD(card)) { 316 pr_debug("Invalid param: %d is not a valid card id\n", card); 317 return -ENODEV; 318 } 319 320 strcpy(sc_adapter[card]->channel[arg].eazlist, num); 321 sc_adapter[card]->channel[arg].eazclear = 0; 322 pr_debug("%s: EAZ list for channel %lu set to: %s\n", 323 sc_adapter[card]->devicename, arg + 1, 324 sc_adapter[card]->channel[arg].eazlist); 325 return 0; 326} 327 328int reset(int card) 329{ 330 unsigned long flags; 331 332 if (!IS_VALID_CARD(card)) { 333 pr_debug("Invalid param: %d is not a valid card id\n", card); 334 return -ENODEV; 335 } 336 337 indicate_status(card, ISDN_STAT_STOP, 0, NULL); 338 339 if (sc_adapter[card]->EngineUp) { 340 del_timer(&sc_adapter[card]->stat_timer); 341 } 342 343 sc_adapter[card]->EngineUp = 0; 344 345 spin_lock_irqsave(&sc_adapter[card]->lock, flags); 346 init_timer(&sc_adapter[card]->reset_timer); 347 sc_adapter[card]->reset_timer.function = sc_check_reset; 348 sc_adapter[card]->reset_timer.data = card; 349 sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME; 350 add_timer(&sc_adapter[card]->reset_timer); 351 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); 352 353 outb(0x1, sc_adapter[card]->ioport[SFT_RESET]); 354 355 pr_debug("%s: Adapter Reset\n", sc_adapter[card]->devicename); 356 return 0; 357} 358 359void flushreadfifo(int card) 360{ 361 while (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) 362 inb(sc_adapter[card]->ioport[FIFO_READ]); 363} 364