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