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