1 /* $Id: tpam_commands.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
2 *
3 * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands)
4 *
5 * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc�ve
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 all support questions please contact: <support@auvertech.fr>
11 *
12 */
13
14 #include <linux/module.h>
15 #include <linux/pci.h>
16 #include <linux/sched.h>
17 #include <linux/tqueue.h>
18 #include <linux/interrupt.h>
19 #include <asm/io.h>
20
21 #include <linux/isdn/tpam.h>
22 #include "tpam.h"
23
24 /* Local functions prototypes */
25 static int tpam_command_ioctl_dspload(tpam_card *, u32);
26 static int tpam_command_ioctl_dspsave(tpam_card *, u32);
27 static int tpam_command_ioctl_dsprun(tpam_card *);
28 static int tpam_command_ioctl_loopmode(tpam_card *, u8);
29 static int tpam_command_dial(tpam_card *, u32, u8 *);
30 static int tpam_command_setl2(tpam_card *, u32, u8);
31 static int tpam_command_getl2(tpam_card *, u32);
32 static int tpam_command_acceptd(tpam_card *, u32);
33 static int tpam_command_acceptb(tpam_card *, u32);
34 static int tpam_command_hangup(tpam_card *, u32);
35 static int tpam_command_proceed(tpam_card *, u32);
36 static void tpam_statcallb_run(unsigned long);
37 static void tpam_statcallb(tpam_card *, isdn_ctrl);
38
39 /*
40 * Function called when the ISDN link level send a command to the driver.
41 *
42 * c: ISDN command.
43 *
44 * Return: 0 if OK, <0 on errors.
45 */
tpam_command(isdn_ctrl * c)46 int tpam_command(isdn_ctrl *c) {
47 tpam_card *card;
48 unsigned long argp;
49
50 dprintk("TurboPAM(tpam_command) card=%d, command=%d\n",
51 c->driver, c->command);
52
53 /* search for the board */
54 if (!(card = tpam_findcard(c->driver))) {
55 printk(KERN_ERR "TurboPAM(tpam_command): invalid driverId %d\n",
56 c->driver);
57 return -ENODEV;
58 }
59
60 /* dispatch the command */
61 switch (c->command) {
62 case ISDN_CMD_IOCTL:
63 argp = c->parm.userdata;
64 switch (c->arg) {
65 case TPAM_CMD_DSPLOAD:
66 return tpam_command_ioctl_dspload(card,
67 argp);
68 case TPAM_CMD_DSPSAVE:
69 return tpam_command_ioctl_dspsave(card,
70 argp);
71 case TPAM_CMD_DSPRUN:
72 return tpam_command_ioctl_dsprun(card);
73 case TPAM_CMD_LOOPMODEON:
74 return tpam_command_ioctl_loopmode(card,
75 1);
76 case TPAM_CMD_LOOPMODEOFF:
77 return tpam_command_ioctl_loopmode(card,
78 0);
79 default:
80 dprintk("TurboPAM(tpam_command): "
81 "invalid tpam ioctl %ld\n",
82 c->arg);
83 return -EINVAL;
84 }
85 case ISDN_CMD_DIAL:
86 return tpam_command_dial(card, c->arg,
87 c->parm.setup.phone);
88 case ISDN_CMD_ACCEPTD:
89 return tpam_command_acceptd(card, c->arg);
90 case ISDN_CMD_ACCEPTB:
91 return tpam_command_acceptb(card, c->arg);
92 case ISDN_CMD_HANGUP:
93 return tpam_command_hangup(card, c->arg);
94 case ISDN_CMD_SETL2:
95 return tpam_command_setl2(card, c->arg & 0xff,
96 c->arg >> 8);
97 case ISDN_CMD_GETL2:
98 return tpam_command_getl2(card, c->arg);
99 case ISDN_CMD_LOCK:
100 MOD_INC_USE_COUNT;
101 return 0;
102 case ISDN_CMD_UNLOCK:
103 MOD_DEC_USE_COUNT;
104 return 0;
105 case ISDN_CMD_PROCEED:
106 return tpam_command_proceed(card, c->arg);
107 default:
108 dprintk("TurboPAM(tpam_command): "
109 "unknown or unused isdn ioctl %d\n",
110 c->command);
111 return -EINVAL;
112 }
113
114 /* not reached */
115 return -EINVAL;
116 }
117
118 /*
119 * Load some data into the board's memory.
120 *
121 * card: the board
122 * arg: IOCTL argument containing the user space address of
123 * the tpam_dsp_ioctl structure describing the IOCTL.
124 *
125 * Return: 0 if OK, <0 on errors.
126 */
tpam_command_ioctl_dspload(tpam_card * card,u32 arg)127 static int tpam_command_ioctl_dspload(tpam_card *card, u32 arg) {
128 tpam_dsp_ioctl tdl;
129 int ret;
130
131 dprintk("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id);
132
133 /* get the IOCTL parameter from userspace */
134 if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl)))
135 return -EFAULT;
136
137 /* if the board's firmware was started, protect against writes
138 * to unallowed memory areas. If the board's firmware wasn't started,
139 * all is allowed. */
140 if (card->running && tpam_verify_area(tdl.address, tdl.data_len))
141 return -EPERM;
142
143 /* write the data in the board's memory */
144 ret = copy_from_user_to_pam(card, (void *)tdl.address,
145 (void *)arg + sizeof(tpam_dsp_ioctl),
146 tdl.data_len);
147 return 0;
148 }
149
150 /*
151 * Extract some data from the board's memory.
152 *
153 * card: the board
154 * arg: IOCTL argument containing the user space address of
155 * the tpam_dsp_ioctl structure describing the IOCTL.
156 *
157 * Return: 0 if OK, <0 on errors.
158 */
tpam_command_ioctl_dspsave(tpam_card * card,u32 arg)159 static int tpam_command_ioctl_dspsave(tpam_card *card, u32 arg) {
160 tpam_dsp_ioctl tdl;
161 int ret;
162
163 dprintk("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id);
164
165 /* get the IOCTL parameter from userspace */
166 if (copy_from_user(&tdl, (void *)arg, sizeof(tpam_dsp_ioctl)))
167 return -EFAULT;
168
169 /* protect against read from unallowed memory areas */
170 if (tpam_verify_area(tdl.address, tdl.data_len))
171 return -EPERM;
172
173 /* read the data from the board's memory */
174 ret = copy_from_pam_to_user(card, (void *)arg + sizeof(tpam_dsp_ioctl),
175 (void *)tdl.address, tdl.data_len);
176 return ret;
177 }
178
179 /*
180 * Launch the board's firmware. This function must be called after the
181 * firmware was loaded into the board's memory using TPAM_CMD_DSPLOAD
182 * IOCTL commands. After launching the firmware, this function creates
183 * the NCOs and waits for their creation.
184 *
185 * card: the board
186 *
187 * Return: 0 if OK, <0 on errors.
188 */
tpam_command_ioctl_dsprun(tpam_card * card)189 static int tpam_command_ioctl_dsprun(tpam_card *card) {
190 u32 signature = 0, timeout, i;
191 isdn_ctrl ctrl;
192 struct sk_buff *skb;
193
194 dprintk("TurboPAM(tpam_command_ioctl_dsprun): card=%d\n", card->id);
195
196 /* board must _not_ be running */
197 if (card->running)
198 return -EBUSY;
199
200 /* reset the board */
201 spin_lock_irq(&card->lock);
202 copy_to_pam_dword(card, (void *)TPAM_MAGICNUMBER_REGISTER, 0xdeadface);
203 readl(card->bar0 + TPAM_DSPINT_REGISTER);
204 readl(card->bar0 + TPAM_HINTACK_REGISTER);
205 spin_unlock_irq(&card->lock);
206
207 /* wait for the board signature */
208 timeout = jiffies + SIGNATURE_TIMEOUT;
209 while (time_before(jiffies, timeout)) {
210 spin_lock_irq(&card->lock);
211 signature = copy_from_pam_dword(card,
212 (void *)TPAM_MAGICNUMBER_REGISTER);
213 spin_unlock_irq(&card->lock);
214 if (signature == TPAM_MAGICNUMBER)
215 break;
216 set_current_state(TASK_UNINTERRUPTIBLE);
217 schedule_timeout(2);
218 }
219
220 /* signature not present -> board not started */
221 if (signature != TPAM_MAGICNUMBER) {
222 printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
223 "card=%d, signature 0x%lx, expected 0x%lx\n",
224 card->id, (unsigned long)signature,
225 (unsigned long)TPAM_MAGICNUMBER);
226 printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
227 "card=%d, firmware not started\n", card->id);
228 return -EIO;
229 }
230
231 /* the firmware is started */
232 printk(KERN_INFO "TurboPAM: card=%d, firmware started\n", card->id);
233
234 /* init the CRC routines */
235 init_CRC();
236
237 /* create all the NCOs */
238 for (i = 0; i < TPAM_NBCHANNEL; ++i)
239 if ((skb = build_ACreateNCOReq("")))
240 tpam_enqueue(card, skb);
241
242 /* wait for NCO creation confirmation */
243 timeout = jiffies + NCOCREATE_TIMEOUT;
244 while (time_before(jiffies, timeout)) {
245 if (card->channels_tested == TPAM_NBCHANNEL)
246 break;
247 set_current_state(TASK_UNINTERRUPTIBLE);
248 schedule_timeout(2);
249 }
250
251 card->running = 1;
252
253 if (card->channels_tested != TPAM_NBCHANNEL)
254 printk(KERN_ERR "TurboPAM(tpam_command_ioctl_dsprun): "
255 "card=%d, tried to init %d channels, "
256 "got reply from only %d channels\n", card->id,
257 TPAM_NBCHANNEL, card->channels_tested);
258
259 /* if all the channels were not initialized, signal to the ISDN
260 * link layer that fact that some channels are not usable */
261 if (card->channels_used != TPAM_NBCHANNEL)
262 for (i = card->channels_used; i < TPAM_NBCHANNEL; ++i) {
263 ctrl.driver = card->id;
264 ctrl.command = ISDN_STAT_DISCH;
265 ctrl.arg = i;
266 ctrl.parm.num[0] = 0;
267 (* card->interface.statcallb)(&ctrl);
268 }
269
270 printk(KERN_INFO "TurboPAM: card=%d, ready, %d channels available\n",
271 card->id, card->channels_used);
272
273 /* let's rock ! */
274 ctrl.driver = card->id;
275 ctrl.command = ISDN_STAT_RUN;
276 ctrl.arg = 0;
277 tpam_statcallb(card, ctrl);
278
279 return 0;
280 }
281
282 /*
283 * Set/reset the board's looptest mode.
284 *
285 * card: the board
286 * mode: if 1, sets the board's looptest mode, if 0 resets it.
287 *
288 * Return: 0 if OK, <0 if error.
289 */
tpam_command_ioctl_loopmode(tpam_card * card,u8 mode)290 static int tpam_command_ioctl_loopmode(tpam_card *card, u8 mode) {
291
292 /* board must be running */
293 if (!card->running)
294 return -ENODEV;
295
296 card->loopmode = mode;
297 return 0;
298 }
299
300 /*
301 * Issue a dial command. This function builds and sends a CConnectReq.
302 *
303 * card: the board
304 * channel: the channel number
305 * phone: the remote phone number (EAZ)
306 *
307 * Return: 0 if OK, <0 if error.
308 */
tpam_command_dial(tpam_card * card,u32 channel,u8 * phone)309 static int tpam_command_dial(tpam_card *card, u32 channel, u8 *phone) {
310 struct sk_buff *skb;
311 isdn_ctrl ctrl;
312
313 dprintk("TurboPAM(tpam_command_dial): card=%d, channel=%lu, phone=%s\n",
314 card->id, (unsigned long)channel, phone);
315
316 /* board must be running */
317 if (!card->running)
318 return -ENODEV;
319
320 /* initialize channel parameters */
321 card->channels[channel].realhdlc = card->channels[channel].hdlc;
322 card->channels[channel].hdlcshift = 0;
323 card->channels[channel].readytoreceive = 0;
324
325 /* build and send a CConnectReq */
326 skb = build_CConnectReq(card->channels[channel].ncoid, phone,
327 card->channels[channel].realhdlc);
328 if (!skb)
329 return -ENOMEM;
330 tpam_enqueue(card, skb);
331
332 /* making a connection in modem mode is slow and causes the ISDN
333 * link layer to hangup the connection before even it gets a chance
334 * to establish... All we can do is simulate a successful connection
335 * for now, and send a DHUP later if the connection fails */
336 if (!card->channels[channel].realhdlc) {
337 ctrl.driver = card->id;
338 ctrl.command = ISDN_STAT_DCONN;
339 ctrl.arg = channel;
340 tpam_statcallb(card, ctrl);
341 }
342
343 return 0;
344 }
345
346 /*
347 * Set the level2 protocol (modem or HDLC).
348 *
349 * card: the board
350 * channel: the channel number
351 * proto: the level2 protocol (one of ISDN_PROTO_L2*)
352 *
353 * Return: 0 if OK, <0 if error.
354 */
tpam_command_setl2(tpam_card * card,u32 channel,u8 proto)355 static int tpam_command_setl2(tpam_card *card, u32 channel, u8 proto) {
356
357 dprintk("TurboPAM(tpam_command_setl2): card=%d, channel=%lu, proto=%d\n",
358 card->id, (unsigned long)channel, proto);
359
360 /* board must be running */
361 if (!card->running)
362 return -ENODEV;
363
364 /* set the hdlc/modem mode */
365 switch (proto) {
366 case ISDN_PROTO_L2_HDLC:
367 card->channels[channel].hdlc = 1;
368 break;
369 case ISDN_PROTO_L2_MODEM:
370 card->channels[channel].hdlc = 0;
371 break;
372 default:
373 return -EINVAL;
374 }
375 return 0;
376 }
377
378 /*
379 * Return the level2 protocol (modem or HDLC).
380 *
381 * card: the board
382 * channel: the channel number
383 *
384 * Return: ISDN_PROTO_L2_HDLC/MODEM if OK, <0 if error.
385 */
tpam_command_getl2(tpam_card * card,u32 channel)386 static int tpam_command_getl2(tpam_card *card, u32 channel) {
387
388 dprintk("TurboPAM(tpam_command_getl2): card=%d, channel=%lu\n",
389 card->id, (unsigned long)channel);
390
391 /* board must be running */
392 if (!card->running)
393 return -ENODEV;
394
395 /* return the current mode */
396 if (card->channels[channel].realhdlc)
397 return ISDN_PROTO_L2_HDLC;
398 else
399 return ISDN_PROTO_L2_MODEM;
400 }
401
402 /*
403 * Accept a D-channel connection (incoming connection). This function
404 * builds and sends a CConnectRsp message and signals DCONN to the ISDN
405 * link level.
406 *
407 * card: the board
408 * channel: the channel number
409 *
410 * Return: 0 if OK, <0 if error.
411 */
tpam_command_acceptd(tpam_card * card,u32 channel)412 static int tpam_command_acceptd(tpam_card *card, u32 channel) {
413 isdn_ctrl ctrl;
414 struct sk_buff *skb;
415
416 dprintk("TurboPAM(tpam_command_acceptd): card=%d, channel=%lu\n",
417 card->id, (unsigned long)channel);
418
419 /* board must be running */
420 if (!card->running)
421 return -ENODEV;
422
423 /* build and send a CConnectRsp */
424 skb = build_CConnectRsp(card->channels[channel].ncoid);
425 if (!skb)
426 return -ENOMEM;
427 tpam_enqueue(card, skb);
428
429 /* issue DCONN to the ISDN link level */
430 ctrl.driver = card->id;
431 ctrl.command = ISDN_STAT_DCONN;
432 ctrl.arg = channel;
433 tpam_statcallb(card, ctrl);
434 return 0;
435 }
436
437 /*
438 * Accepts a B-channel connection. This is not used by the driver,
439 * since the TurboPAM is an active card hiding its B-channels from
440 * us. We just signal BCONN to the ISDN link layer.
441 *
442 * card: the board
443 * channel: the channel number
444 *
445 * Return: 0 if OK, <0 if error.
446 */
tpam_command_acceptb(tpam_card * card,u32 channel)447 static int tpam_command_acceptb(tpam_card *card, u32 channel) {
448 isdn_ctrl ctrl;
449
450 dprintk("TurboPAM(tpam_command_acceptb): card=%d, channel=%lu\n",
451 card->id, (unsigned long)channel);
452
453 /* board must be running */
454 if (!card->running)
455 return -ENODEV;
456
457 /* issue BCONN to the ISDN link level */
458 ctrl.driver = card->id;
459 ctrl.command = ISDN_STAT_BCONN;
460 ctrl.arg = channel;
461 ctrl.parm.num[0] = '\0';
462 tpam_statcallb(card, ctrl);
463 return 0;
464 }
465
466 /*
467 * Hang up a connection. This function builds and sends a CDisconnectReq.
468 *
469 * card: the board
470 * channel: the channel number.
471 *
472 * Return: 0 if OK, <0 if error.
473 */
tpam_command_hangup(tpam_card * card,u32 channel)474 static int tpam_command_hangup(tpam_card *card, u32 channel) {
475 struct sk_buff *skb;
476
477 dprintk("TurboPAM(tpam_command_hangup): card=%d, channel=%lu\n",
478 card->id, (unsigned long)channel);
479
480 /* board must be running */
481 if (!card->running)
482 return -ENODEV;
483
484 /* build and send a CDisconnectReq */
485 skb = build_CDisconnectReq(card->channels[channel].ncoid);
486 if (!skb)
487 return -ENOMEM;
488 tpam_enqueue(card, skb);
489 return 0;
490 }
491
492 /*
493 * Proceed with an incoming connection. This function builds and sends a
494 * CConnectRsp.
495 *
496 * card: the board
497 * channel: the channel number.
498 *
499 * Return: 0 if OK, <0 if error.
500 */
tpam_command_proceed(tpam_card * card,u32 channel)501 static int tpam_command_proceed(tpam_card *card, u32 channel) {
502 struct sk_buff *skb;
503
504 dprintk("TurboPAM(tpam_command_proceed): card=%d, channel=%lu\n",
505 card->id, (unsigned long)channel);
506
507 /* board must be running */
508 if (!card->running)
509 return -ENODEV;
510
511 /* build and send a CConnectRsp */
512 skb = build_CConnectRsp(card->channels[channel].ncoid);
513 if (!skb)
514 return -ENOMEM;
515 tpam_enqueue(card, skb);
516 return 0;
517 }
518
519 /*
520 * Send data through the board. This function encodes the data depending
521 * on the connection type (modem or HDLC), then builds and sends a U3DataReq.
522 *
523 * driverId: the driver id (really meaning here the board)
524 * channel: the channel number
525 * ack: data needs to be acknowledged upon send
526 * skb: sk_buff containing the data
527 *
528 * Return: size of data send if OK, <0 if error.
529 */
tpam_writebuf_skb(int driverId,int channel,int ack,struct sk_buff * skb)530 int tpam_writebuf_skb(int driverId, int channel, int ack, struct sk_buff *skb) {
531 tpam_card *card;
532 int orig_size = skb->len;
533 void *finaldata;
534 u32 finallen;
535
536 dprintk("TurboPAM(tpam_writebuf_skb): "
537 "card=%d, channel=%ld, ack=%d, data size=%d\n",
538 driverId, (unsigned long)channel, ack, skb->len);
539
540 /* find the board based on its driver ID */
541 if (!(card = tpam_findcard(driverId))) {
542 printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
543 "invalid driverId %d\n", driverId);
544 return -ENODEV;
545 }
546
547 /* board must be running */
548 if (!card->running)
549 return -ENODEV;
550
551 /* allocate some temporary memory */
552 if (!(finaldata = (void *)__get_free_page(GFP_ATOMIC))) {
553 printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
554 "get_free_page failed\n");
555 return -ENOMEM;
556 }
557
558 /* encode the data */
559 if (!card->channels[channel].realhdlc) {
560 /* modem mode */
561 hdlc_encode_modem(skb->data, skb->len, finaldata, &finallen);
562 }
563 else {
564 /* HDLC mode */
565 void *tempdata;
566 u32 templen;
567
568 if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) {
569 printk(KERN_ERR "TurboPAM(tpam_writebuf_skb): "
570 "get_free_page failed\n");
571 free_page((u32)finaldata);
572 return -ENOMEM;
573 }
574 hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen);
575 finallen = tpam_hdlc_encode(tempdata, finaldata,
576 &card->channels[channel].hdlcshift,
577 templen);
578 free_page((u32)tempdata);
579 }
580
581 /* free the old sk_buff */
582 kfree_skb(skb);
583
584 /* build and send a U3DataReq */
585 skb = build_U3DataReq(card->channels[channel].ncoid, finaldata,
586 finallen, ack, orig_size);
587 if (!skb) {
588 free_page((u32)finaldata);
589 return -ENOMEM;
590 }
591 tpam_enqueue_data(&card->channels[channel], skb);
592
593 /* free the temporary memory */
594 free_page((u32)finaldata);
595 return orig_size;
596 }
597
598 /*
599 * Treat a received ACreateNCOCnf message.
600 *
601 * card: the board
602 * skb: the received message
603 */
tpam_recv_ACreateNCOCnf(tpam_card * card,struct sk_buff * skb)604 void tpam_recv_ACreateNCOCnf(tpam_card *card, struct sk_buff *skb) {
605 u32 ncoid;
606 u8 status;
607 u32 channel;
608
609 dprintk("TurboPAM(tpam_recv_ACreateNCOCnf): card=%d\n", card->id);
610
611 /* parse the message contents */
612 if (parse_ACreateNCOCnf(skb, &status, &ncoid))
613 return;
614
615 /* if the card is alreay running, it means that this message
616 * arrives too late... */
617 if (card->running) {
618 printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
619 "ACreateNCOCnf received too late, status=%d\n", status);
620 return;
621 }
622
623 /* the NCO creation failed, the corresponding channel will
624 * be unused */
625 if (status) {
626 printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
627 "ACreateNCO failed, status=%d\n", status);
628 card->channels_tested++;
629 return;
630 }
631
632 /* find the first free channel and assign the nco ID to it */
633 if ((channel = tpam_findchannel(card, TPAM_NCOID_INVALID)) == TPAM_CHANNEL_INVALID) {
634 printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
635 "All channels are assigned\n");
636 return;
637 }
638 card->channels[channel].ncoid = ncoid;
639 card->channels_tested++;
640 card->channels_used++;
641 }
642
643 /*
644 * Treat a received ADestroyNCOCnf message. Not used by the driver.
645 *
646 * card: the board
647 * skb: the received message
648 */
tpam_recv_ADestroyNCOCnf(tpam_card * card,struct sk_buff * skb)649 void tpam_recv_ADestroyNCOCnf(tpam_card *card, struct sk_buff *skb) {
650 u32 ncoid;
651 u8 status;
652 u32 channel;
653
654 dprintk("TurboPAM(tpam_recv_ADestroyNCOCnf): card=%d\n", card->id);
655
656 /* parse the message contents */
657 if (parse_ADestroyNCOCnf(skb, &status, &ncoid))
658 return;
659
660 if (status) {
661 printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): "
662 "ADestroyNCO failed, status=%d\n", status);
663 return;
664 }
665
666 /* clears the channel's nco ID */
667 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
668 printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): "
669 "ncoid invalid %lu\n", (unsigned long)ncoid);
670 return;
671 }
672
673 card->channels[channel].ncoid = TPAM_NCOID_INVALID;
674 }
675
676 /*
677 * Treat a received CConnectCnf message.
678 *
679 * card: the board
680 * skb: the received message
681 */
tpam_recv_CConnectCnf(tpam_card * card,struct sk_buff * skb)682 void tpam_recv_CConnectCnf(tpam_card *card, struct sk_buff *skb) {
683 u32 ncoid;
684 u32 channel;
685 isdn_ctrl ctrl;
686
687 dprintk("TurboPAM(tpam_recv_CConnectCnf): card=%d\n", card->id);
688
689 /* parse the message contents */
690 if (parse_CConnectCnf(skb, &ncoid))
691 return;
692
693 /* find the channel by its nco ID */
694 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
695 printk(KERN_ERR "TurboPAM(tpam_recv_CConnectCnf): "
696 "ncoid invalid %lu\n", (unsigned long)ncoid);
697 return;
698 }
699
700 /* issue a DCONN command to the ISDN link layer if we are in HDLC mode.
701 * In modem mode, we alreay did it - the ISDN timer kludge */
702 if (card->channels[channel].realhdlc) {
703 ctrl.driver = card->id;
704 ctrl.command = ISDN_STAT_DCONN;
705 ctrl.arg = channel;
706 (* card->interface.statcallb)(&ctrl);
707 }
708 }
709
710 /*
711 * Treat a received CConnectInd message. This function signals a ICALL
712 * to the ISDN link layer.
713 *
714 * card: the board
715 * skb: the received message
716 */
tpam_recv_CConnectInd(tpam_card * card,struct sk_buff * skb)717 void tpam_recv_CConnectInd(tpam_card *card, struct sk_buff *skb) {
718 u32 ncoid;
719 u32 channel;
720 u8 hdlc, plan, screen;
721 u8 calling[PHONE_MAXIMUMSIZE], called[PHONE_MAXIMUMSIZE];
722 isdn_ctrl ctrl;
723 int status;
724
725 dprintk("TurboPAM(tpam_recv_CConnectInd): card=%d\n", card->id);
726
727 /* parse the message contents */
728 if (parse_CConnectInd(skb, &ncoid, &hdlc, calling, called, &plan, &screen))
729 return;
730
731 /* find the channel by its nco ID */
732 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
733 printk(KERN_ERR "TurboPAM(tpam_recv_CConnectInd): "
734 "ncoid invalid %lu\n", (unsigned long)ncoid);
735 return;
736 }
737
738 /* initialize the channel parameters */
739 card->channels[channel].realhdlc = hdlc;
740 card->channels[channel].hdlcshift = 0;
741 card->channels[channel].readytoreceive = 0;
742
743 /* issue a ICALL command to the ISDN link layer */
744 ctrl.driver = card->id;
745 ctrl.command = ISDN_STAT_ICALL;
746 ctrl.arg = channel;
747 memcpy(ctrl.parm.setup.phone, calling, 32);
748 memcpy(ctrl.parm.setup.eazmsn, called, 32);
749 ctrl.parm.setup.si1 = 7; /* data capability */
750 ctrl.parm.setup.si2 = 0;
751 ctrl.parm.setup.plan = plan;
752 ctrl.parm.setup.screen = screen;
753
754 status = (* card->interface.statcallb)(&ctrl);
755 switch (status) {
756 case 1:
757 case 4:
758 /* call accepted, link layer will send us a ACCEPTD
759 * command later */
760 dprintk("TurboPAM(tpam_recv_CConnectInd): "
761 "card=%d, channel=%d, icall waiting, status=%d\n",
762 card->id, channel, status);
763 break;
764 default:
765 /* call denied, we build and send a CDisconnectReq */
766 dprintk("TurboPAM(tpam_recv_CConnectInd): "
767 "card=%d, channel=%d, icall denied, status=%d\n",
768 card->id, channel, status);
769 skb = build_CDisconnectReq(ncoid);
770 if (!skb)
771 return;
772 tpam_enqueue(card, skb);
773 }
774 }
775
776 /*
777 * Treat a received CDisconnectInd message. This function signals a DHUP and
778 * a BHUP to the ISDN link layer.
779 *
780 * card: the board
781 * skb: the received message
782 */
tpam_recv_CDisconnectInd(tpam_card * card,struct sk_buff * skb)783 void tpam_recv_CDisconnectInd(tpam_card *card, struct sk_buff *skb) {
784 u32 ncoid;
785 u32 channel;
786 u32 cause;
787 isdn_ctrl ctrl;
788
789 dprintk("TurboPAM(tpam_recv_CDisconnectInd): card=%d\n", card->id);
790
791 /* parse the message contents */
792 if (parse_CDisconnectInd(skb, &ncoid, &cause))
793 return;
794
795 /* find the channel by its nco ID */
796 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
797 printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectInd): "
798 "ncoid invalid %lu\n", (unsigned long)ncoid);
799 return;
800 }
801
802 /* build and send a CDisconnectRsp */
803 skb = build_CDisconnectRsp(ncoid);
804 if (!skb)
805 return;
806 tpam_enqueue(card, skb);
807
808 /* issue a DHUP to the ISDN link layer */
809 ctrl.driver = card->id;
810 ctrl.command = ISDN_STAT_DHUP;
811 ctrl.arg = channel;
812 (* card->interface.statcallb)(&ctrl);
813
814 /* issue a BHUP to the ISDN link layer */
815 ctrl.driver = card->id;
816 ctrl.command = ISDN_STAT_BHUP;
817 ctrl.arg = channel;
818 (* card->interface.statcallb)(&ctrl);
819 }
820
821 /*
822 * Treat a received CDisconnectCnf message. This function signals a DHUP and
823 * a BHUP to the ISDN link layer.
824 *
825 * card: the board
826 * skb: the received message
827 */
tpam_recv_CDisconnectCnf(tpam_card * card,struct sk_buff * skb)828 void tpam_recv_CDisconnectCnf(tpam_card *card, struct sk_buff *skb) {
829 u32 ncoid;
830 u32 channel;
831 u32 cause;
832 isdn_ctrl ctrl;
833
834 dprintk("TurboPAM(tpam_recv_CDisconnectCnf): card=%d\n", card->id);
835
836 /* parse the message contents */
837 if (parse_CDisconnectCnf(skb, &ncoid, &cause))
838 return;
839
840 /* find the channel by its nco ID */
841 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
842 printk(KERN_ERR "TurboPAM(tpam_recv_CDisconnectCnf): "
843 "ncoid invalid %lu\n", (unsigned long)ncoid);
844 return;
845 }
846
847 /* issue a DHUP to the ISDN link layer */
848 ctrl.driver = card->id;
849 ctrl.command = ISDN_STAT_DHUP;
850 ctrl.arg = channel;
851 (* card->interface.statcallb)(&ctrl);
852
853 /* issue a BHUP to the ISDN link layer */
854 ctrl.driver = card->id;
855 ctrl.command = ISDN_STAT_BHUP;
856 ctrl.arg = channel;
857 (* card->interface.statcallb)(&ctrl);
858 }
859
860 /*
861 * Treat a received U3DataInd message. This function decodes the data
862 * depending on the connection type (modem or HDLC) and passes it to the
863 * ISDN link layer by using rcvcallb_skb.
864 *
865 * card: the board
866 * skb: the received message + data
867 */
tpam_recv_U3DataInd(tpam_card * card,struct sk_buff * skb)868 void tpam_recv_U3DataInd(tpam_card *card, struct sk_buff *skb) {
869 u32 ncoid;
870 u32 channel;
871 u8 *data;
872 u16 len;
873 struct sk_buff *result;
874
875 dprintk("TurboPAM(tpam_recv_U3DataInd): card=%d, datalen=%d\n",
876 card->id, skb->len);
877
878 /* parse the message contents */
879 if (parse_U3DataInd(skb, &ncoid, &data, &len))
880 return;
881
882 /* find the channel by its nco ID */
883 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
884 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
885 "ncoid invalid %lu\n", (unsigned long)ncoid);
886 return;
887 }
888
889 /* decode the data */
890 if (card->channels[ncoid].realhdlc) {
891 /* HDLC mode */
892 u8 *tempdata;
893 u32 templen;
894
895 if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) {
896 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
897 "get_free_page failed\n");
898 return;
899 }
900 templen = tpam_hdlc_decode(data, tempdata, len);
901 templen = hdlc_no_accm_decode(tempdata, templen);
902 if (!(result = alloc_skb(templen, GFP_ATOMIC))) {
903 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
904 "alloc_skb failed\n");
905 free_page((u32)tempdata);
906 return;
907 }
908 memcpy(skb_put(result, templen), tempdata, templen);
909 free_page((u32)tempdata);
910 }
911 else {
912 /* modem mode */
913 if (!(result = alloc_skb(len, GFP_ATOMIC))) {
914 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
915 "alloc_skb failed\n");
916 return;
917 }
918 memcpy(skb_put(result, len), data, len);
919 }
920
921 /* In loop mode, resend the data immediatly */
922 if (card->loopmode) {
923 struct sk_buff *loopskb;
924
925 if (!(loopskb = alloc_skb(skb->len, GFP_ATOMIC))) {
926 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
927 "alloc_skb failed\n");
928 kfree_skb(result);
929 return;
930 }
931 memcpy(skb_put(loopskb, result->len), result->data,
932 result->len);
933 if (tpam_writebuf_skb(card->id, channel, 0, loopskb) < 0)
934 kfree_skb(loopskb);
935 }
936
937 /* pass the data to the ISDN link layer */
938 (* card->interface.rcvcallb_skb)(card->id, channel, result);
939 }
940
941 /*
942 * Treat a received U3ReadyToReceiveInd message. This function sets the
943 * channel ready flag and triggers the send of data if the channel becomed
944 * ready.
945 *
946 * card: the board
947 * skb: the received message + data
948 */
tpam_recv_U3ReadyToReceiveInd(tpam_card * card,struct sk_buff * skb)949 void tpam_recv_U3ReadyToReceiveInd(tpam_card *card, struct sk_buff *skb) {
950 u32 ncoid;
951 u32 channel;
952 u8 ready;
953
954 dprintk("TurboPAM(tpam_recv_U3ReadyToReceiveInd): card=%d\n", card->id);
955
956 /* parse the message contents */
957 if (parse_U3ReadyToReceiveInd(skb, &ncoid, &ready))
958 return;
959
960 /* find the channel by its nco ID */
961 if ((channel = tpam_findchannel(card, ncoid)) == TPAM_CHANNEL_INVALID) {
962 printk(KERN_ERR "TurboPAM(tpam_recv_U3ReadyToReceiveInd): "
963 "ncoid invalid %lu\n", (unsigned long)ncoid);
964 return;
965 }
966
967 /* set the readytoreceive flag */
968 card->channels[channel].readytoreceive = ready;
969
970 /* if the channel just becomed ready, trigger the send of queued data */
971 if (ready)
972 tpam_enqueue_data(&card->channels[channel], NULL);
973 }
974
975 /*
976 * Runs the delayed statcallb when its timer expires.
977 *
978 * parm: pointer to the tpam_statcallb_data statcallb argument.
979 */
tpam_statcallb_run(unsigned long parm)980 static void tpam_statcallb_run(unsigned long parm) {
981 tpam_statcallb_data *ds = (tpam_statcallb_data *)parm;
982
983 dprintk("TurboPAM(tpam_statcallb_run)\n");
984
985 (* ds->card->interface.statcallb)(&ds->ctrl);
986
987 kfree(ds->timer);
988 kfree(ds);
989 }
990
991 /*
992 * Queues a statcallb call for delayed invocation.
993 *
994 * card: the board
995 * ctrl: the statcallb argument
996 */
tpam_statcallb(tpam_card * card,isdn_ctrl ctrl)997 static void tpam_statcallb(tpam_card *card, isdn_ctrl ctrl) {
998 struct timer_list *timer;
999 tpam_statcallb_data *ds;
1000
1001 dprintk("TurboPAM(tpam_statcallb): card=%d\n", card->id);
1002
1003 if (!(timer = (struct timer_list *) kmalloc(sizeof(struct timer_list),
1004 GFP_ATOMIC))) {
1005 printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
1006 return;
1007 }
1008
1009 if (!(ds = (tpam_statcallb_data *) kmalloc(sizeof(tpam_statcallb_data),
1010 GFP_ATOMIC))) {
1011 printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
1012 kfree(timer);
1013 return;
1014 }
1015 ds->card = card;
1016 ds->timer = timer;
1017 memcpy(&ds->ctrl, &ctrl, sizeof(isdn_ctrl));
1018
1019 init_timer(timer);
1020 timer->function = tpam_statcallb_run;
1021 timer->data = (unsigned long)ds;
1022 timer->expires = jiffies + HZ / 10; /* 0.1 second */
1023 add_timer(timer);
1024 }
1025