diff options
Diffstat (limited to 'drivers/isdn/sc/ioctl.c')
-rw-r--r-- | drivers/isdn/sc/ioctl.c | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c new file mode 100644 index 00000000..e63983aa --- /dev/null +++ b/drivers/isdn/sc/ioctl.c @@ -0,0 +1,582 @@ +/* + * Copyright (C) 1996 SpellCaster Telecommunications Inc. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + */ + +#include "includes.h" +#include "hardware.h" +#include "message.h" +#include "card.h" +#include "scioc.h" + +static int GetStatus(int card, boardInfo *); + +/* + * Process private IOCTL messages (typically from scctrl) + */ +int sc_ioctl(int card, scs_ioctl *data) +{ + int status; + RspMessage *rcvmsg; + char *spid; + char *dn; + char switchtype; + char speed; + + rcvmsg = kmalloc(sizeof(RspMessage), GFP_KERNEL); + if (!rcvmsg) + return -ENOMEM; + + switch (data->command) { + case SCIOCRESET: /* Perform a hard reset of the adapter */ + { + pr_debug("%s: SCIOCRESET: ioctl received\n", + sc_adapter[card]->devicename); + sc_adapter[card]->StartOnReset = 0; + kfree(rcvmsg); + return reset(card); + } + + case SCIOCLOAD: + { + char *srec; + + srec = kmalloc(SCIOC_SRECSIZE, GFP_KERNEL); + if (!srec) { + kfree(rcvmsg); + return -ENOMEM; + } + pr_debug("%s: SCIOLOAD: ioctl received\n", + sc_adapter[card]->devicename); + if (sc_adapter[card]->EngineUp) { + pr_debug("%s: SCIOCLOAD: command failed, LoadProc while engine running.\n", + sc_adapter[card]->devicename); + kfree(rcvmsg); + kfree(srec); + return -1; + } + + /* + * Get the SRec from user space + */ + if (copy_from_user(srec, data->dataptr, SCIOC_SRECSIZE)) { + kfree(rcvmsg); + kfree(srec); + return -EFAULT; + } + + status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc, + 0, SCIOC_SRECSIZE, srec, rcvmsg, SAR_TIMEOUT); + kfree(rcvmsg); + kfree(srec); + + if (status) { + pr_debug("%s: SCIOCLOAD: command failed, status = %d\n", + sc_adapter[card]->devicename, status); + return -1; + } + else { + pr_debug("%s: SCIOCLOAD: command successful\n", + sc_adapter[card]->devicename); + return 0; + } + } + + case SCIOCSTART: + { + kfree(rcvmsg); + pr_debug("%s: SCIOSTART: ioctl received\n", + sc_adapter[card]->devicename); + if (sc_adapter[card]->EngineUp) { + pr_debug("%s: SCIOCSTART: command failed, engine already running.\n", + sc_adapter[card]->devicename); + return -1; + } + + sc_adapter[card]->StartOnReset = 1; + startproc(card); + return 0; + } + + case SCIOCSETSWITCH: + { + pr_debug("%s: SCIOSETSWITCH: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the switch type from user space + */ + if (copy_from_user(&switchtype, data->dataptr, sizeof(char))) { + kfree(rcvmsg); + return -EFAULT; + } + + pr_debug("%s: SCIOCSETSWITCH: setting switch type to %d\n", + sc_adapter[card]->devicename, + switchtype); + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallSetSwitchType, + 0, sizeof(char), &switchtype, rcvmsg, SAR_TIMEOUT); + if (!status && !(rcvmsg->rsp_status)) { + pr_debug("%s: SCIOCSETSWITCH: command successful\n", + sc_adapter[card]->devicename); + kfree(rcvmsg); + return 0; + } + else { + pr_debug("%s: SCIOCSETSWITCH: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + return status; + } + } + + case SCIOCGETSWITCH: + { + pr_debug("%s: SCIOGETSWITCH: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the switch type from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetSwitchType, 0, 0, NULL, rcvmsg, SAR_TIMEOUT); + if (!status && !(rcvmsg->rsp_status)) { + pr_debug("%s: SCIOCGETSWITCH: command successful\n", + sc_adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETSWITCH: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + return status; + } + + switchtype = rcvmsg->msg_data.byte_array[0]; + + /* + * Package the switch type and send to user space + */ + if (copy_to_user(data->dataptr, &switchtype, + sizeof(char))) { + kfree(rcvmsg); + return -EFAULT; + } + + kfree(rcvmsg); + return 0; + } + + case SCIOCGETSPID: + { + pr_debug("%s: SCIOGETSPID: ioctl received\n", + sc_adapter[card]->devicename); + + spid = kzalloc(SCIOC_SPIDSIZE, GFP_KERNEL); + if (!spid) { + kfree(rcvmsg); + return -ENOMEM; + } + /* + * Get the spid from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetSPID, + data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); + if (!status) { + pr_debug("%s: SCIOCGETSPID: command successful\n", + sc_adapter[card]->devicename); + } else { + pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(spid); + kfree(rcvmsg); + return status; + } + strlcpy(spid, rcvmsg->msg_data.byte_array, SCIOC_SPIDSIZE); + + /* + * Package the switch type and send to user space + */ + if (copy_to_user(data->dataptr, spid, SCIOC_SPIDSIZE)) { + kfree(spid); + kfree(rcvmsg); + return -EFAULT; + } + + kfree(spid); + kfree(rcvmsg); + return 0; + } + + case SCIOCSETSPID: + { + pr_debug("%s: DCBIOSETSPID: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the spid from user space + */ + spid = memdup_user(data->dataptr, SCIOC_SPIDSIZE); + if (IS_ERR(spid)) { + kfree(rcvmsg); + return PTR_ERR(spid); + } + + pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n", + sc_adapter[card]->devicename, data->channel, spid); + status = send_and_receive(card, CEPID, ceReqTypeCall, + ceReqClass0, ceReqCallSetSPID, data->channel, + strlen(spid), spid, rcvmsg, SAR_TIMEOUT); + if (!status && !(rcvmsg->rsp_status)) { + pr_debug("%s: SCIOCSETSPID: command successful\n", + sc_adapter[card]->devicename); + kfree(rcvmsg); + kfree(spid); + return 0; + } + else { + pr_debug("%s: SCIOCSETSPID: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + kfree(spid); + return status; + } + } + + case SCIOCGETDN: + { + pr_debug("%s: SCIOGETDN: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the dn from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, ceReqCallGetMyNumber, + data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); + if (!status) { + pr_debug("%s: SCIOCGETDN: command successful\n", + sc_adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETDN: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + return status; + } + + dn = kzalloc(SCIOC_DNSIZE, GFP_KERNEL); + if (!dn) { + kfree(rcvmsg); + return -ENOMEM; + } + strlcpy(dn, rcvmsg->msg_data.byte_array, SCIOC_DNSIZE); + kfree(rcvmsg); + + /* + * Package the dn and send to user space + */ + if (copy_to_user(data->dataptr, dn, SCIOC_DNSIZE)) { + kfree(dn); + return -EFAULT; + } + kfree(dn); + return 0; + } + + case SCIOCSETDN: + { + pr_debug("%s: SCIOSETDN: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the spid from user space + */ + dn = memdup_user(data->dataptr, SCIOC_DNSIZE); + if (IS_ERR(dn)) { + kfree(rcvmsg); + return PTR_ERR(dn); + } + + pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n", + sc_adapter[card]->devicename, data->channel, dn); + status = send_and_receive(card, CEPID, ceReqTypeCall, + ceReqClass0, ceReqCallSetMyNumber, data->channel, + strlen(dn), dn, rcvmsg, SAR_TIMEOUT); + if (!status && !(rcvmsg->rsp_status)) { + pr_debug("%s: SCIOCSETDN: command successful\n", + sc_adapter[card]->devicename); + kfree(rcvmsg); + kfree(dn); + return 0; + } + else { + pr_debug("%s: SCIOCSETDN: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + kfree(dn); + return status; + } + } + + case SCIOCTRACE: + + pr_debug("%s: SCIOTRACE: ioctl received\n", + sc_adapter[card]->devicename); +/* sc_adapter[card]->trace = !sc_adapter[card]->trace; + pr_debug("%s: SCIOCTRACE: tracing turned %s\n", + sc_adapter[card]->devicename, + sc_adapter[card]->trace ? "ON" : "OFF"); */ + break; + + case SCIOCSTAT: + { + boardInfo *bi; + + pr_debug("%s: SCIOSTAT: ioctl received\n", + sc_adapter[card]->devicename); + + bi = kzalloc(sizeof(boardInfo), GFP_KERNEL); + if (!bi) { + kfree(rcvmsg); + return -ENOMEM; + } + + kfree(rcvmsg); + GetStatus(card, bi); + + if (copy_to_user(data->dataptr, bi, sizeof(boardInfo))) { + kfree(bi); + return -EFAULT; + } + + kfree(bi); + return 0; + } + + case SCIOCGETSPEED: + { + pr_debug("%s: SCIOGETSPEED: ioctl received\n", + sc_adapter[card]->devicename); + + /* + * Get the speed from the board + */ + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetCallType, data->channel, 0, NULL, rcvmsg, SAR_TIMEOUT); + if (!status && !(rcvmsg->rsp_status)) { + pr_debug("%s: SCIOCGETSPEED: command successful\n", + sc_adapter[card]->devicename); + } + else { + pr_debug("%s: SCIOCGETSPEED: command failed (status = %d)\n", + sc_adapter[card]->devicename, status); + kfree(rcvmsg); + return status; + } + + speed = rcvmsg->msg_data.byte_array[0]; + + kfree(rcvmsg); + + /* + * Package the switch type and send to user space + */ + + if (copy_to_user(data->dataptr, &speed, sizeof(char))) + return -EFAULT; + + return 0; + } + + case SCIOCSETSPEED: + pr_debug("%s: SCIOCSETSPEED: ioctl received\n", + sc_adapter[card]->devicename); + break; + + case SCIOCLOOPTST: + pr_debug("%s: SCIOCLOOPTST: ioctl received\n", + sc_adapter[card]->devicename); + break; + + default: + kfree(rcvmsg); + return -1; + } + + kfree(rcvmsg); + return 0; +} + +static int GetStatus(int card, boardInfo *bi) +{ + RspMessage rcvmsg; + int i, status; + + /* + * Fill in some of the basic info about the board + */ + bi->modelid = sc_adapter[card]->model; + strcpy(bi->serial_no, sc_adapter[card]->hwconfig.serial_no); + strcpy(bi->part_no, sc_adapter[card]->hwconfig.part_no); + bi->iobase = sc_adapter[card]->iobase; + bi->rambase = sc_adapter[card]->rambase; + bi->irq = sc_adapter[card]->interrupt; + bi->ramsize = sc_adapter[card]->hwconfig.ram_size; + bi->interface = sc_adapter[card]->hwconfig.st_u_sense; + strcpy(bi->load_ver, sc_adapter[card]->load_ver); + strcpy(bi->proc_ver, sc_adapter[card]->proc_ver); + + /* + * Get the current PhyStats and LnkStats + */ + status = send_and_receive(card, CEPID, ceReqTypePhy, ceReqClass2, + ceReqPhyStatus, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + if (sc_adapter[card]->model < PRI_BOARD) { + bi->l1_status = rcvmsg.msg_data.byte_array[2]; + for (i = 0; i < BRI_CHANNELS; i++) + bi->status.bristats[i].phy_stat = + rcvmsg.msg_data.byte_array[i]; + } + else { + bi->l1_status = rcvmsg.msg_data.byte_array[0]; + bi->l2_status = rcvmsg.msg_data.byte_array[1]; + for (i = 0; i < PRI_CHANNELS; i++) + bi->status.pristats[i].phy_stat = + rcvmsg.msg_data.byte_array[i + 2]; + } + } + + /* + * Get the call types for each channel + */ + for (i = 0; i < sc_adapter[card]->nChannels; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetCallType, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + if (sc_adapter[card]->model == PRI_BOARD) { + bi->status.pristats[i].call_type = + rcvmsg.msg_data.byte_array[0]; + } + else { + bi->status.bristats[i].call_type = + rcvmsg.msg_data.byte_array[0]; + } + } + } + + /* + * If PRI, get the call states and service states for each channel + */ + if (sc_adapter[card]->model == PRI_BOARD) { + /* + * Get the call states + */ + status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2, + ceReqPhyChCallState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + for (i = 0; i < PRI_CHANNELS; i++) + bi->status.pristats[i].call_state = + rcvmsg.msg_data.byte_array[i]; + } + + /* + * Get the service states + */ + status = send_and_receive(card, CEPID, ceReqTypeStat, ceReqClass2, + ceReqPhyChServState, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + for (i = 0; i < PRI_CHANNELS; i++) + bi->status.pristats[i].serv_state = + rcvmsg.msg_data.byte_array[i]; + } + + /* + * Get the link stats for the channels + */ + for (i = 1; i <= PRI_CHANNELS; i++) { + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, i, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->status.pristats[i - 1].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->status.pristats[i - 1].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->status.pristats[i - 1].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->status.pristats[i - 1].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[12]; + } + } + + /* + * Link stats for the D channel + */ + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12]; + } + + return 0; + } + + /* + * If BRI or POTS, Get SPID, DN and call types for each channel + */ + + /* + * Get the link stats for the channels + */ + status = send_and_receive(card, CEPID, ceReqTypeLnk, ceReqClass0, + ceReqLnkGetStats, 0, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) { + bi->dch_stats.tx_good = (unsigned long)rcvmsg.msg_data.byte_array[0]; + bi->dch_stats.tx_bad = (unsigned long)rcvmsg.msg_data.byte_array[4]; + bi->dch_stats.rx_good = (unsigned long)rcvmsg.msg_data.byte_array[8]; + bi->dch_stats.rx_bad = (unsigned long)rcvmsg.msg_data.byte_array[12]; + bi->status.bristats[0].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[16]; + bi->status.bristats[0].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[20]; + bi->status.bristats[0].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[24]; + bi->status.bristats[0].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[28]; + bi->status.bristats[1].link_stats.tx_good = + (unsigned long)rcvmsg.msg_data.byte_array[32]; + bi->status.bristats[1].link_stats.tx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[36]; + bi->status.bristats[1].link_stats.rx_good = + (unsigned long)rcvmsg.msg_data.byte_array[40]; + bi->status.bristats[1].link_stats.rx_bad = + (unsigned long)rcvmsg.msg_data.byte_array[44]; + } + + /* + * Get the SPIDs + */ + for (i = 0; i < BRI_CHANNELS; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetSPID, i + 1, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) + strcpy(bi->status.bristats[i].spid, rcvmsg.msg_data.byte_array); + } + + /* + * Get the DNs + */ + for (i = 0; i < BRI_CHANNELS; i++) { + status = send_and_receive(card, CEPID, ceReqTypeCall, ceReqClass0, + ceReqCallGetMyNumber, i + 1, 0, NULL, &rcvmsg, SAR_TIMEOUT); + if (!status) + strcpy(bi->status.bristats[i].dn, rcvmsg.msg_data.byte_array); + } + + return 0; +} |