Merge branch 'master'
[linux-2.6] / drivers / isdn / sc / message.c
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
20 #include "includes.h"
21 #include "hardware.h"
22 #include "message.h"
23 #include "card.h"
24
25 extern board *sc_adapter[];
26 extern unsigned int cinst;
27
28 /*
29  * Obligatory function prototypes
30  */
31 extern int indicate_status(int,ulong,char*);
32 extern int scm_command(isdn_ctrl *);
33
34
35 /*
36  * receive a message from the board
37  */
38 int receivemessage(int card, RspMessage *rspmsg) 
39 {
40         DualPortMemory *dpm;
41         unsigned long flags;
42
43         if (!IS_VALID_CARD(card)) {
44                 pr_debug("Invalid param: %d is not a valid card id\n", card);
45                 return -EINVAL;
46         }
47         
48         pr_debug("%s: Entered receivemessage\n",
49                         sc_adapter[card]->devicename);
50
51         /*
52          * See if there are messages waiting
53          */
54         if (inb(sc_adapter[card]->ioport[FIFO_STATUS]) & RF_HAS_DATA) {
55                 /*
56                  * Map in the DPM to the base page and copy the message
57                  */
58                 spin_lock_irqsave(&sc_adapter[card]->lock, flags);
59                 outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
60                         sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
61                 dpm = (DualPortMemory *) sc_adapter[card]->rambase;
62                 memcpy_fromio(rspmsg, &(dpm->rsp_queue[dpm->rsp_tail]), 
63                         MSG_LEN);
64                 dpm->rsp_tail = (dpm->rsp_tail+1) % MAX_MESSAGES;
65                 inb(sc_adapter[card]->ioport[FIFO_READ]);
66                 spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
67                 /*
68                  * Tell the board that the message is received
69                  */
70                 pr_debug("%s: Received Message seq:%d pid:%d time:%d cmd:%d "
71                                 "cnt:%d (type,class,code):(%d,%d,%d) "
72                                 "link:%d stat:0x%x\n",
73                                         sc_adapter[card]->devicename,
74                                         rspmsg->sequence_no,
75                                         rspmsg->process_id,
76                                         rspmsg->time_stamp,
77                                         rspmsg->cmd_sequence_no,
78                                         rspmsg->msg_byte_cnt,
79                                         rspmsg->type,
80                                         rspmsg->class,
81                                         rspmsg->code,
82                                         rspmsg->phy_link_no, 
83                                         rspmsg->rsp_status);
84
85                 return 0;
86         }
87         return -ENOMSG;
88 }
89         
90 /*
91  * send a message to the board
92  */
93 int sendmessage(int card,
94                 unsigned int procid,
95                 unsigned int type, 
96                 unsigned int class, 
97                 unsigned int code,
98                 unsigned int link, 
99                 unsigned int data_len, 
100                 unsigned int *data) 
101 {
102         DualPortMemory *dpm;
103         ReqMessage sndmsg;
104         unsigned long flags;
105
106         if (!IS_VALID_CARD(card)) {
107                 pr_debug("Invalid param: %d is not a valid card id\n", card);
108                 return -EINVAL;
109         }
110
111         /*
112          * Make sure we only send CEPID messages when the engine is up
113          * and CMPID messages when it is down
114          */
115         if(sc_adapter[card]->EngineUp && procid == CMPID) {
116                 pr_debug("%s: Attempt to send CM message with engine up\n",
117                         sc_adapter[card]->devicename);
118                 return -ESRCH;
119         }
120
121         if(!sc_adapter[card]->EngineUp && procid == CEPID) {
122                 pr_debug("%s: Attempt to send CE message with engine down\n",
123                         sc_adapter[card]->devicename);
124                 return -ESRCH;
125         }
126
127         memset(&sndmsg, 0, MSG_LEN);
128         sndmsg.msg_byte_cnt = 4;
129         sndmsg.type = type;
130         sndmsg.class = class;
131         sndmsg.code = code;
132         sndmsg.phy_link_no = link;
133
134         if (data_len > 0) {
135                 if (data_len > MSG_DATA_LEN)
136                         data_len = MSG_DATA_LEN;
137                 memcpy(&(sndmsg.msg_data), data, data_len);
138                 sndmsg.msg_byte_cnt = data_len + 8;
139         }
140
141         sndmsg.process_id = procid;
142         sndmsg.sequence_no = sc_adapter[card]->seq_no++ % 256;
143
144         /*
145          * wait for an empty slot in the queue
146          */
147         while (!(inb(sc_adapter[card]->ioport[FIFO_STATUS]) & WF_NOT_FULL))
148                 udelay(1);
149
150         /*
151          * Disable interrupts and map in shared memory
152          */
153         spin_lock_irqsave(&sc_adapter[card]->lock, flags);
154         outb((sc_adapter[card]->shmem_magic >> 14) | 0x80,
155                 sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
156         dpm = (DualPortMemory *) sc_adapter[card]->rambase;     /* Fix me */
157         memcpy_toio(&(dpm->req_queue[dpm->req_head]),&sndmsg,MSG_LEN);
158         dpm->req_head = (dpm->req_head+1) % MAX_MESSAGES;
159         outb(sndmsg.sequence_no, sc_adapter[card]->ioport[FIFO_WRITE]);
160         spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
161                 
162         pr_debug("%s: Sent Message seq:%d pid:%d time:%d "
163                         "cnt:%d (type,class,code):(%d,%d,%d) "
164                         "link:%d\n ",
165                                 sc_adapter[card]->devicename,
166                                 sndmsg.sequence_no,
167                                 sndmsg.process_id,
168                                 sndmsg.time_stamp,
169                                 sndmsg.msg_byte_cnt,
170                                 sndmsg.type,
171                                 sndmsg.class,
172                                 sndmsg.code,
173                                 sndmsg.phy_link_no); 
174                 
175         return 0;
176 }
177
178 int send_and_receive(int card,
179                 unsigned int procid, 
180                 unsigned char type,
181                 unsigned char class, 
182                 unsigned char code,
183                 unsigned char link,
184                 unsigned char data_len, 
185                 unsigned char *data, 
186                 RspMessage *mesgdata,
187                 int timeout) 
188 {
189         int retval;
190         int tries;
191
192         if (!IS_VALID_CARD(card)) {
193                 pr_debug("Invalid param: %d is not a valid card id\n", card);
194                 return -EINVAL;
195         }
196
197         sc_adapter[card]->want_async_messages = 1;
198         retval = sendmessage(card, procid, type, class, code, link, 
199                         data_len, (unsigned int *) data);
200   
201         if (retval) {
202                 pr_debug("%s: SendMessage failed in SAR\n",
203                         sc_adapter[card]->devicename);
204                 sc_adapter[card]->want_async_messages = 0;
205                 return -EIO;
206         }
207
208         tries = 0;
209         /* wait for the response */
210         while (tries < timeout) {
211                 schedule_timeout_interruptible(1);
212                 
213                 pr_debug("SAR waiting..\n");
214
215                 /*
216                  * See if we got our message back
217                  */
218                 if ((sc_adapter[card]->async_msg.type == type) &&
219                     (sc_adapter[card]->async_msg.class == class) &&
220                     (sc_adapter[card]->async_msg.code == code) &&
221                     (sc_adapter[card]->async_msg.phy_link_no == link)) {
222
223                         /*
224                          * Got it!
225                          */
226                         pr_debug("%s: Got ASYNC message\n",
227                                 sc_adapter[card]->devicename);
228                         memcpy(mesgdata, &(sc_adapter[card]->async_msg),
229                                 sizeof(RspMessage));
230                         sc_adapter[card]->want_async_messages = 0;
231                         return 0;
232                 }
233
234                 tries++;
235         }
236
237         pr_debug("%s: SAR message timeout\n", sc_adapter[card]->devicename);
238         sc_adapter[card]->want_async_messages = 0;
239         return -ETIME;
240 }