tpam_nco.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
- /* $Id: tpam_nco.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
- *
- * Turbo PAM ISDN driver for Linux.
- * (Kernel Driver - Low Level NCO Manipulation)
- *
- * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc魐e
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For all support questions please contact: <support@auvertech.fr>
- *
- */
- #include <linux/pci.h>
- #include <linux/sched.h>
- #include <linux/tqueue.h>
- #include <linux/interrupt.h>
- #include <asm/io.h>
- #include "tpam.h"
- /* Local function prototypes */
- static struct sk_buff *build_NCOpacket(u16, u16, u16, u16, u16);
- static int extract_NCOParameter(struct sk_buff *, u8, void *, u16);
- /*
- * Build a NCO packet (PCI message).
- *
- * messageID: the message type (ID_*)
- * size: size of the TLV block
- * data_size: size of the data block
- * ack: packet needs to send ack upon send
- * ack_size: size of data to be acknowledged upon send
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- static struct sk_buff *build_NCOpacket(u16 messageID, u16 size,
- u16 data_size, u16 ack,
- u16 ack_size) {
- struct sk_buff *skb;
- skb_header *h;
- pci_mpb *p;
- u16 finalsize;
- /* reserve enough space for the sk_buff header, the pci * header,
- * size bytes for the TLV block, size bytes for the data and 4 more
- * bytes in order to make sure we can write dwords to the board. */
- finalsize = sizeof(skb_header) + sizeof(pci_mpb) + size + data_size + 4;
- /* allocate the sk_buff */
- if (!(skb = alloc_skb(finalsize, GFP_ATOMIC))) {
- printk(KERN_ERR "TurboPAM(make_NCOpacket): alloc_skb failedn");
- return NULL;
- }
- /* construct the skb_header */
- h = (skb_header *)skb_put(skb, sizeof(skb_header));
- h->size = sizeof(pci_mpb) + size;
- h->data_size = data_size;
- h->ack = ack;
- h->ack_size = ack_size;
- /* construct the pci_mpb */
- p = (pci_mpb *)skb_put(skb, sizeof(pci_mpb));
- p->exID = 0;
- p->flags = 0;
- p->errorCode = 0;
- p->messageID = messageID;
- p->maximumBlockTLVSize = MPB_MAXIMUMBLOCKTLVSIZE;
- p->actualBlockTLVSize = size;
- p->maximumDataSize = MPB_MAXIMUMDATASIZE;
- p->actualDataSize = data_size;
- return skb;
- }
- /*
- * Build a ACreateNCOReq message.
- *
- * phone: the local phone number.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_ACreateNCOReq(const u8 *phone) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_ACreateNCOReq): phone=%sn", phone);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_ACreateNCOReq, 23 + strlen(phone), 0, 0, 0)))
- return NULL;
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 3);
- *tlv = PAR_NCOType;
- *(tlv+1) = 1;
- *(tlv+2) = 5; /* mistery value... */
- tlv = (u8 *)skb_put(skb, 4);
- *tlv = PAR_U3Protocol;
- *(tlv+1) = 2;
- *(tlv+2) = 4; /* no level 3 protocol */
- *(tlv+3) = 1; /* HDLC in level 2 */
- tlv = (u8 *)skb_put(skb, 3);
- *tlv = PAR_Cdirection;
- *(tlv+1) = 1;
- *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
- tlv = (u8 *)skb_put(skb, 3);
- *tlv = PAR_Udirection;
- *(tlv+1) = 1;
- *(tlv+2) = 3; /* PCI_DIRECTION_BOTH */
- tlv = (u8 *)skb_put(skb, 4);
- *tlv = PAR_BearerCap;
- *(tlv+1) = 2;
- *(tlv+2) = 0x88;
- *(tlv+3) = 0x90;
- tlv = (u8 *)skb_put(skb, 6 + strlen(phone));
- *tlv = PAR_CallingNumber;
- *(tlv+1) = strlen(phone) + 4;
- *(tlv+2) = 0x01; /* international */
- *(tlv+3) = 0x01; /* isdn */
- *(tlv+4) = 0x00;
- *(tlv+5) = 0x00;
- memcpy(tlv + 6, phone, strlen(phone));
- return skb;
- }
- /*
- * Build a ADestroyNCOReq message.
- *
- * ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_ADestroyNCOReq(u32 ncoid) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_ADestroyNCOReq): ncoid=%lun",
- (unsigned long)ncoid);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_ADestroyNCOReq, 6, 0, 0, 0)))
- return NULL;
-
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- return skb;
- }
- /*
- * Build a CConnectReq message.
- *
- * ncoid: the NCO id.
- * called: the destination phone number
- * hdlc: type of connection: 1 (HDLC) or 0(modem)
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_CConnectReq(u32 ncoid, const u8 *called, u8 hdlc) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_CConnectReq): ncoid=%lu, called=%s, hdlc=%dn",
- (unsigned long)ncoid, called, hdlc);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_CConnectReq, 20 + strlen(called), 0, 0, 0)))
- return NULL;
-
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- tlv = (u8 *)skb_put(skb, 4 + strlen(called));
- *tlv = PAR_CalledNumber;
- *(tlv+1) = strlen(called) + 2;
- *(tlv+2) = 0x01; /* international */
- *(tlv+3) = 0x01; /* isdn */
- memcpy(tlv + 4, called, strlen(called));
- tlv = (u8 *)skb_put(skb, 3);
- *tlv = PAR_BearerCap;
- *(tlv+1) = 1;
- *(tlv+2) = hdlc ? 0x88 /* HDLC */ : 0x80 /* MODEM */;
- tlv = (u8 *)skb_put(skb, 4);
- *tlv = PAR_HLC;
- *(tlv+1) = 2;
- *(tlv+2) = 0x2;
- *(tlv+3) = 0x7f;
- tlv = (u8 *)skb_put(skb, 3);
- *tlv = PAR_Facility;
- *(tlv+1) = 1;
- *(tlv+2) = 2;
- return skb;
- }
- /*
- * Build a CConnectRsp message.
- *
- * ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_CConnectRsp(u32 ncoid) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_CConnectRsp): ncoid=%lun",
- (unsigned long)ncoid);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_CConnectRsp, 6, 0, 0, 0)))
- return NULL;
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- return skb;
- }
- /*
- * Build a CDisconnectReq message.
- *
- * ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_CDisconnectReq(u32 ncoid) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_CDisconnectReq): ncoid=%lun",
- (unsigned long)ncoid);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_CDisconnectReq, 6, 0, 0, 0)))
- return NULL;
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- return skb;
- }
- /*
- * Build a CDisconnectRsp message.
- *
- * ncoid: the NCO id.
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_CDisconnectRsp(u32 ncoid) {
- struct sk_buff *skb;
- u8 *tlv;
- dprintk("TurboPAM(build_CDisconnectRsp): ncoid=%lun",
- (unsigned long)ncoid);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_CDisconnectRsp, 6, 0, 0, 0)))
- return NULL;
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- return skb;
- }
- /*
- * Build a U3DataReq message.
- *
- * ncoid: the NCO id.
- * data: the data to be send
- * len: length of the data
- * ack: send ack upon send
- * ack_size: size of data to be acknowledged upon send
- *
- * Return: the sk_buff filled with the NCO packet, or NULL if error.
- */
- struct sk_buff *build_U3DataReq(u32 ncoid, void *data, u16 len,
- u16 ack, u16 ack_size) {
- struct sk_buff *skb;
- u8 *tlv;
- void *p;
- dprintk("TurboPAM(build_U3DataReq): "
- "ncoid=%lu, len=%d, ack=%d, ack_size=%dn",
- (unsigned long)ncoid, len, ack, ack_size);
- /* build the NCO packet */
- if (!(skb = build_NCOpacket(ID_U3DataReq, 6, len, ack, ack_size)))
- return NULL;
- /* add the parameters */
- tlv = (u8 *)skb_put(skb, 6);
- *tlv = PAR_NCOID;
- *(tlv+1) = 4;
- *((u32 *)(tlv+2)) = ncoid;
- p = skb_put(skb, len);
- memcpy(p, data, len);
- return skb;
- }
- /*
- * Extract a parameter from a TLV block.
- *
- * skb: sk_buff containing the PCI message
- * type: parameter to search for (PARAM_*)
- * value: to be filled with the value of the parameter
- * len: maximum length of the parameter value
- *
- * Return: 0 if OK, <0 if error.
- */
- static int extract_NCOParameter(struct sk_buff *skb, u8 type,
- void *value, u16 len) {
- void *buffer = (void *)skb->data;
- pci_mpb *p;
- void * bufferend;
- u8 valtype;
- u16 vallen;
- /* calculate the start and end of the TLV block */
- buffer += sizeof(skb_header);
- p = (pci_mpb *)buffer;
- buffer += sizeof(pci_mpb);
- bufferend = buffer + p->actualBlockTLVSize;
- /* walk through the parameters */
- while (buffer < bufferend) {
- /* parameter type */
- valtype = *((u8 *)buffer++);
- /* parameter length */
- vallen = *((u8 *)buffer++);
- if (vallen == 0xff) {
- /* parameter length is on 2 bytes */
- vallen = *((u8 *)buffer++);
- vallen <<= 8;
- vallen |= *((u8 *)buffer++);
- }
- /* got the right parameter */
- if (valtype == type) {
- /* not enough space for returning the value */
- if (vallen > len)
- return -1;
- /* OK, return it */
- memcpy(value, buffer, vallen);
- return 0;
- }
- buffer += vallen;
- }
- return -1;
- }
- /*
- * Parse a ACreateNCOCnf message.
- *
- * skb: the sk_buff containing the message
- * status: to be filled with the status field value
- * ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_ACreateNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
- /* extract the status */
- if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
- printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
- "CompletionStatus not foundn");
- return -1;
- }
- if (*status) {
- dprintk("TurboPAM(parse_ACreateNCOCnf): status=%dn", *status);
- return 0;
- }
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_ACreateNCOCnf): "
- "NCOID not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_ACreateNCOCnf): ncoid=%lu, status=%dn",
- (unsigned long)*ncoid, *status);
- return 0;
- }
- /*
- * Parse a ADestroyNCOCnf message. Not used in the driver.
- *
- * skb: the sk_buff containing the message
- * status: to be filled with the status field value
- * ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_ADestroyNCOCnf(struct sk_buff *skb, u8 *status, u32 *ncoid) {
- /* extract the status */
- if (extract_NCOParameter(skb, PAR_CompletionStatus, status, 1)) {
- printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
- "CompletionStatus not foundn");
- return -1;
- }
- if (*status) {
- dprintk("TurboPAM(parse_ADestroyNCOCnf): status=%dn", *status);
- return 0;
- }
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_ADestroyNCOCnf): "
- "NCOID not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_ADestroyNCOCnf): ncoid=%lu, status=%dn",
- (unsigned long)*ncoid, *status);
- return 0;
- }
- /*
- * Parse a CConnectCnf message.
- *
- * skb: the sk_buff containing the message
- * ncoid: to be filled with the ncoid field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_CConnectCnf(struct sk_buff *skb, u32 *ncoid) {
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CConnectCnf): "
- "NCOID not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_CConnectCnf): ncoid=%lun",
- (unsigned long)*ncoid);
- return 0;
- }
- /*
- * Parse a CConnectInd message.
- *
- * skb: the sk_buff containing the message
- * ncoid: to be filled with the ncoid field value
- * hdlc: to be filled with 1 if the incoming connection is a HDLC one,
- * with 0 if the incoming connection is a modem one
- * calling: to be filled with the calling phone number value
- * called: to be filled with the called phone number value
- * plan: to be filled with the plan value
- * screen: to be filled with the screen value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_CConnectInd(struct sk_buff *skb, u32 *ncoid, u8 *hdlc,
- u8 *calling, u8 *called, u8 *plan, u8 *screen) {
- u8 phone[PHONE_MAXIMUMSIZE + 4];
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
- "NCOID not foundn");
- return -1;
- }
- /* extract the bearer capability field */
- if (extract_NCOParameter(skb, PAR_BearerCap, hdlc, 1)) {
- printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
- "BearerCap not foundn");
- return -1;
- }
- *hdlc = (*hdlc == 0x88) ? 1 : 0;
- /* extract the calling number / plan / screen */
- if (extract_NCOParameter(skb, PAR_CallingNumber, phone,
- PHONE_MAXIMUMSIZE + 4)) {
- printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
- "CallingNumber not foundn");
- return -1;
- }
- memcpy(calling, phone + 4, PHONE_MAXIMUMSIZE);
- *plan = phone[1];
- *screen = phone[3];
- /* extract the called number */
- if (extract_NCOParameter(skb, PAR_CalledNumber, phone,
- PHONE_MAXIMUMSIZE + 2)) {
- printk(KERN_ERR "TurboPAM(parse_CConnectInd): "
- "CalledNumber not foundn");
- return -1;
- }
- memcpy(called, phone + 2, PHONE_MAXIMUMSIZE);
- dprintk("TurboPAM(parse_CConnectInd): "
- "ncoid=%lu, hdlc=%d, plan=%d, scr=%d, calling=%s, called=%sn",
- (unsigned long)*ncoid, *hdlc, *plan, *screen, calling, called);
- return 0;
- }
- /*
- * Parse a CDisconnectCnf message.
- *
- * skb: the sk_buff containing the message
- * ncoid: to be filled with the ncoid field value
- * causetopuf: to be filled with the cause field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_CDisconnectCnf(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
- "NCOID not foundn");
- return -1;
- }
- /* extract the cause of disconnection */
- if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CDisconnectCnf): "
- "CauseToPUF not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_CDisconnectCnf): ncoid=%lu, causetopuf=%lun",
- (unsigned long)*ncoid, (unsigned long)*causetopuf);
- return 0;
- }
- /*
- * Parse a CDisconnectInd message.
- *
- * skb: the sk_buff containing the message
- * ncoid: to be filled with the ncoid field value
- * causetopuf: to be filled with the cause field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_CDisconnectInd(struct sk_buff *skb, u32 *ncoid, u32 *causetopuf) {
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
- "NCOID not foundn");
- return -1;
- }
- /* extract the cause of disconnection */
- if (extract_NCOParameter(skb, PAR_CauseToPUF, causetopuf, 4)) {
- printk(KERN_ERR "TurboPAM(parse_CDisconnectInd): "
- "CauseToPUF not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_CDisconnectInd): ncoid=%lu, causetopuf=%lun",
- (unsigned long)*ncoid, (unsigned long)*causetopuf);
- return 0;
- }
- /*
- * Parse a U3ReadyToReceiveInd message.
- *
- * skb: the sk_buff containing the message
- * ncoid: to be filled with the ncoid field value
- * ready: to be filled with the ready field value
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_U3ReadyToReceiveInd(struct sk_buff *skb, u32 *ncoid, u8 *ready) {
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4)) {
- printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
- "NCOID not foundn");
- return -1;
- }
- /* extract the ready flag */
- if (extract_NCOParameter(skb, PAR_ReadyFlag, ready, 1)) {
- printk(KERN_ERR "TurboPAM(parse_U3ReadyToReceiveInd): "
- "ReadyFlag not foundn");
- return -1;
- }
- dprintk("TurboPAM(parse_U3ReadyToReceiveInd): ncoid=%lu, ready=%dn",
- (unsigned long)*ncoid, *ready);
- return 0;
- }
- /*
- * Parse a U3DataInd message.
- *
- * skb: the sk_buff containing the message + data
- * ncoid: to be filled with the ncoid field value
- * data: to be filled with the data
- * ready: to be filled with the data length
- *
- * Return: 0 if OK, <0 if error.
- */
- int parse_U3DataInd(struct sk_buff *skb, u32 *ncoid, u8 **data, u16 *len) {
- pci_mpb *p;
- /* extract the ncoid */
- if (extract_NCOParameter(skb, PAR_NCOID, ncoid, 4) == -1) {
- printk(KERN_ERR "TurboPAM(parse_U3DataInd): NCOID not foundn");
- return -1;
- }
- /* get a pointer to the beginning of the data block and its length */
- p = (pci_mpb *)(skb->data + sizeof(skb_header));
- *len = p->actualDataSize;
- skb_pull(skb,
- sizeof(skb_header) + sizeof(pci_mpb) + p->actualBlockTLVSize);
- *data = skb->data;
- dprintk("TurboPAM(parse_U3DataInd): ncoid=%lu, datalen=%dn",
- (unsigned long)*ncoid, *len);
- return 0;
- }