added mtd driver
[linux-2.4.git] / drivers / isdn / tpam / tpam_commands.c
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }