File: /usr/src/linux/drivers/isdn/sc/interrupt.c
1 /*
2 * $Id: interrupt.c,v 1.4.8.2 2001/04/08 17:51:43 kai Exp $
3 * Copyright (C) 1996 SpellCaster Telecommunications Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * For more information, please contact gpl-info@spellcast.com or write:
20 *
21 * SpellCaster Telecommunications Inc.
22 * 5621 Finch Avenue East, Unit #3
23 * Scarborough, Ontario Canada
24 * M1B 2T9
25 * +1 (416) 297-8565
26 * +1 (416) 297-6433 Facsimile
27 */
28
29 #define __NO_VERSION__
30 #include "includes.h"
31 #include "hardware.h"
32 #include "message.h"
33 #include "card.h"
34
35 extern int indicate_status(int, int, ulong, char *);
36 extern void check_phystat(unsigned long);
37 extern int receivemessage(int, RspMessage *);
38 extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
39 unsigned int, unsigned int, unsigned int, unsigned int *);
40 extern void rcvpkt(int, RspMessage *);
41
42 extern int cinst;
43 extern board *adapter[];
44
45 int get_card_from_irq(int irq)
46 {
47 int i;
48
49 for(i = 0 ; i < cinst ; i++) {
50 if(adapter[i]->interrupt == irq)
51 return i;
52 }
53 return -1;
54 }
55
56 /*
57 *
58 */
59 void interrupt_handler(int interrupt, void * cardptr, struct pt_regs *regs ) {
60
61 RspMessage rcvmsg;
62 int channel;
63 int card;
64
65 card = get_card_from_irq(interrupt);
66
67 if(!IS_VALID_CARD(card)) {
68 pr_debug("Invalid param: %d is not a valid card id\n", card);
69 return;
70 }
71
72 pr_debug("%s: Entered Interrupt handler\n", adapter[card]->devicename);
73
74 /*
75 * Pull all of the waiting messages off the response queue
76 */
77 while (!receivemessage(card, &rcvmsg)) {
78 /*
79 * Push the message to the adapter structure for
80 * send_and_receive to snoop
81 */
82 if(adapter[card]->want_async_messages)
83 memcpy(&(adapter[card]->async_msg), &rcvmsg, sizeof(RspMessage));
84
85 channel = (unsigned int) rcvmsg.phy_link_no;
86
87 /*
88 * Trap Invalid request messages
89 */
90 if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) {
91 pr_debug("%s: Invalid request Message, rsp_status = %d\n",
92 adapter[card]->devicename, rcvmsg.rsp_status);
93 break;
94 }
95
96 /*
97 * Check for a linkRead message
98 */
99 if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
100 {
101 pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
102 adapter[card]->devicename,
103 rcvmsg.msg_data.response.msg_len,
104 rcvmsg.msg_data.response.buff_offset);
105 rcvpkt(card, &rcvmsg);
106 continue;
107
108 }
109
110 /*
111 * Handle a write acknoledgement
112 */
113 if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) {
114 pr_debug("%s: Packet Send ACK on channel %d\n", adapter[card]->devicename,
115 rcvmsg.phy_link_no);
116 adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++;
117 continue;
118 }
119
120 /*
121 * Handle a connection message
122 */
123 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect))
124 {
125 unsigned int callid;
126 setup_parm setup;
127 pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n",
128 adapter[card]->devicename,
129 rcvmsg.phy_link_no,
130 rcvmsg.rsp_status,
131 rcvmsg.msg_data.byte_array[2]);
132
133 memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int));
134 if(callid>=0x8000 && callid<=0xFFFF)
135 {
136 pr_debug("%s: Got Dial-Out Rsp\n", adapter[card]->devicename);
137 indicate_status(card, ISDN_STAT_DCONN,
138 (unsigned long)rcvmsg.phy_link_no-1,NULL);
139
140 }
141 else if(callid>=0x0000 && callid<=0x7FFF)
142 {
143 pr_debug("%s: Got Incoming Call\n", adapter[card]->devicename);
144 strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
145 strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
146 setup.si1 = 7;
147 setup.si2 = 0;
148 setup.plan = 0;
149 setup.screen = 0;
150
151 indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup);
152 indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL);
153 }
154 continue;
155 }
156
157 /*
158 * Handle a disconnection message
159 */
160 if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect))
161 {
162 pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n",
163 adapter[card]->devicename,
164 rcvmsg.phy_link_no,
165 rcvmsg.rsp_status,
166 rcvmsg.msg_data.byte_array[2]);
167
168 indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
169 indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL);
170 continue;
171
172 }
173
174 /*
175 * Handle a startProc engine up message
176 */
177 if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) {
178 pr_debug("%s: Received EngineUp message\n", adapter[card]->devicename);
179 adapter[card]->EngineUp = 1;
180 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL);
181 sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL);
182 init_timer(&adapter[card]->stat_timer);
183 adapter[card]->stat_timer.function = check_phystat;
184 adapter[card]->stat_timer.data = card;
185 adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
186 add_timer(&adapter[card]->stat_timer);
187 continue;
188 }
189
190 /*
191 * Start proc response
192 */
193 if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) {
194 pr_debug("%s: StartProc Response Status %d\n", adapter[card]->devicename,
195 rcvmsg.rsp_status);
196 continue;
197 }
198
199 /*
200 * Handle a GetMyNumber Rsp
201 */
202 if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){
203 strcpy(adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array);
204 continue;
205 }
206
207 /*
208 * PhyStatus response
209 */
210 if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) {
211 unsigned int b1stat, b2stat;
212
213 /*
214 * Covert the message data to the adapter->phystat code
215 */
216 b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0];
217 b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1];
218
219 adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */
220 pr_debug("%s: PhyStat is 0x%2x\n", adapter[card]->devicename,
221 adapter[card]->nphystat);
222 continue;
223 }
224
225
226 /*
227 * Handle a GetFramFormat
228 */
229 if(IS_CE_MESSAGE(rcvmsg, Call, 0, GetFrameFormat)) {
230 if(rcvmsg.msg_data.byte_array[0] != HDLC_PROTO) {
231 unsigned int proto = HDLC_PROTO;
232 /*
233 * Set board format to HDLC if it wasn't already
234 */
235 pr_debug("%s: current frame format: 0x%x, will change to HDLC\n",
236 adapter[card]->devicename,
237 rcvmsg.msg_data.byte_array[0]);
238 sendmessage(card, CEPID, ceReqTypeCall,
239 ceReqClass0,
240 ceReqCallSetFrameFormat,
241 (unsigned char) channel +1,
242 1,&proto);
243 }
244 continue;
245 }
246
247 /*
248 * Hmm...
249 */
250 pr_debug("%s: Received unhandled message (%d,%d,%d) link %d\n",
251 adapter[card]->devicename, rcvmsg.type, rcvmsg.class, rcvmsg.code,
252 rcvmsg.phy_link_no);
253
254 } /* while */
255
256 pr_debug("%s: Exiting Interrupt Handler\n", adapter[card]->devicename);
257 }
258