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