linux/drivers/isdn/sc/command.c
<<
>>
Prefs
   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