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