diff options
Diffstat (limited to 'drivers/isdn/sc/interrupt.c')
-rw-r--r-- | drivers/isdn/sc/interrupt.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c new file mode 100644 index 000000000000..e5e164aca7fa --- /dev/null +++ b/drivers/isdn/sc/interrupt.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* $Id: interrupt.c,v 1.4.8.3 2001/09/23 22:24:59 kai Exp $ | ||
2 | * | ||
3 | * Copyright (C) 1996 SpellCaster Telecommunications Inc. | ||
4 | * | ||
5 | * This software may be used and distributed according to the terms | ||
6 | * of the GNU General Public License, incorporated herein by reference. | ||
7 | * | ||
8 | * For more information, please contact gpl-info@spellcast.com or write: | ||
9 | * | ||
10 | * SpellCaster Telecommunications Inc. | ||
11 | * 5621 Finch Avenue East, Unit #3 | ||
12 | * Scarborough, Ontario Canada | ||
13 | * M1B 2T9 | ||
14 | * +1 (416) 297-8565 | ||
15 | * +1 (416) 297-6433 Facsimile | ||
16 | */ | ||
17 | |||
18 | #include "includes.h" | ||
19 | #include "hardware.h" | ||
20 | #include "message.h" | ||
21 | #include "card.h" | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
24 | extern int indicate_status(int, int, ulong, char *); | ||
25 | extern void check_phystat(unsigned long); | ||
26 | extern int receivemessage(int, RspMessage *); | ||
27 | extern int sendmessage(int, unsigned int, unsigned int, unsigned int, | ||
28 | unsigned int, unsigned int, unsigned int, unsigned int *); | ||
29 | extern void rcvpkt(int, RspMessage *); | ||
30 | |||
31 | extern int cinst; | ||
32 | extern board *sc_adapter[]; | ||
33 | |||
34 | int get_card_from_irq(int irq) | ||
35 | { | ||
36 | int i; | ||
37 | |||
38 | for(i = 0 ; i < cinst ; i++) { | ||
39 | if(sc_adapter[i]->interrupt == irq) | ||
40 | return i; | ||
41 | } | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * | ||
47 | */ | ||
48 | irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs) | ||
49 | { | ||
50 | |||
51 | RspMessage rcvmsg; | ||
52 | int channel; | ||
53 | int card; | ||
54 | |||
55 | card = get_card_from_irq(interrupt); | ||
56 | |||
57 | if(!IS_VALID_CARD(card)) { | ||
58 | pr_debug("Invalid param: %d is not a valid card id\n", card); | ||
59 | return IRQ_NONE; | ||
60 | } | ||
61 | |||
62 | pr_debug("%s: Entered Interrupt handler\n", | ||
63 | sc_adapter[card]->devicename); | ||
64 | |||
65 | /* | ||
66 | * Pull all of the waiting messages off the response queue | ||
67 | */ | ||
68 | while (!receivemessage(card, &rcvmsg)) { | ||
69 | /* | ||
70 | * Push the message to the adapter structure for | ||
71 | * send_and_receive to snoop | ||
72 | */ | ||
73 | if(sc_adapter[card]->want_async_messages) | ||
74 | memcpy(&(sc_adapter[card]->async_msg), | ||
75 | &rcvmsg, sizeof(RspMessage)); | ||
76 | |||
77 | channel = (unsigned int) rcvmsg.phy_link_no; | ||
78 | |||
79 | /* | ||
80 | * Trap Invalid request messages | ||
81 | */ | ||
82 | if(IS_CM_MESSAGE(rcvmsg, 0, 0, Invalid)) { | ||
83 | pr_debug("%s: Invalid request Message, rsp_status = %d\n", | ||
84 | sc_adapter[card]->devicename, | ||
85 | rcvmsg.rsp_status); | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * Check for a linkRead message | ||
91 | */ | ||
92 | if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read)) | ||
93 | { | ||
94 | pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n", | ||
95 | sc_adapter[card]->devicename, | ||
96 | rcvmsg.msg_data.response.msg_len, | ||
97 | rcvmsg.msg_data.response.buff_offset); | ||
98 | rcvpkt(card, &rcvmsg); | ||
99 | continue; | ||
100 | |||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Handle a write acknoledgement | ||
105 | */ | ||
106 | if(IS_CE_MESSAGE(rcvmsg, Lnk, 1, Write)) { | ||
107 | pr_debug("%s: Packet Send ACK on channel %d\n", | ||
108 | sc_adapter[card]->devicename, | ||
109 | rcvmsg.phy_link_no); | ||
110 | sc_adapter[card]->channel[rcvmsg.phy_link_no-1].free_sendbufs++; | ||
111 | continue; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Handle a connection message | ||
116 | */ | ||
117 | if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Connect)) | ||
118 | { | ||
119 | unsigned int callid; | ||
120 | setup_parm setup; | ||
121 | pr_debug("%s: Connect message: line %d: status %d: cause 0x%x\n", | ||
122 | sc_adapter[card]->devicename, | ||
123 | rcvmsg.phy_link_no, | ||
124 | rcvmsg.rsp_status, | ||
125 | rcvmsg.msg_data.byte_array[2]); | ||
126 | |||
127 | memcpy(&callid,rcvmsg.msg_data.byte_array,sizeof(int)); | ||
128 | if(callid>=0x8000 && callid<=0xFFFF) | ||
129 | { | ||
130 | pr_debug("%s: Got Dial-Out Rsp\n", | ||
131 | sc_adapter[card]->devicename); | ||
132 | indicate_status(card, ISDN_STAT_DCONN, | ||
133 | (unsigned long)rcvmsg.phy_link_no-1,NULL); | ||
134 | |||
135 | } | ||
136 | else if(callid>=0x0000 && callid<=0x7FFF) | ||
137 | { | ||
138 | pr_debug("%s: Got Incoming Call\n", | ||
139 | sc_adapter[card]->devicename); | ||
140 | strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4])); | ||
141 | strcpy(setup.eazmsn, | ||
142 | sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn); | ||
143 | setup.si1 = 7; | ||
144 | setup.si2 = 0; | ||
145 | setup.plan = 0; | ||
146 | setup.screen = 0; | ||
147 | |||
148 | indicate_status(card, ISDN_STAT_ICALL,(unsigned long)rcvmsg.phy_link_no-1,(char *)&setup); | ||
149 | indicate_status(card, ISDN_STAT_DCONN,(unsigned long)rcvmsg.phy_link_no-1,NULL); | ||
150 | } | ||
151 | continue; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Handle a disconnection message | ||
156 | */ | ||
157 | if (IS_CE_MESSAGE(rcvmsg, Phy, 1, Disconnect)) | ||
158 | { | ||
159 | pr_debug("%s: disconnect message: line %d: status %d: cause 0x%x\n", | ||
160 | sc_adapter[card]->devicename, | ||
161 | rcvmsg.phy_link_no, | ||
162 | rcvmsg.rsp_status, | ||
163 | rcvmsg.msg_data.byte_array[2]); | ||
164 | |||
165 | indicate_status(card, ISDN_STAT_BHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL); | ||
166 | indicate_status(card, ISDN_STAT_DHUP,(unsigned long)rcvmsg.phy_link_no-1,NULL); | ||
167 | continue; | ||
168 | |||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Handle a startProc engine up message | ||
173 | */ | ||
174 | if (IS_CM_MESSAGE(rcvmsg, 5, 0, MiscEngineUp)) { | ||
175 | pr_debug("%s: Received EngineUp message\n", | ||
176 | sc_adapter[card]->devicename); | ||
177 | sc_adapter[card]->EngineUp = 1; | ||
178 | sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,1,0,NULL); | ||
179 | sendmessage(card, CEPID,ceReqTypeCall,ceReqClass0,ceReqCallGetMyNumber,2,0,NULL); | ||
180 | init_timer(&sc_adapter[card]->stat_timer); | ||
181 | sc_adapter[card]->stat_timer.function = check_phystat; | ||
182 | sc_adapter[card]->stat_timer.data = card; | ||
183 | sc_adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME; | ||
184 | add_timer(&sc_adapter[card]->stat_timer); | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Start proc response | ||
190 | */ | ||
191 | if (IS_CM_MESSAGE(rcvmsg, 2, 0, StartProc)) { | ||
192 | pr_debug("%s: StartProc Response Status %d\n", | ||
193 | sc_adapter[card]->devicename, | ||
194 | rcvmsg.rsp_status); | ||
195 | continue; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Handle a GetMyNumber Rsp | ||
200 | */ | ||
201 | if (IS_CE_MESSAGE(rcvmsg,Call,0,GetMyNumber)){ | ||
202 | strcpy(sc_adapter[card]->channel[rcvmsg.phy_link_no-1].dn,rcvmsg.msg_data.byte_array); | ||
203 | continue; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * PhyStatus response | ||
208 | */ | ||
209 | if(IS_CE_MESSAGE(rcvmsg, Phy, 2, Status)) { | ||
210 | unsigned int b1stat, b2stat; | ||
211 | |||
212 | /* | ||
213 | * Covert the message data to the adapter->phystat code | ||
214 | */ | ||
215 | b1stat = (unsigned int) rcvmsg.msg_data.byte_array[0]; | ||
216 | b2stat = (unsigned int) rcvmsg.msg_data.byte_array[1]; | ||
217 | |||
218 | sc_adapter[card]->nphystat = (b2stat >> 8) | b1stat; /* endian?? */ | ||
219 | pr_debug("%s: PhyStat is 0x%2x\n", | ||
220 | sc_adapter[card]->devicename, | ||
221 | sc_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 | sc_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 | sc_adapter[card]->devicename, | ||
252 | rcvmsg.type, rcvmsg.class, rcvmsg.code, | ||
253 | rcvmsg.phy_link_no); | ||
254 | |||
255 | } /* while */ | ||
256 | |||
257 | pr_debug("%s: Exiting Interrupt Handler\n", | ||
258 | sc_adapter[card]->devicename); | ||
259 | return IRQ_HANDLED; | ||
260 | } | ||