/* $Id: message.c,v 1.5.8.2 2001/09/23 22:24:59 kai Exp $ * * functions for sending and receiving control messages * * 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. * * For more information, please contact gpl-info@spellcast.com or write: * * SpellCaster Telecommunications Inc. * 5621 Finch Avenue East, Unit #3 * Scarborough, Ontario Canada * M1B 2T9 * +1 (416) 297-8565 * +1 (416) 297-6433 Facsimile */ #include <linux/sched.h> #include "includes.h" #include "hardware.h" #include "message.h" #include "card.h" /* * receive a message from the board */ int receivemessage(int card, RspMessage *rspmsg) { DualPortMemory *dpm; unsigned long flags; if (!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); return -EINVAL; } pr_debug("%s: Entered receivemessage\n", sc_adapter[card]->devicename); /* * See if there are messages waiting */ if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) { /* * Map in the DPM to the base page and copy the message */ spin_lock_irqsave(&sc_adapter[card]->lock, flags); outb((sc_adapter[card]->shmem_magic >> 14) | 0x80, sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]); dpm = (DualPortMemory *) sc_adapter[card]->rambase; memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN); dpm->rsp_tail = (dpm->rsp_tail + 1) % MAX_MESSAGES; inb(sc_adapter[card]->ioport[FIFO_READ]); spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); /* * Tell the board that the message is received */ pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d " "cnt:%d (type,class,code):(%d,%d,%d) " "link:%d stat:0x%x\n", sc_adapter[card]->devicename, rspmsg->sequence_no, rspmsg->process_id, rspmsg->time_stamp, rspmsg->cmd_sequence_no, rspmsg->msg_byte_cnt, rspmsg->type, rspmsg->class, rspmsg->code, rspmsg->phy_link_no, rspmsg->rsp_status); return 0; } return -ENOMSG; } /* * send a message to the board */ int sendmessage(int card, unsigned int procid, unsigned int type, unsigned int class, unsigned int code, unsigned int link, unsigned int data_len, unsigned int *data) { DualPortMemory *dpm; ReqMessage sndmsg; unsigned long flags; if (!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); return -EINVAL; } /* * Make sure we only send CEPID messages when the engine is up * and CMPID messages when it is down */ if (sc_adapter[card]->EngineUp && procid == CMPID) { pr_debug("%s: Attempt to send CM message with engine up\n", sc_adapter[card]->devicename); return -ESRCH; } if (!sc_adapter[card]->EngineUp && procid == CEPID) { pr_debug("%s: Attempt to send CE message with engine down\n", sc_adapter[card]->devicename); return -ESRCH; } memset(&sndmsg, 0, MSG_LEN); sndmsg.msg_byte_cnt = 4; sndmsg.type = type; sndmsg.class = class; sndmsg.code = code; sndmsg.phy_link_no = link; if (data_len > 0) { if (data_len > MSG_DATA_LEN) data_len = MSG_DATA_LEN; memcpy(&(sndmsg.msg_data), data, data_len); sndmsg.msg_byte_cnt = data_len + 8; } sndmsg.process_id = procid; sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256; /* * wait for an empty slot in the queue */ while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL)) udelay(1); /* * Disable interrupts and map in shared memory */ spin_lock_irqsave(&sc_adapter[card]->lock, flags); outb((sc_adapter[card]->shmem_magic >> 14) | 0x80, sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]); dpm = (DualPortMemory *) sc_adapter[card]->rambase; /* Fix me */ memcpy_toio(&(dpm->req_queue[dpm->req_head]), &sndmsg, MSG_LEN); dpm->req_head = (dpm->req_head + 1) % MAX_MESSAGES; outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]); spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); pr_debug("%s: Sent Message seq:%d pid:%d time:%d " "cnt:%d (type,class,code):(%d,%d,%d) " "link:%d\n ", sc_adapter[card]->devicename, sndmsg.sequence_no, sndmsg.process_id, sndmsg.time_stamp, sndmsg.msg_byte_cnt, sndmsg.type, sndmsg.class, sndmsg.code, sndmsg.phy_link_no); return 0; } int send_and_receive(int card, unsigned int procid, unsigned char type, unsigned char class, unsigned char code, unsigned char link, unsigned char data_len, unsigned char *data, RspMessage *mesgdata, int timeout) { int retval; int tries; if (!IS_VALID_CARD(card)) { pr_debug("Invalid param: %d is not a valid card id\n", card); return -EINVAL; } sc_adapter[card]->want_async_messages = 1; retval = sendmessage(card, procid, type, class, code, link, data_len, (unsigned int *) data); if (retval) { pr_debug("%s: SendMessage failed in SAR\n", sc_adapter[card]->devicename); sc_adapter[card]->want_async_messages = 0; return -EIO; } tries = 0; /* wait for the response */ while (tries < timeout) { schedule_timeout_interruptible(1); pr_debug("SAR waiting..\n"); /* * See if we got our message back */ if ((sc_adapter[card]->async_msg.type == type) && (sc_adapter[card]->async_msg.class == class) && (sc_adapter[card]->async_msg.code == code) && (sc_adapter[card]->async_msg.phy_link_no == link)) { /* * Got it! */ pr_debug("%s: Got ASYNC message\n", sc_adapter[card]->devicename); memcpy(mesgdata, &(sc_adapter[card]->async_msg), sizeof(RspMessage)); sc_adapter[card]->want_async_messages = 0; return 0; } tries++; } pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename); sc_adapter[card]->want_async_messages = 0; return -ETIME; }