diff options
Diffstat (limited to 'drivers/isdn/sc/ioctl.c')
-rw-r--r-- | drivers/isdn/sc/ioctl.c | 601 |
1 files changed, 601 insertions, 0 deletions
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c new file mode 100644 index 00000000000..1371a990416 --- /dev/null +++ b/drivers/isdn/sc/ioctl.c @@ -0,0 +1,601 @@ +/* + * 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" + +extern int indicate_status(int, int, unsigned long, char *); +extern int startproc(int); +extern int loadproc(int, char *record); +extern int reset(int); +extern int send_and_receive(int, unsigned int, unsigned char,unsigned char, + unsigned char,unsigned char, + unsigned char, unsigned char *, RspMessage *, int); + +extern board *sc_adapter[]; + + +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; + 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, sizeof(srec))) { + kfree(rcvmsg); + kfree(srec); + return -EFAULT; + } + + status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc, + 0, sizeof(srec), 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: + { + 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 = kmalloc(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(rcvmsg); + return status; + } + strcpy(spid, rcvmsg->msg_data.byte_array); + + /* + * 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); + + spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL); + if(!spid) { + kfree(rcvmsg); + return -ENOMEM; + } + + /* + * Get the spid from user space + */ + if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) { + kfree(rcvmsg); + return -EFAULT; + } + + 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 = kmalloc(SCIOC_DNSIZE, GFP_KERNEL); + if (!dn) { + kfree(rcvmsg); + return -ENOMEM; + } + strcpy(dn, rcvmsg->msg_data.byte_array); + 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); + + dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL); + if (!dn) { + kfree(rcvmsg); + return -ENOMEM; + } + /* + * Get the spid from user space + */ + if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) { + kfree(rcvmsg); + kfree(dn); + return -EFAULT; + } + + 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 = kmalloc (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; +} + +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; +} |