1 /* $Id: tpam_commands.c,v 1.1.2.4 2001/11/06 20:58:30 kai Exp $
3 * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands)
5 * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, AlcĂ´ve
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
10 * For all support questions please contact: <support@auvertech.fr>
14 #include <linux/module.h>
15 #include <linux/pci.h>
16 #include <linux/sched.h>
17 #include <linux/interrupt.h>
20 #include <linux/isdn/tpam.h>
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);
38 * Function called when the ISDN link level send a command to the driver.
42 * Return: 0 if OK, <0 on errors.
44 int tpam_command(isdn_ctrl *c) {
48 dprintk("TurboPAM(tpam_command) card=%d, command=%d\n",
49 c->driver, c->command);
51 /* search for the board */
52 if (!(card = tpam_findcard(c->driver))) {
53 printk(KERN_ERR "TurboPAM(tpam_command): invalid driverId %d\n",
58 /* dispatch the command */
61 argp = c->parm.userdata;
63 case TPAM_CMD_DSPLOAD:
64 return tpam_command_ioctl_dspload(card,
66 case TPAM_CMD_DSPSAVE:
67 return tpam_command_ioctl_dspsave(card,
70 return tpam_command_ioctl_dsprun(card);
71 case TPAM_CMD_LOOPMODEON:
72 return tpam_command_ioctl_loopmode(card,
74 case TPAM_CMD_LOOPMODEOFF:
75 return tpam_command_ioctl_loopmode(card,
78 dprintk("TurboPAM(tpam_command): "
79 "invalid tpam ioctl %ld\n",
84 return tpam_command_dial(card, c->arg,
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);
91 return tpam_command_hangup(card, c->arg);
93 return tpam_command_setl2(card, c->arg & 0xff,
95 case ISDN_CMD_PROCEED:
96 return tpam_command_proceed(card, c->arg);
98 dprintk("TurboPAM(tpam_command): "
99 "unknown or unused isdn ioctl %d\n",
109 * Load some data into the board's memory.
112 * arg: IOCTL argument containing the user space address of
113 * the tpam_dsp_ioctl structure describing the IOCTL.
115 * Return: 0 if OK, <0 on errors.
117 static int tpam_command_ioctl_dspload(tpam_card *card, u32 arg) {
120 dprintk("TurboPAM(tpam_command_ioctl_dspload): card=%d\n", card->id);
122 /* get the IOCTL parameter from userspace */
123 if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl)))
126 /* if the board's firmware was started, protect against writes
127 * to unallowed memory areas. If the board's firmware wasn't started,
129 if (card->running && tpam_verify_area(tdl.address, tdl.data_len))
132 /* write the data in the board's memory */
133 return copy_from_user_to_pam(card, (void *)tdl.address,
134 (void __user *)arg + sizeof(tpam_dsp_ioctl),
139 * Extract some data from the board's memory.
142 * arg: IOCTL argument containing the user space address of
143 * the tpam_dsp_ioctl structure describing the IOCTL.
145 * Return: 0 if OK, <0 on errors.
147 static int tpam_command_ioctl_dspsave(tpam_card *card, u32 arg) {
150 dprintk("TurboPAM(tpam_command_ioctl_dspsave): card=%d\n", card->id);
152 /* get the IOCTL parameter from userspace */
153 if (copy_from_user(&tdl, (void __user *)arg, sizeof(tpam_dsp_ioctl)))
156 /* protect against read from unallowed memory areas */
157 if (tpam_verify_area(tdl.address, tdl.data_len))
160 /* read the data from the board's memory */
161 return copy_from_pam_to_user(card, (void __user *)arg + sizeof(tpam_dsp_ioctl),
162 (void *)tdl.address, tdl.data_len);
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.
173 * Return: 0 if OK, <0 on errors.
175 static int tpam_command_ioctl_dsprun(tpam_card *card) {
176 u32 signature = 0, i;
177 unsigned long timeout;
181 dprintk("TurboPAM(tpam_command_ioctl_dsprun): card=%d\n", card->id);
183 /* board must _not_ be running */
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);
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)
203 set_current_state(TASK_UNINTERRUPTIBLE);
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);
218 /* the firmware is started */
219 printk(KERN_INFO "TurboPAM: card=%d, firmware started\n", card->id);
221 /* init the CRC routines */
224 /* create all the NCOs */
225 for (i = 0; i < TPAM_NBCHANNEL; ++i)
226 if ((skb = build_ACreateNCOReq("")))
227 tpam_enqueue(card, skb);
229 /* wait for NCO creation confirmation */
230 timeout = jiffies + NCOCREATE_TIMEOUT;
231 while (time_before(jiffies, timeout)) {
232 if (card->channels_tested == TPAM_NBCHANNEL)
234 set_current_state(TASK_UNINTERRUPTIBLE);
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);
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;
253 ctrl.parm.num[0] = 0;
254 (* card->interface.statcallb)(&ctrl);
257 printk(KERN_INFO "TurboPAM: card=%d, ready, %d channels available\n",
258 card->id, card->channels_used);
261 ctrl.driver = card->id;
262 ctrl.command = ISDN_STAT_RUN;
264 tpam_statcallb(card, ctrl);
270 * Set/reset the board's looptest mode.
273 * mode: if 1, sets the board's looptest mode, if 0 resets it.
275 * Return: 0 if OK, <0 if error.
277 static int tpam_command_ioctl_loopmode(tpam_card *card, u8 mode) {
279 /* board must be running */
283 card->loopmode = mode;
288 * Issue a dial command. This function builds and sends a CConnectReq.
291 * channel: the channel number
292 * phone: the remote phone number (EAZ)
294 * Return: 0 if OK, <0 if error.
296 static int tpam_command_dial(tpam_card *card, u32 channel, u8 *phone) {
300 dprintk("TurboPAM(tpam_command_dial): card=%d, channel=%lu, phone=%s\n",
301 card->id, (unsigned long)channel, phone);
303 /* board must be running */
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;
312 /* build and send a CConnectReq */
313 skb = build_CConnectReq(card->channels[channel].ncoid, phone,
314 card->channels[channel].realhdlc);
317 tpam_enqueue(card, skb);
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;
327 tpam_statcallb(card, ctrl);
334 * Set the level2 protocol (modem or HDLC).
337 * channel: the channel number
338 * proto: the level2 protocol (one of ISDN_PROTO_L2*)
340 * Return: 0 if OK, <0 if error.
342 static int tpam_command_setl2(tpam_card *card, u32 channel, u8 proto) {
344 dprintk("TurboPAM(tpam_command_setl2): card=%d, channel=%lu, proto=%d\n",
345 card->id, (unsigned long)channel, proto);
347 /* board must be running */
351 /* set the hdlc/modem mode */
353 case ISDN_PROTO_L2_HDLC:
354 card->channels[channel].hdlc = 1;
356 case ISDN_PROTO_L2_MODEM:
357 card->channels[channel].hdlc = 0;
366 * Accept a D-channel connection (incoming connection). This function
367 * builds and sends a CConnectRsp message and signals DCONN to the ISDN
371 * channel: the channel number
373 * Return: 0 if OK, <0 if error.
375 static int tpam_command_acceptd(tpam_card *card, u32 channel) {
379 dprintk("TurboPAM(tpam_command_acceptd): card=%d, channel=%lu\n",
380 card->id, (unsigned long)channel);
382 /* board must be running */
386 /* build and send a CConnectRsp */
387 skb = build_CConnectRsp(card->channels[channel].ncoid);
390 tpam_enqueue(card, skb);
392 /* issue DCONN to the ISDN link level */
393 ctrl.driver = card->id;
394 ctrl.command = ISDN_STAT_DCONN;
396 tpam_statcallb(card, ctrl);
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.
406 * channel: the channel number
408 * Return: 0 if OK, <0 if error.
410 static int tpam_command_acceptb(tpam_card *card, u32 channel) {
413 dprintk("TurboPAM(tpam_command_acceptb): card=%d, channel=%lu\n",
414 card->id, (unsigned long)channel);
416 /* board must be running */
420 /* issue BCONN to the ISDN link level */
421 ctrl.driver = card->id;
422 ctrl.command = ISDN_STAT_BCONN;
424 ctrl.parm.num[0] = '\0';
425 tpam_statcallb(card, ctrl);
430 * Hang up a connection. This function builds and sends a CDisconnectReq.
433 * channel: the channel number.
435 * Return: 0 if OK, <0 if error.
437 static int tpam_command_hangup(tpam_card *card, u32 channel) {
440 dprintk("TurboPAM(tpam_command_hangup): card=%d, channel=%lu\n",
441 card->id, (unsigned long)channel);
443 /* board must be running */
447 /* build and send a CDisconnectReq */
448 skb = build_CDisconnectReq(card->channels[channel].ncoid);
451 tpam_enqueue(card, skb);
456 * Proceed with an incoming connection. This function builds and sends a
460 * channel: the channel number.
462 * Return: 0 if OK, <0 if error.
464 static int tpam_command_proceed(tpam_card *card, u32 channel) {
467 dprintk("TurboPAM(tpam_command_proceed): card=%d, channel=%lu\n",
468 card->id, (unsigned long)channel);
470 /* board must be running */
474 /* build and send a CConnectRsp */
475 skb = build_CConnectRsp(card->channels[channel].ncoid);
478 tpam_enqueue(card, skb);
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.
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
491 * Return: size of data send if OK, <0 if error.
493 int tpam_writebuf_skb(int driverId, int channel, int ack, struct sk_buff *skb) {
495 int orig_size = skb->len;
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);
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);
510 /* board must be running */
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");
521 /* encode the data */
522 if (!card->channels[channel].realhdlc) {
524 hdlc_encode_modem(skb->data, skb->len, finaldata, &finallen);
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);
537 hdlc_no_accm_encode(skb->data, skb->len, tempdata, &templen);
538 finallen = tpam_hdlc_encode(tempdata, finaldata,
539 &card->channels[channel].hdlcshift,
541 free_page((u32)tempdata);
544 /* free the old sk_buff */
547 /* build and send a U3DataReq */
548 skb = build_U3DataReq(card->channels[channel].ncoid, finaldata,
549 finallen, ack, orig_size);
551 free_page((u32)finaldata);
554 tpam_enqueue_data(&card->channels[channel], skb);
556 /* free the temporary memory */
557 free_page((u32)finaldata);
562 * Treat a received ACreateNCOCnf message.
565 * skb: the received message
567 void tpam_recv_ACreateNCOCnf(tpam_card *card, struct sk_buff *skb) {
572 dprintk("TurboPAM(tpam_recv_ACreateNCOCnf): card=%d\n", card->id);
574 /* parse the message contents */
575 if (parse_ACreateNCOCnf(skb, &status, &ncoid))
578 /* if the card is alreay running, it means that this message
579 * arrives too late... */
581 printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
582 "ACreateNCOCnf received too late, status=%d\n", status);
586 /* the NCO creation failed, the corresponding channel will
589 printk(KERN_ERR "TurboPAM(tpam_recv_ACreateNCOCnf): "
590 "ACreateNCO failed, status=%d\n", status);
591 card->channels_tested++;
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");
601 card->channels[channel].ncoid = ncoid;
602 card->channels_tested++;
603 card->channels_used++;
607 * Treat a received ADestroyNCOCnf message. Not used by the driver.
610 * skb: the received message
612 void tpam_recv_ADestroyNCOCnf(tpam_card *card, struct sk_buff *skb) {
617 dprintk("TurboPAM(tpam_recv_ADestroyNCOCnf): card=%d\n", card->id);
619 /* parse the message contents */
620 if (parse_ADestroyNCOCnf(skb, &status, &ncoid))
624 printk(KERN_ERR "TurboPAM(tpam_recv_ADestroyNCOCnf): "
625 "ADestroyNCO failed, status=%d\n", status);
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);
636 card->channels[channel].ncoid = TPAM_NCOID_INVALID;
640 * Treat a received CConnectCnf message.
643 * skb: the received message
645 void tpam_recv_CConnectCnf(tpam_card *card, struct sk_buff *skb) {
650 dprintk("TurboPAM(tpam_recv_CConnectCnf): card=%d\n", card->id);
652 /* parse the message contents */
653 if (parse_CConnectCnf(skb, &ncoid))
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);
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;
669 (* card->interface.statcallb)(&ctrl);
674 * Treat a received CConnectInd message. This function signals a ICALL
675 * to the ISDN link layer.
678 * skb: the received message
680 void tpam_recv_CConnectInd(tpam_card *card, struct sk_buff *skb) {
683 u8 hdlc, plan, screen;
684 u8 calling[PHONE_MAXIMUMSIZE], called[PHONE_MAXIMUMSIZE];
688 dprintk("TurboPAM(tpam_recv_CConnectInd): card=%d\n", card->id);
690 /* parse the message contents */
691 if (parse_CConnectInd(skb, &ncoid, &hdlc, calling, called, &plan, &screen))
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);
701 /* initialize the channel parameters */
702 card->channels[channel].realhdlc = hdlc;
703 card->channels[channel].hdlcshift = 0;
704 card->channels[channel].readytoreceive = 0;
706 /* issue a ICALL command to the ISDN link layer */
707 ctrl.driver = card->id;
708 ctrl.command = ISDN_STAT_ICALL;
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;
717 status = (* card->interface.statcallb)(&ctrl);
721 /* call accepted, link layer will send us a ACCEPTD
723 dprintk("TurboPAM(tpam_recv_CConnectInd): "
724 "card=%d, channel=%d, icall waiting, status=%d\n",
725 card->id, channel, status);
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);
735 tpam_enqueue(card, skb);
740 * Treat a received CDisconnectInd message. This function signals a DHUP and
741 * a BHUP to the ISDN link layer.
744 * skb: the received message
746 void tpam_recv_CDisconnectInd(tpam_card *card, struct sk_buff *skb) {
752 dprintk("TurboPAM(tpam_recv_CDisconnectInd): card=%d\n", card->id);
754 /* parse the message contents */
755 if (parse_CDisconnectInd(skb, &ncoid, &cause))
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);
765 /* build and send a CDisconnectRsp */
766 skb = build_CDisconnectRsp(ncoid);
769 tpam_enqueue(card, skb);
771 /* issue a DHUP to the ISDN link layer */
772 ctrl.driver = card->id;
773 ctrl.command = ISDN_STAT_DHUP;
775 (* card->interface.statcallb)(&ctrl);
777 /* issue a BHUP to the ISDN link layer */
778 ctrl.driver = card->id;
779 ctrl.command = ISDN_STAT_BHUP;
781 (* card->interface.statcallb)(&ctrl);
785 * Treat a received CDisconnectCnf message. This function signals a DHUP and
786 * a BHUP to the ISDN link layer.
789 * skb: the received message
791 void tpam_recv_CDisconnectCnf(tpam_card *card, struct sk_buff *skb) {
797 dprintk("TurboPAM(tpam_recv_CDisconnectCnf): card=%d\n", card->id);
799 /* parse the message contents */
800 if (parse_CDisconnectCnf(skb, &ncoid, &cause))
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);
810 /* issue a DHUP to the ISDN link layer */
811 ctrl.driver = card->id;
812 ctrl.command = ISDN_STAT_DHUP;
814 (* card->interface.statcallb)(&ctrl);
816 /* issue a BHUP to the ISDN link layer */
817 ctrl.driver = card->id;
818 ctrl.command = ISDN_STAT_BHUP;
820 (* card->interface.statcallb)(&ctrl);
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.
829 * skb: the received message + data
831 void tpam_recv_U3DataInd(tpam_card *card, struct sk_buff *skb) {
836 struct sk_buff *result;
838 dprintk("TurboPAM(tpam_recv_U3DataInd): card=%d, datalen=%d\n",
841 /* parse the message contents */
842 if (parse_U3DataInd(skb, &ncoid, &data, &len))
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);
852 /* decode the data */
853 if (card->channels[ncoid].realhdlc) {
858 if (!(tempdata = (void *)__get_free_page(GFP_ATOMIC))) {
859 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
860 "get_free_page failed\n");
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);
871 memcpy(skb_put(result, templen), tempdata, templen);
872 free_page((u32)tempdata);
876 if (!(result = alloc_skb(len, GFP_ATOMIC))) {
877 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
878 "alloc_skb failed\n");
881 memcpy(skb_put(result, len), data, len);
884 /* In loop mode, resend the data immediately */
885 if (card->loopmode) {
886 struct sk_buff *loopskb;
888 if (!(loopskb = alloc_skb(skb->len, GFP_ATOMIC))) {
889 printk(KERN_ERR "TurboPAM(tpam_recv_U3DataInd): "
890 "alloc_skb failed\n");
894 memcpy(skb_put(loopskb, result->len), result->data,
896 if (tpam_writebuf_skb(card->id, channel, 0, loopskb) < 0)
900 /* pass the data to the ISDN link layer */
901 (* card->interface.rcvcallb_skb)(card->id, channel, result);
905 * Treat a received U3ReadyToReceiveInd message. This function sets the
906 * channel ready flag and triggers the send of data if the channel becomed
910 * skb: the received message + data
912 void tpam_recv_U3ReadyToReceiveInd(tpam_card *card, struct sk_buff *skb) {
917 dprintk("TurboPAM(tpam_recv_U3ReadyToReceiveInd): card=%d\n", card->id);
919 /* parse the message contents */
920 if (parse_U3ReadyToReceiveInd(skb, &ncoid, &ready))
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);
930 /* set the readytoreceive flag */
931 card->channels[channel].readytoreceive = ready;
933 /* if the channel just becomed ready, trigger the send of queued data */
935 tpam_enqueue_data(&card->channels[channel], NULL);
939 * Runs the delayed statcallb when its timer expires.
941 * parm: pointer to the tpam_statcallb_data statcallb argument.
943 static void tpam_statcallb_run(unsigned long parm) {
944 tpam_statcallb_data *ds = (tpam_statcallb_data *)parm;
946 dprintk("TurboPAM(tpam_statcallb_run)\n");
948 (* ds->card->interface.statcallb)(&ds->ctrl);
955 * Queues a statcallb call for delayed invocation.
958 * ctrl: the statcallb argument
960 static void tpam_statcallb(tpam_card *card, isdn_ctrl ctrl) {
961 struct timer_list *timer;
962 tpam_statcallb_data *ds;
964 dprintk("TurboPAM(tpam_statcallb): card=%d\n", card->id);
966 if (!(timer = (struct timer_list *) kmalloc(sizeof(struct timer_list),
968 printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
972 if (!(ds = (tpam_statcallb_data *) kmalloc(sizeof(tpam_statcallb_data),
974 printk(KERN_ERR "TurboPAM: tpam_statcallb: kmalloc failed!\n");
980 memcpy(&ds->ctrl, &ctrl, sizeof(isdn_ctrl));
983 timer->function = tpam_statcallb_run;
984 timer->data = (unsigned long)ds;
985 timer->expires = jiffies + HZ / 10; /* 0.1 second */