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