Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[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 #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  */
28 int 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  */
83 int 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
168 int 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 }