1/* $Id: message.c,v 1.5.8.2 2001/09/23 22:24:59 kai Exp $ 2 * 3 * functions for sending and receiving control messages 4 * 5 * Copyright (C) 1996 SpellCaster Telecommunications Inc. 6 * 7 * This software may be used and distributed according to the terms 8 * of the GNU General Public License, incorporated herein by reference. 9 * 10 * For more information, please contact gpl-info@spellcast.com or write: 11 * 12 * SpellCaster Telecommunications Inc. 13 * 5621 Finch Avenue East, Unit #3 14 * Scarborough, Ontario Canada 15 * M1B 2T9 16 * +1 (416) 297-8565 17 * +1 (416) 297-6433 Facsimile 18 */ 19#include <linux/sched.h> 20#include "includes.h" 21#include "hardware.h" 22#include "message.h" 23#include "card.h" 24 25/* 26 * receive a message from the board 27 */ 28int receivemessage(int card, RspMessage *rspmsg) 29{ 30 DualPortMemory *dpm; 31 unsigned long flags; 32 33 if (!IS_VALID_CARD(card)) { 34 pr_debug("Invalid param: %d is not a valid card id\n", card); 35 return -EINVAL; 36 } 37 38 pr_debug("%s: Entered receivemessage\n", 39 sc_adapter[card]->devicename); 40 41 /* 42 * See if there are messages waiting 43 */ 44 if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) { 45 /* 46 * Map in the DPM to the base page and copy the message 47 */ 48 spin_lock_irqsave(&sc_adapter[card]->lock, flags); 49 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80, 50 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]); 51 dpm = (DualPortMemory *) sc_adapter[card]->rambase; 52 memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), 53 MSG_LEN); 54 dpm->rsp_tail = (dpm->rsp_tail + 1) % MAX_MESSAGES; 55 inb(sc_adapter[card]->ioport[FIFO_READ]); 56 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); 57 /* 58 * Tell the board that the message is received 59 */ 60 pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d " 61 "cnt:%d (type,class,code):(%d,%d,%d) " 62 "link:%d stat:0x%x\n", 63 sc_adapter[card]->devicename, 64 rspmsg->sequence_no, 65 rspmsg->process_id, 66 rspmsg->time_stamp, 67 rspmsg->cmd_sequence_no, 68 rspmsg->msg_byte_cnt, 69 rspmsg->type, 70 rspmsg->class, 71 rspmsg->code, 72 rspmsg->phy_link_no, 73 rspmsg->rsp_status); 74 75 return 0; 76 } 77 return -ENOMSG; 78} 79 80/* 81 * send a message to the board 82 */ 83int sendmessage(int card, 84 unsigned int procid, 85 unsigned int type, 86 unsigned int class, 87 unsigned int code, 88 unsigned int link, 89 unsigned int data_len, 90 unsigned int *data) 91{ 92 DualPortMemory *dpm; 93 ReqMessage sndmsg; 94 unsigned long flags; 95 96 if (!IS_VALID_CARD(card)) { 97 pr_debug("Invalid param: %d is not a valid card id\n", card); 98 return -EINVAL; 99 } 100 101 /* 102 * Make sure we only send CEPID messages when the engine is up 103 * and CMPID messages when it is down 104 */ 105 if (sc_adapter[card]->EngineUp && procid == CMPID) { 106 pr_debug("%s: Attempt to send CM message with engine up\n", 107 sc_adapter[card]->devicename); 108 return -ESRCH; 109 } 110 111 if (!sc_adapter[card]->EngineUp && procid == CEPID) { 112 pr_debug("%s: Attempt to send CE message with engine down\n", 113 sc_adapter[card]->devicename); 114 return -ESRCH; 115 } 116 117 memset(&sndmsg, 0, MSG_LEN); 118 sndmsg.msg_byte_cnt = 4; 119 sndmsg.type = type; 120 sndmsg.class = class; 121 sndmsg.code = code; 122 sndmsg.phy_link_no = link; 123 124 if (data_len > 0) { 125 if (data_len > MSG_DATA_LEN) 126 data_len = MSG_DATA_LEN; 127 memcpy(&(sndmsg.msg_data), data, data_len); 128 sndmsg.msg_byte_cnt = data_len + 8; 129 } 130 131 sndmsg.process_id = procid; 132 sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256; 133 134 /* 135 * wait for an empty slot in the queue 136 */ 137 while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL)) 138 udelay(1); 139 140 /* 141 * Disable interrupts and map in shared memory 142 */ 143 spin_lock_irqsave(&sc_adapter[card]->lock, flags); 144 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80, 145 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]); 146 dpm = (DualPortMemory *) sc_adapter[card]->rambase; /* Fix me */ 147 memcpy_toio(&(dpm->req_queue[dpm->req_head]), &sndmsg, MSG_LEN); 148 dpm->req_head = (dpm->req_head + 1) % MAX_MESSAGES; 149 outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]); 150 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags); 151 152 pr_debug("%s: Sent Message seq:%d pid:%d time:%d " 153 "cnt:%d (type,class,code):(%d,%d,%d) " 154 "link:%d\n ", 155 sc_adapter[card]->devicename, 156 sndmsg.sequence_no, 157 sndmsg.process_id, 158 sndmsg.time_stamp, 159 sndmsg.msg_byte_cnt, 160 sndmsg.type, 161 sndmsg.class, 162 sndmsg.code, 163 sndmsg.phy_link_no); 164 165 return 0; 166} 167 168int send_and_receive(int card, 169 unsigned int procid, 170 unsigned char type, 171 unsigned char class, 172 unsigned char code, 173 unsigned char link, 174 unsigned char data_len, 175 unsigned char *data, 176 RspMessage *mesgdata, 177 int timeout) 178{ 179 int retval; 180 int tries; 181 182 if (!IS_VALID_CARD(card)) { 183 pr_debug("Invalid param: %d is not a valid card id\n", card); 184 return -EINVAL; 185 } 186 187 sc_adapter[card]->want_async_messages = 1; 188 retval = sendmessage(card, procid, type, class, code, link, 189 data_len, (unsigned int *) data); 190 191 if (retval) { 192 pr_debug("%s: SendMessage failed in SAR\n", 193 sc_adapter[card]->devicename); 194 sc_adapter[card]->want_async_messages = 0; 195 return -EIO; 196 } 197 198 tries = 0; 199 /* wait for the response */ 200 while (tries < timeout) { 201 schedule_timeout_interruptible(1); 202 203 pr_debug("SAR waiting..\n"); 204 205 /* 206 * See if we got our message back 207 */ 208 if ((sc_adapter[card]->async_msg.type == type) && 209 (sc_adapter[card]->async_msg.class == class) && 210 (sc_adapter[card]->async_msg.code == code) && 211 (sc_adapter[card]->async_msg.phy_link_no == link)) { 212 213 /* 214 * Got it! 215 */ 216 pr_debug("%s: Got ASYNC message\n", 217 sc_adapter[card]->devicename); 218 memcpy(mesgdata, &(sc_adapter[card]->async_msg), 219 sizeof(RspMessage)); 220 sc_adapter[card]->want_async_messages = 0; 221 return 0; 222 } 223 224 tries++; 225 } 226 227 pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename); 228 sc_adapter[card]->want_async_messages = 0; 229 return -ETIME; 230} 231