capi.c 32.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* $Id: capi.c,v 1.1.2.7 2004/04/28 09:48:59 armin Exp $
 *
 * CAPI 2.0 Interface for Linux
 *
 * Copyright 1996 by Carsten Paeth <calle@calle.de>
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
21
#include <linux/mutex.h>
L
Linus Torvalds 已提交
22 23 24 25 26 27
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/netdevice.h>
#include <linux/ppp_defs.h>
28
#include <linux/ppp-ioctl.h>
L
Linus Torvalds 已提交
29 30
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
31
#include <linux/seq_file.h>
L
Linus Torvalds 已提交
32 33 34 35 36 37 38 39
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
J
Jan Kiszka 已提交
40

L
Linus Torvalds 已提交
41 42 43 44 45 46
MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");

/* -------- driver information -------------------------------------- */

47
static DEFINE_MUTEX(capi_mutex);
48
static struct class *capi_class;
A
Adrian Bunk 已提交
49
static int capi_major = 68;		/* allocated */
50 51 52

module_param_named(major, capi_major, uint, 0);

L
Linus Torvalds 已提交
53
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
54
#define CAPINC_NR_PORTS		32
L
Linus Torvalds 已提交
55
#define CAPINC_MAX_PORTS	256
56

A
Adrian Bunk 已提交
57
static int capi_ttyminors = CAPINC_NR_PORTS;
L
Linus Torvalds 已提交
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

module_param_named(ttyminors, capi_ttyminors, uint, 0);
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */

/* -------- defines ------------------------------------------------- */

#define CAPINC_MAX_RECVQUEUE	10
#define CAPINC_MAX_SENDQUEUE	10
#define CAPI_MAX_BLKSIZE	2048

/* -------- data structures ----------------------------------------- */

struct capidev;
struct capincci;
struct capiminor;

74
struct ackqueue_entry {
75 76 77 78
	struct list_head	list;
	u16			datahandle;
};

L
Linus Torvalds 已提交
79 80 81
struct capiminor {
	unsigned int      minor;

82 83 84 85
	struct capi20_appl	*ap;
	u32			ncci;
	atomic_t		datahandle;
	atomic_t		msgid;
L
Linus Torvalds 已提交
86

87
	struct tty_port port;
L
Linus Torvalds 已提交
88 89 90
	int                ttyinstop;
	int                ttyoutstop;

91 92 93 94 95 96
	struct sk_buff_head	inqueue;

	struct sk_buff_head	outqueue;
	int			outbytes;
	struct sk_buff		*outskb;
	spinlock_t		outlock;
L
Linus Torvalds 已提交
97 98

	/* transmit path */
99
	struct list_head ackqueue;
L
Linus Torvalds 已提交
100
	int nack;
101
	spinlock_t ackqlock;
L
Linus Torvalds 已提交
102 103 104
};

struct capincci {
105
	struct list_head list;
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	u32		 ncci;
	struct capidev	*cdev;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
	struct capiminor *minorp;
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
};

struct capidev {
	struct list_head list;
	struct capi20_appl ap;
	u16		errcode;
	unsigned        userflags;

	struct sk_buff_head recvqueue;
	wait_queue_head_t recvwait;

122
	struct list_head nccis;
L
Linus Torvalds 已提交
123

124
	struct mutex lock;
L
Linus Torvalds 已提交
125 126 127 128
};

/* -------- global variables ---------------------------------------- */

129
static DEFINE_MUTEX(capidev_list_lock);
L
Linus Torvalds 已提交
130 131 132
static LIST_HEAD(capidev_list);

#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
133

J
Jan Kiszka 已提交
134
static DEFINE_SPINLOCK(capiminors_lock);
135
static struct capiminor **capiminors;
L
Linus Torvalds 已提交
136

137 138
static struct tty_driver *capinc_tty_driver;

L
Linus Torvalds 已提交
139 140
/* -------- datahandles --------------------------------------------- */

141
static int capiminor_add_ack(struct capiminor *mp, u16 datahandle)
L
Linus Torvalds 已提交
142
{
143
	struct ackqueue_entry *n;
L
Linus Torvalds 已提交
144 145

	n = kmalloc(sizeof(*n), GFP_ATOMIC);
146 147 148
	if (unlikely(!n)) {
		printk(KERN_ERR "capi: alloc datahandle failed\n");
		return -1;
L
Linus Torvalds 已提交
149 150
	}
	n->datahandle = datahandle;
151
	INIT_LIST_HEAD(&n->list);
J
Jan Kiszka 已提交
152
	spin_lock_bh(&mp->ackqlock);
153
	list_add_tail(&n->list, &mp->ackqueue);
L
Linus Torvalds 已提交
154
	mp->nack++;
J
Jan Kiszka 已提交
155
	spin_unlock_bh(&mp->ackqlock);
L
Linus Torvalds 已提交
156 157 158 159 160
	return 0;
}

static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
{
161
	struct ackqueue_entry *p, *tmp;
L
Linus Torvalds 已提交
162

J
Jan Kiszka 已提交
163
	spin_lock_bh(&mp->ackqlock);
164
	list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
165
		if (p->datahandle == datahandle) {
166
			list_del(&p->list);
L
Linus Torvalds 已提交
167
			mp->nack--;
J
Jan Kiszka 已提交
168 169
			spin_unlock_bh(&mp->ackqlock);
			kfree(p);
L
Linus Torvalds 已提交
170 171 172
			return 0;
		}
	}
J
Jan Kiszka 已提交
173
	spin_unlock_bh(&mp->ackqlock);
L
Linus Torvalds 已提交
174 175 176 177 178
	return -1;
}

static void capiminor_del_all_ack(struct capiminor *mp)
{
179
	struct ackqueue_entry *p, *tmp;
L
Linus Torvalds 已提交
180

181 182
	list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
		list_del(&p->list);
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190
		kfree(p);
		mp->nack--;
	}
}


/* -------- struct capiminor ---------------------------------------- */

J
Jiri Slaby 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204
static void capiminor_destroy(struct tty_port *port)
{
	struct capiminor *mp = container_of(port, struct capiminor, port);

	kfree_skb(mp->outskb);
	skb_queue_purge(&mp->inqueue);
	skb_queue_purge(&mp->outqueue);
	capiminor_del_all_ack(mp);
	kfree(mp);
}

static const struct tty_port_operations capiminor_port_ops = {
	.destruct = capiminor_destroy,
};
205

L
Linus Torvalds 已提交
206 207
static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
{
208
	struct capiminor *mp;
209
	struct device *dev;
210
	unsigned int minor;
L
Linus Torvalds 已提交
211

212
	mp = kzalloc(sizeof(*mp), GFP_KERNEL);
213 214
	if (!mp) {
		printk(KERN_ERR "capi: can't alloc capiminor\n");
L
Linus Torvalds 已提交
215 216 217 218 219
		return NULL;
	}

	mp->ap = ap;
	mp->ncci = ncci;
220 221
	INIT_LIST_HEAD(&mp->ackqueue);
	spin_lock_init(&mp->ackqlock);
L
Linus Torvalds 已提交
222 223 224

	skb_queue_head_init(&mp->inqueue);
	skb_queue_head_init(&mp->outqueue);
225
	spin_lock_init(&mp->outlock);
L
Linus Torvalds 已提交
226

227 228 229
	tty_port_init(&mp->port);
	mp->port.ops = &capiminor_port_ops;

230
	/* Allocate the least unused minor number. */
J
Jan Kiszka 已提交
231
	spin_lock(&capiminors_lock);
232 233 234 235
	for (minor = 0; minor < capi_ttyminors; minor++)
		if (!capiminors[minor]) {
			capiminors[minor] = mp;
			break;
L
Linus Torvalds 已提交
236
		}
J
Jan Kiszka 已提交
237
	spin_unlock(&capiminors_lock);
L
Linus Torvalds 已提交
238

239
	if (minor == capi_ttyminors) {
L
Linus Torvalds 已提交
240
		printk(KERN_NOTICE "capi: out of minors\n");
241
		goto err_out1;
L
Linus Torvalds 已提交
242 243
	}

244 245
	mp->minor = minor;

J
Jiri Slaby 已提交
246 247
	dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
			NULL);
248 249 250
	if (IS_ERR(dev))
		goto err_out2;

L
Linus Torvalds 已提交
251
	return mp;
252 253

err_out2:
J
Jan Kiszka 已提交
254
	spin_lock(&capiminors_lock);
255
	capiminors[minor] = NULL;
J
Jan Kiszka 已提交
256
	spin_unlock(&capiminors_lock);
257 258

err_out1:
J
Jiri Slaby 已提交
259
	tty_port_put(&mp->port);
260
	return NULL;
L
Linus Torvalds 已提交
261 262
}

263
static struct capiminor *capiminor_get(unsigned int minor)
L
Linus Torvalds 已提交
264
{
265
	struct capiminor *mp;
L
Linus Torvalds 已提交
266

J
Jan Kiszka 已提交
267
	spin_lock(&capiminors_lock);
268
	mp = capiminors[minor];
J
Jan Kiszka 已提交
269
	if (mp)
J
Jiri Slaby 已提交
270
		tty_port_get(&mp->port);
J
Jan Kiszka 已提交
271
	spin_unlock(&capiminors_lock);
272 273

	return mp;
L
Linus Torvalds 已提交
274 275
}

J
Jan Kiszka 已提交
276 277
static inline void capiminor_put(struct capiminor *mp)
{
J
Jiri Slaby 已提交
278
	tty_port_put(&mp->port);
J
Jan Kiszka 已提交
279 280 281 282 283 284
}

static void capiminor_free(struct capiminor *mp)
{
	tty_unregister_device(capinc_tty_driver, mp->minor);

J
Jan Kiszka 已提交
285
	spin_lock(&capiminors_lock);
J
Jan Kiszka 已提交
286
	capiminors[mp->minor] = NULL;
J
Jan Kiszka 已提交
287
	spin_unlock(&capiminors_lock);
J
Jan Kiszka 已提交
288 289 290 291

	capiminor_put(mp);
}

L
Linus Torvalds 已提交
292 293
/* -------- struct capincci ----------------------------------------- */

294
static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
L
Linus Torvalds 已提交
295
{
296 297
	if (cdev->userflags & CAPIFLAG_HIGHJACKING)
		np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
298 299 300 301 302
}

static void capincci_free_minor(struct capincci *np)
{
	struct capiminor *mp = np->minorp;
303
	struct tty_struct *tty;
304 305

	if (mp) {
306 307
		tty = tty_port_tty_get(&mp->port);
		if (tty) {
308
			tty_vhangup(tty);
309
			tty_kref_put(tty);
310
		}
311 312

		capiminor_free(mp);
313 314 315 316 317 318
	}
}

static inline unsigned int capincci_minor_opencount(struct capincci *np)
{
	struct capiminor *mp = np->minorp;
J
Jan Kiszka 已提交
319 320
	unsigned int count = 0;
	struct tty_struct *tty;
321

J
Jan Kiszka 已提交
322 323 324 325 326 327 328 329
	if (mp) {
		tty = tty_port_tty_get(&mp->port);
		if (tty) {
			count = tty->count;
			tty_kref_put(tty);
		}
	}
	return count;
330 331 332 333 334 335 336 337 338 339 340 341
}

#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */

static inline void
capincci_alloc_minor(struct capidev *cdev, struct capincci *np) { }
static inline void capincci_free_minor(struct capincci *np) { }

#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */

static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
{
342
	struct capincci *np;
343

344
	np = kzalloc(sizeof(*np), GFP_KERNEL);
345 346 347 348 349 350 351
	if (!np)
		return NULL;
	np->ncci = ncci;
	np->cdev = cdev;

	capincci_alloc_minor(cdev, np);

352 353 354
	list_add_tail(&np->list, &cdev->nccis);

	return np;
L
Linus Torvalds 已提交
355 356 357 358
}

static void capincci_free(struct capidev *cdev, u32 ncci)
{
359
	struct capincci *np, *tmp;
L
Linus Torvalds 已提交
360

361
	list_for_each_entry_safe(np, tmp, &cdev->nccis, list)
L
Linus Torvalds 已提交
362
		if (ncci == 0xffffffff || np->ncci == ncci) {
363
			capincci_free_minor(np);
364
			list_del(&np->list);
L
Linus Torvalds 已提交
365 366 367 368
			kfree(np);
		}
}

369
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
L
Linus Torvalds 已提交
370 371
static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
{
372
	struct capincci *np;
L
Linus Torvalds 已提交
373

374 375 376 377
	list_for_each_entry(np, &cdev->nccis, list)
		if (np->ncci == ncci)
			return np;
	return NULL;
L
Linus Torvalds 已提交
378 379 380 381 382 383 384 385
}

/* -------- handle data queue --------------------------------------- */

static struct sk_buff *
gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
{
	struct sk_buff *nskb;
386
	nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_KERNEL);
L
Linus Torvalds 已提交
387
	if (nskb) {
388
		u16 datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2);
L
Linus Torvalds 已提交
389 390 391 392 393
		unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
		capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
		capimsg_setu16(s, 2, mp->ap->applid);
		capimsg_setu8 (s, 4, CAPI_DATA_B3);
		capimsg_setu8 (s, 5, CAPI_RESP);
394
		capimsg_setu16(s, 6, atomic_inc_return(&mp->msgid));
L
Linus Torvalds 已提交
395 396 397 398 399 400 401 402
		capimsg_setu32(s, 8, mp->ncci);
		capimsg_setu16(s, 12, datahandle);
	}
	return nskb;
}

static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
{
J
Jan Kiszka 已提交
403
	unsigned int datalen = skb->len - CAPIMSG_LEN(skb->data);
404
	struct tty_struct *tty;
L
Linus Torvalds 已提交
405 406 407
	struct sk_buff *nskb;
	u16 errcode, datahandle;
	struct tty_ldisc *ld;
408 409 410 411
	int ret = -1;

	tty = tty_port_tty_get(&mp->port);
	if (!tty) {
412
		pr_debug("capi: currently no receiver\n");
L
Linus Torvalds 已提交
413 414
		return -1;
	}
415

416
	ld = tty_ldisc_ref(tty);
J
Jan Kiszka 已提交
417 418 419 420 421 422
	if (!ld) {
		/* fatal error, do not requeue */
		ret = 0;
		kfree_skb(skb);
		goto deref_tty;
	}
423

A
Alan Cox 已提交
424
	if (ld->ops->receive_buf == NULL) {
425
		pr_debug("capi: ldisc has no receive_buf function\n");
J
Jan Kiszka 已提交
426 427
		/* fatal error, do not requeue */
		goto free_skb;
L
Linus Torvalds 已提交
428 429
	}
	if (mp->ttyinstop) {
430
		pr_debug("capi: recv tty throttled\n");
J
Jan Kiszka 已提交
431
		goto deref_ldisc;
L
Linus Torvalds 已提交
432
	}
J
Jan Kiszka 已提交
433

434
	if (tty->receive_room < datalen) {
435
		pr_debug("capi: no room in tty\n");
J
Jan Kiszka 已提交
436
		goto deref_ldisc;
L
Linus Torvalds 已提交
437
	}
J
Jan Kiszka 已提交
438 439 440

	nskb = gen_data_b3_resp_for(mp, skb);
	if (!nskb) {
L
Linus Torvalds 已提交
441
		printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
J
Jan Kiszka 已提交
442
		goto deref_ldisc;
L
Linus Torvalds 已提交
443
	}
J
Jan Kiszka 已提交
444 445 446

	datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);

L
Linus Torvalds 已提交
447
	errcode = capi20_put_message(mp->ap, nskb);
J
Jan Kiszka 已提交
448 449 450

	if (errcode == CAPI_NOERROR) {
		skb_pull(skb, CAPIMSG_LEN(skb->data));
451 452
		pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n",
			 datahandle, skb->len);
J
Jan Kiszka 已提交
453 454
		ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
	} else {
L
Linus Torvalds 已提交
455
		printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
456
		       errcode);
L
Linus Torvalds 已提交
457
		kfree_skb(nskb);
J
Jan Kiszka 已提交
458 459 460

		if (errcode == CAPI_SENDQUEUEFULL)
			goto deref_ldisc;
L
Linus Torvalds 已提交
461
	}
J
Jan Kiszka 已提交
462 463

free_skb:
464
	ret = 0;
J
Jan Kiszka 已提交
465 466 467
	kfree_skb(skb);

deref_ldisc:
L
Linus Torvalds 已提交
468
	tty_ldisc_deref(ld);
J
Jan Kiszka 已提交
469 470

deref_tty:
471 472
	tty_kref_put(tty);
	return ret;
L
Linus Torvalds 已提交
473 474 475 476 477
}

static void handle_minor_recv(struct capiminor *mp)
{
	struct sk_buff *skb;
478 479

	while ((skb = skb_dequeue(&mp->inqueue)) != NULL)
L
Linus Torvalds 已提交
480 481 482 483 484 485
		if (handle_recv_skb(mp, skb) < 0) {
			skb_queue_head(&mp->inqueue, skb);
			return;
		}
}

486
static void handle_minor_send(struct capiminor *mp)
L
Linus Torvalds 已提交
487
{
488
	struct tty_struct *tty;
L
Linus Torvalds 已提交
489 490 491 492 493
	struct sk_buff *skb;
	u16 len;
	u16 errcode;
	u16 datahandle;

494 495
	tty = tty_port_tty_get(&mp->port);
	if (!tty)
496
		return;
497 498

	if (mp->ttyoutstop) {
499
		pr_debug("capi: send: tty stopped\n");
500
		tty_kref_put(tty);
501
		return;
L
Linus Torvalds 已提交
502 503
	}

504 505 506 507 508 509 510
	while (1) {
		spin_lock_bh(&mp->outlock);
		skb = __skb_dequeue(&mp->outqueue);
		if (!skb) {
			spin_unlock_bh(&mp->outlock);
			break;
		}
L
Linus Torvalds 已提交
511
		len = (u16)skb->len;
512 513 514 515
		mp->outbytes -= len;
		spin_unlock_bh(&mp->outlock);

		datahandle = atomic_inc_return(&mp->datahandle);
L
Linus Torvalds 已提交
516 517 518 519 520 521
		skb_push(skb, CAPI_DATA_B3_REQ_LEN);
		memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
		capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
		capimsg_setu16(skb->data, 2, mp->ap->applid);
		capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
		capimsg_setu8 (skb->data, 5, CAPI_REQ);
522
		capimsg_setu16(skb->data, 6, atomic_inc_return(&mp->msgid));
L
Linus Torvalds 已提交
523
		capimsg_setu32(skb->data, 8, mp->ncci);	/* NCCI */
A
Andrew Morton 已提交
524
		capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */
L
Linus Torvalds 已提交
525 526 527 528
		capimsg_setu16(skb->data, 16, len);	/* Data length */
		capimsg_setu16(skb->data, 18, datahandle);
		capimsg_setu16(skb->data, 20, 0);	/* Flags */

529
		if (capiminor_add_ack(mp, datahandle) < 0) {
L
Linus Torvalds 已提交
530
			skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
531 532 533 534 535 536

			spin_lock_bh(&mp->outlock);
			__skb_queue_head(&mp->outqueue, skb);
			mp->outbytes += len;
			spin_unlock_bh(&mp->outlock);

537
			break;
L
Linus Torvalds 已提交
538 539 540
		}
		errcode = capi20_put_message(mp->ap, skb);
		if (errcode == CAPI_NOERROR) {
541 542
			pr_debug("capi: DATA_B3_REQ %u len=%u\n",
				 datahandle, len);
L
Linus Torvalds 已提交
543 544 545 546 547 548
			continue;
		}
		capiminor_del_ack(mp, datahandle);

		if (errcode == CAPI_SENDQUEUEFULL) {
			skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
549 550 551 552 553 554

			spin_lock_bh(&mp->outlock);
			__skb_queue_head(&mp->outqueue, skb);
			mp->outbytes += len;
			spin_unlock_bh(&mp->outlock);

L
Linus Torvalds 已提交
555 556 557 558 559 560 561
			break;
		}

		/* ups, drop packet */
		printk(KERN_ERR "capi: put_message = %x\n", errcode);
		kfree_skb(skb);
	}
562
	tty_kref_put(tty);
L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571 572 573 574
}

#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
/* -------- function called by lower level -------------------------- */

static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
	struct capidev *cdev = ap->private;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
	struct capiminor *mp;
	u16 datahandle;
	struct capincci *np;
575
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
L
Linus Torvalds 已提交
576

577 578
	mutex_lock(&cdev->lock);

L
Linus Torvalds 已提交
579 580
	if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
		u16 info = CAPIMSG_U16(skb->data, 12); // Info field
581
		if ((info & 0xff00) == 0)
L
Linus Torvalds 已提交
582 583
			capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
	}
584
	if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND)
L
Linus Torvalds 已提交
585
		capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
586

L
Linus Torvalds 已提交
587 588 589
	if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
		skb_queue_tail(&cdev->recvqueue, skb);
		wake_up_interruptible(&cdev->recvwait);
590
		goto unlock_out;
L
Linus Torvalds 已提交
591
	}
592

593 594 595 596 597 598
#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
	skb_queue_tail(&cdev->recvqueue, skb);
	wake_up_interruptible(&cdev->recvwait);

#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */

599
	np = capincci_find(cdev, CAPIMSG_CONTROL(skb->data));
L
Linus Torvalds 已提交
600 601 602 603
	if (!np) {
		printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
		skb_queue_tail(&cdev->recvqueue, skb);
		wake_up_interruptible(&cdev->recvwait);
604
		goto unlock_out;
L
Linus Torvalds 已提交
605
	}
606

L
Linus Torvalds 已提交
607 608 609 610
	mp = np->minorp;
	if (!mp) {
		skb_queue_tail(&cdev->recvqueue, skb);
		wake_up_interruptible(&cdev->recvwait);
611
		goto unlock_out;
L
Linus Torvalds 已提交
612 613
	}
	if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
614
		datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 4 + 2);
615 616
		pr_debug("capi_signal: DATA_B3_IND %u len=%d\n",
			 datahandle, skb->len-CAPIMSG_LEN(skb->data));
L
Linus Torvalds 已提交
617
		skb_queue_tail(&mp->inqueue, skb);
618

L
Linus Torvalds 已提交
619 620 621 622
		handle_minor_recv(mp);

	} else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {

623
		datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4);
624 625
		pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n",
			 datahandle,
626
			 CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));
L
Linus Torvalds 已提交
627
		kfree_skb(skb);
J
Jan Kiszka 已提交
628
		capiminor_del_ack(mp, datahandle);
J
Jiri Slaby 已提交
629
		tty_port_tty_wakeup(&mp->port);
630
		handle_minor_send(mp);
L
Linus Torvalds 已提交
631 632 633 634 635 636 637

	} else {
		/* ups, let capi application handle it :-) */
		skb_queue_tail(&cdev->recvqueue, skb);
		wake_up_interruptible(&cdev->recvwait);
	}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
638

639 640
unlock_out:
	mutex_unlock(&cdev->lock);
L
Linus Torvalds 已提交
641 642 643 644 645 646 647
}

/* -------- file_operations for capidev ----------------------------- */

static ssize_t
capi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
648
	struct capidev *cdev = file->private_data;
L
Linus Torvalds 已提交
649 650
	struct sk_buff *skb;
	size_t copied;
J
Jan Kiszka 已提交
651
	int err;
L
Linus Torvalds 已提交
652 653 654 655

	if (!cdev->ap.applid)
		return -ENODEV;

J
Jan Kiszka 已提交
656 657
	skb = skb_dequeue(&cdev->recvqueue);
	if (!skb) {
L
Linus Torvalds 已提交
658 659
		if (file->f_flags & O_NONBLOCK)
			return -EAGAIN;
J
Jan Kiszka 已提交
660
		err = wait_event_interruptible(cdev->recvwait,
661
					       (skb = skb_dequeue(&cdev->recvqueue)));
J
Jan Kiszka 已提交
662 663
		if (err)
			return err;
L
Linus Torvalds 已提交
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
	}
	if (skb->len > count) {
		skb_queue_head(&cdev->recvqueue, skb);
		return -EMSGSIZE;
	}
	if (copy_to_user(buf, skb->data, skb->len)) {
		skb_queue_head(&cdev->recvqueue, skb);
		return -EFAULT;
	}
	copied = skb->len;

	kfree_skb(skb);

	return copied;
}

static ssize_t
capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
683
	struct capidev *cdev = file->private_data;
L
Linus Torvalds 已提交
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	struct sk_buff *skb;
	u16 mlen;

	if (!cdev->ap.applid)
		return -ENODEV;

	skb = alloc_skb(count, GFP_USER);
	if (!skb)
		return -ENOMEM;

	if (copy_from_user(skb_put(skb, count), buf, count)) {
		kfree_skb(skb);
		return -EFAULT;
	}
	mlen = CAPIMSG_LEN(skb->data);
	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
		if ((size_t)(mlen + CAPIMSG_DATALEN(skb->data)) != count) {
			kfree_skb(skb);
			return -EINVAL;
		}
	} else {
		if (mlen != count) {
			kfree_skb(skb);
			return -EINVAL;
		}
	}
	CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);

	if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
713
		mutex_lock(&cdev->lock);
L
Linus Torvalds 已提交
714
		capincci_free(cdev, CAPIMSG_NCCI(skb->data));
715
		mutex_unlock(&cdev->lock);
L
Linus Torvalds 已提交
716 717 718 719 720 721 722 723 724 725 726 727
	}

	cdev->errcode = capi20_put_message(&cdev->ap, skb);

	if (cdev->errcode) {
		kfree_skb(skb);
		return -EIO;
	}
	return count;
}

static unsigned int
728
capi_poll(struct file *file, poll_table *wait)
L
Linus Torvalds 已提交
729
{
730
	struct capidev *cdev = file->private_data;
L
Linus Torvalds 已提交
731 732 733 734 735 736 737 738 739 740 741 742 743
	unsigned int mask = 0;

	if (!cdev->ap.applid)
		return POLLERR;

	poll_wait(file, &(cdev->recvwait), wait);
	mask = POLLOUT | POLLWRNORM;
	if (!skb_queue_empty(&cdev->recvqueue))
		mask |= POLLIN | POLLRDNORM;
	return mask;
}

static int
744
capi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
745 746 747 748 749 750 751 752
{
	struct capidev *cdev = file->private_data;
	capi_ioctl_struct data;
	int retval = -EINVAL;
	void __user *argp = (void __user *)arg;

	switch (cmd) {
	case CAPI_REGISTER:
753
		mutex_lock(&cdev->lock);
L
Linus Torvalds 已提交
754

755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
		if (cdev->ap.applid) {
			retval = -EEXIST;
			goto register_out;
		}
		if (copy_from_user(&cdev->ap.rparam, argp,
				   sizeof(struct capi_register_params))) {
			retval = -EFAULT;
			goto register_out;
		}
		cdev->ap.private = cdev;
		cdev->ap.recv_message = capi_recv_message;
		cdev->errcode = capi20_register(&cdev->ap);
		retval = (int)cdev->ap.applid;
		if (cdev->errcode) {
			cdev->ap.applid = 0;
			retval = -EIO;
L
Linus Torvalds 已提交
771
		}
772 773 774 775

register_out:
		mutex_unlock(&cdev->lock);
		return retval;
L
Linus Torvalds 已提交
776 777

	case CAPI_GET_VERSION:
778 779 780 781 782 783 784 785 786
		if (copy_from_user(&data.contr, argp,
				   sizeof(data.contr)))
			return -EFAULT;
		cdev->errcode = capi20_get_version(data.contr, &data.version);
		if (cdev->errcode)
			return -EIO;
		if (copy_to_user(argp, &data.version,
				 sizeof(data.version)))
			return -EFAULT;
787
		return 0;
L
Linus Torvalds 已提交
788 789

	case CAPI_GET_SERIAL:
790 791 792 793 794 795 796 797 798
		if (copy_from_user(&data.contr, argp,
				   sizeof(data.contr)))
			return -EFAULT;
		cdev->errcode = capi20_get_serial(data.contr, data.serial);
		if (cdev->errcode)
			return -EIO;
		if (copy_to_user(argp, data.serial,
				 sizeof(data.serial)))
			return -EFAULT;
799 800
		return 0;

L
Linus Torvalds 已提交
801
	case CAPI_GET_PROFILE:
802 803 804
		if (copy_from_user(&data.contr, argp,
				   sizeof(data.contr)))
			return -EFAULT;
L
Linus Torvalds 已提交
805

806 807 808 809
		if (data.contr == 0) {
			cdev->errcode = capi20_get_profile(data.contr, &data.profile);
			if (cdev->errcode)
				return -EIO;
L
Linus Torvalds 已提交
810

811 812 813
			retval = copy_to_user(argp,
					      &data.profile.ncontroller,
					      sizeof(data.profile.ncontroller));
L
Linus Torvalds 已提交
814

815 816 817 818
		} else {
			cdev->errcode = capi20_get_profile(data.contr, &data.profile);
			if (cdev->errcode)
				return -EIO;
L
Linus Torvalds 已提交
819

820 821
			retval = copy_to_user(argp, &data.profile,
					      sizeof(data.profile));
L
Linus Torvalds 已提交
822
		}
823 824
		if (retval)
			return -EFAULT;
825
		return 0;
L
Linus Torvalds 已提交
826 827

	case CAPI_GET_MANUFACTURER:
828 829 830 831 832 833
		if (copy_from_user(&data.contr, argp,
				   sizeof(data.contr)))
			return -EFAULT;
		cdev->errcode = capi20_get_manufacturer(data.contr, data.manufacturer);
		if (cdev->errcode)
			return -EIO;
L
Linus Torvalds 已提交
834

835 836 837
		if (copy_to_user(argp, data.manufacturer,
				 sizeof(data.manufacturer)))
			return -EFAULT;
L
Linus Torvalds 已提交
838

839 840
		return 0;

L
Linus Torvalds 已提交
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	case CAPI_GET_ERRCODE:
		data.errcode = cdev->errcode;
		cdev->errcode = CAPI_NOERROR;
		if (arg) {
			if (copy_to_user(argp, &data.errcode,
					 sizeof(data.errcode)))
				return -EFAULT;
		}
		return data.errcode;

	case CAPI_INSTALLED:
		if (capi20_isinstalled() == CAPI_NOERROR)
			return 0;
		return -ENXIO;

856
	case CAPI_MANUFACTURER_CMD: {
857 858 859 860 861 862 863
		struct capi_manufacturer_cmd mcmd;
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;
		if (copy_from_user(&mcmd, argp, sizeof(mcmd)))
			return -EFAULT;
		return capi20_manufacturer(mcmd.cmd, mcmd.data);
	}
L
Linus Torvalds 已提交
864
	case CAPI_SET_FLAGS:
865 866 867 868 869
	case CAPI_CLR_FLAGS: {
		unsigned userflags;

		if (copy_from_user(&userflags, argp, sizeof(userflags)))
			return -EFAULT;
L
Linus Torvalds 已提交
870

871 872 873 874 875 876 877 878
		mutex_lock(&cdev->lock);
		if (cmd == CAPI_SET_FLAGS)
			cdev->userflags |= userflags;
		else
			cdev->userflags &= ~userflags;
		mutex_unlock(&cdev->lock);
		return 0;
	}
L
Linus Torvalds 已提交
879 880 881 882 883 884
	case CAPI_GET_FLAGS:
		if (copy_to_user(argp, &cdev->userflags,
				 sizeof(cdev->userflags)))
			return -EFAULT;
		return 0;

885 886 887 888 889
#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
	case CAPI_NCCI_OPENCOUNT:
		return 0;

#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
890 891 892 893
	case CAPI_NCCI_OPENCOUNT: {
		struct capincci *nccip;
		unsigned ncci;
		int count = 0;
L
Linus Torvalds 已提交
894

895 896 897 898 899 900 901 902 903 904
		if (copy_from_user(&ncci, argp, sizeof(ncci)))
			return -EFAULT;

		mutex_lock(&cdev->lock);
		nccip = capincci_find(cdev, (u32)ncci);
		if (nccip)
			count = capincci_minor_opencount(nccip);
		mutex_unlock(&cdev->lock);
		return count;
	}
L
Linus Torvalds 已提交
905

906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
	case CAPI_NCCI_GETUNIT: {
		struct capincci *nccip;
		struct capiminor *mp;
		unsigned ncci;
		int unit = -ESRCH;

		if (copy_from_user(&ncci, argp, sizeof(ncci)))
			return -EFAULT;

		mutex_lock(&cdev->lock);
		nccip = capincci_find(cdev, (u32)ncci);
		if (nccip) {
			mp = nccip->minorp;
			if (mp)
				unit = mp->minor;
L
Linus Torvalds 已提交
921
		}
922 923 924
		mutex_unlock(&cdev->lock);
		return unit;
	}
L
Linus Torvalds 已提交
925
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
926 927 928

	default:
		return -EINVAL;
L
Linus Torvalds 已提交
929 930 931
	}
}

932 933 934 935 936
static long
capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int ret;

937
	mutex_lock(&capi_mutex);
938
	ret = capi_ioctl(file, cmd, arg);
939
	mutex_unlock(&capi_mutex);
940 941 942 943

	return ret;
}

J
Jan Kiszka 已提交
944
static int capi_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
945
{
J
Jan Kiszka 已提交
946 947 948 949 950 951
	struct capidev *cdev;

	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
	if (!cdev)
		return -ENOMEM;

952
	mutex_init(&cdev->lock);
J
Jan Kiszka 已提交
953 954
	skb_queue_head_init(&cdev->recvqueue);
	init_waitqueue_head(&cdev->recvwait);
955
	INIT_LIST_HEAD(&cdev->nccis);
J
Jan Kiszka 已提交
956 957 958 959 960 961 962
	file->private_data = cdev;

	mutex_lock(&capidev_list_lock);
	list_add_tail(&cdev->list, &capidev_list);
	mutex_unlock(&capidev_list_lock);

	return nonseekable_open(inode, file);
L
Linus Torvalds 已提交
963 964
}

J
Jan Kiszka 已提交
965
static int capi_release(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
966
{
J
Jan Kiszka 已提交
967
	struct capidev *cdev = file->private_data;
L
Linus Torvalds 已提交
968

J
Jan Kiszka 已提交
969 970 971 972
	mutex_lock(&capidev_list_lock);
	list_del(&cdev->list);
	mutex_unlock(&capidev_list_lock);

973
	if (cdev->ap.applid)
J
Jan Kiszka 已提交
974 975 976 977 978
		capi20_release(&cdev->ap);
	skb_queue_purge(&cdev->recvqueue);
	capincci_free(cdev, 0xffffffff);

	kfree(cdev);
L
Linus Torvalds 已提交
979 980 981
	return 0;
}

982
static const struct file_operations capi_fops =
L
Linus Torvalds 已提交
983 984 985 986 987 988
{
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= capi_read,
	.write		= capi_write,
	.poll		= capi_poll,
989
	.unlocked_ioctl	= capi_unlocked_ioctl,
L
Linus Torvalds 已提交
990 991 992 993 994 995 996
	.open		= capi_open,
	.release	= capi_release,
};

#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
/* -------- tty_operations for capincci ----------------------------- */

997 998
static int
capinc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
L
Linus Torvalds 已提交
999
{
1000
	struct capiminor *mp = capiminor_get(tty->index);
J
Jiri Slaby 已提交
1001
	int ret = tty_standard_install(driver, tty);
1002

J
Jiri Slaby 已提交
1003
	if (ret == 0)
1004
		tty->driver_data = mp;
J
Jiri Slaby 已提交
1005
	else
1006 1007 1008
		capiminor_put(mp);
	return ret;
}
L
Linus Torvalds 已提交
1009

1010 1011 1012 1013 1014 1015
static void capinc_tty_cleanup(struct tty_struct *tty)
{
	struct capiminor *mp = tty->driver_data;
	tty->driver_data = NULL;
	capiminor_put(mp);
}
L
Linus Torvalds 已提交
1016

1017
static int capinc_tty_open(struct tty_struct *tty, struct file *filp)
1018 1019
{
	struct capiminor *mp = tty->driver_data;
1020 1021 1022 1023 1024
	int err;

	err = tty_port_open(&mp->port, tty, filp);
	if (err)
		return err;
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029

	handle_minor_recv(mp);
	return 0;
}

1030
static void capinc_tty_close(struct tty_struct *tty, struct file *filp)
L
Linus Torvalds 已提交
1031
{
1032
	struct capiminor *mp = tty->driver_data;
L
Linus Torvalds 已提交
1033

1034
	tty_port_close(&mp->port, tty, filp);
L
Linus Torvalds 已提交
1035 1036
}

1037
static int capinc_tty_write(struct tty_struct *tty,
L
Linus Torvalds 已提交
1038 1039
			    const unsigned char *buf, int count)
{
1040
	struct capiminor *mp = tty->driver_data;
L
Linus Torvalds 已提交
1041 1042
	struct sk_buff *skb;

1043
	pr_debug("capinc_tty_write(count=%d)\n", count);
L
Linus Torvalds 已提交
1044

1045 1046
	spin_lock_bh(&mp->outlock);
	skb = mp->outskb;
L
Linus Torvalds 已提交
1047
	if (skb) {
1048 1049
		mp->outskb = NULL;
		__skb_queue_tail(&mp->outqueue, skb);
L
Linus Torvalds 已提交
1050 1051 1052
		mp->outbytes += skb->len;
	}

1053
	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + count, GFP_ATOMIC);
L
Linus Torvalds 已提交
1054 1055
	if (!skb) {
		printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
1056
		spin_unlock_bh(&mp->outlock);
L
Linus Torvalds 已提交
1057 1058 1059 1060 1061 1062
		return -ENOMEM;
	}

	skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
	memcpy(skb_put(skb, count), buf, count);

1063
	__skb_queue_tail(&mp->outqueue, skb);
L
Linus Torvalds 已提交
1064
	mp->outbytes += skb->len;
1065 1066
	spin_unlock_bh(&mp->outlock);

1067
	handle_minor_send(mp);
1068

L
Linus Torvalds 已提交
1069 1070 1071
	return count;
}

A
Alan Cox 已提交
1072
static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
L
Linus Torvalds 已提交
1073
{
1074
	struct capiminor *mp = tty->driver_data;
1075
	bool invoke_send = false;
L
Linus Torvalds 已提交
1076
	struct sk_buff *skb;
A
Alan Cox 已提交
1077
	int ret = 1;
L
Linus Torvalds 已提交
1078

1079
	pr_debug("capinc_put_char(%u)\n", ch);
L
Linus Torvalds 已提交
1080

1081 1082
	spin_lock_bh(&mp->outlock);
	skb = mp->outskb;
L
Linus Torvalds 已提交
1083 1084 1085
	if (skb) {
		if (skb_tailroom(skb) > 0) {
			*(skb_put(skb, 1)) = ch;
1086
			goto unlock_out;
L
Linus Torvalds 已提交
1087
		}
1088 1089
		mp->outskb = NULL;
		__skb_queue_tail(&mp->outqueue, skb);
L
Linus Torvalds 已提交
1090
		mp->outbytes += skb->len;
1091
		invoke_send = true;
L
Linus Torvalds 已提交
1092
	}
1093

1094
	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN + CAPI_MAX_BLKSIZE, GFP_ATOMIC);
L
Linus Torvalds 已提交
1095 1096 1097
	if (skb) {
		skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
		*(skb_put(skb, 1)) = ch;
1098
		mp->outskb = skb;
L
Linus Torvalds 已提交
1099 1100
	} else {
		printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
A
Alan Cox 已提交
1101
		ret = 0;
L
Linus Torvalds 已提交
1102
	}
1103 1104 1105 1106 1107

unlock_out:
	spin_unlock_bh(&mp->outlock);

	if (invoke_send)
1108
		handle_minor_send(mp);
1109

A
Alan Cox 已提交
1110
	return ret;
L
Linus Torvalds 已提交
1111 1112 1113 1114
}

static void capinc_tty_flush_chars(struct tty_struct *tty)
{
1115
	struct capiminor *mp = tty->driver_data;
L
Linus Torvalds 已提交
1116 1117
	struct sk_buff *skb;

1118
	pr_debug("capinc_tty_flush_chars\n");
L
Linus Torvalds 已提交
1119

1120 1121
	spin_lock_bh(&mp->outlock);
	skb = mp->outskb;
L
Linus Torvalds 已提交
1122
	if (skb) {
1123 1124
		mp->outskb = NULL;
		__skb_queue_tail(&mp->outqueue, skb);
L
Linus Torvalds 已提交
1125
		mp->outbytes += skb->len;
1126 1127
		spin_unlock_bh(&mp->outlock);

1128
		handle_minor_send(mp);
1129 1130 1131 1132
	} else
		spin_unlock_bh(&mp->outlock);

	handle_minor_recv(mp);
L
Linus Torvalds 已提交
1133 1134 1135 1136
}

static int capinc_tty_write_room(struct tty_struct *tty)
{
1137
	struct capiminor *mp = tty->driver_data;
L
Linus Torvalds 已提交
1138
	int room;
1139

L
Linus Torvalds 已提交
1140 1141
	room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
	room *= CAPI_MAX_BLKSIZE;
1142
	pr_debug("capinc_tty_write_room = %d\n", room);
L
Linus Torvalds 已提交
1143 1144 1145
	return room;
}

A
Adrian Bunk 已提交
1146
static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
L
Linus Torvalds 已提交
1147
{
1148 1149
	struct capiminor *mp = tty->driver_data;

1150 1151 1152 1153
	pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
		 mp->outbytes, mp->nack,
		 skb_queue_len(&mp->outqueue),
		 skb_queue_len(&mp->inqueue));
L
Linus Torvalds 已提交
1154 1155 1156
	return mp->outbytes;
}

1157
static int capinc_tty_ioctl(struct tty_struct *tty,
1158
			    unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
1159
{
1160
	return -ENOIOCTLCMD;
L
Linus Torvalds 已提交
1161 1162
}

1163
static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
L
Linus Torvalds 已提交
1164
{
1165
	pr_debug("capinc_tty_set_termios\n");
L
Linus Torvalds 已提交
1166 1167
}

1168
static void capinc_tty_throttle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1169
{
1170
	struct capiminor *mp = tty->driver_data;
1171
	pr_debug("capinc_tty_throttle\n");
1172
	mp->ttyinstop = 1;
L
Linus Torvalds 已提交
1173 1174
}

1175
static void capinc_tty_unthrottle(struct tty_struct *tty)
L
Linus Torvalds 已提交
1176
{
1177 1178
	struct capiminor *mp = tty->driver_data;

1179
	pr_debug("capinc_tty_unthrottle\n");
1180 1181
	mp->ttyinstop = 0;
	handle_minor_recv(mp);
L
Linus Torvalds 已提交
1182 1183 1184 1185
}

static void capinc_tty_stop(struct tty_struct *tty)
{
1186 1187
	struct capiminor *mp = tty->driver_data;

1188
	pr_debug("capinc_tty_stop\n");
1189
	mp->ttyoutstop = 1;
L
Linus Torvalds 已提交
1190 1191 1192 1193
}

static void capinc_tty_start(struct tty_struct *tty)
{
1194 1195
	struct capiminor *mp = tty->driver_data;

1196
	pr_debug("capinc_tty_start\n");
1197
	mp->ttyoutstop = 0;
1198
	handle_minor_send(mp);
L
Linus Torvalds 已提交
1199 1200 1201 1202
}

static void capinc_tty_hangup(struct tty_struct *tty)
{
1203 1204
	struct capiminor *mp = tty->driver_data;

1205
	pr_debug("capinc_tty_hangup\n");
1206
	tty_port_hangup(&mp->port);
L
Linus Torvalds 已提交
1207 1208
}

A
Alan Cox 已提交
1209
static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
L
Linus Torvalds 已提交
1210
{
1211
	pr_debug("capinc_tty_break_ctl(%d)\n", state);
A
Alan Cox 已提交
1212
	return 0;
L
Linus Torvalds 已提交
1213 1214 1215 1216
}

static void capinc_tty_flush_buffer(struct tty_struct *tty)
{
1217
	pr_debug("capinc_tty_flush_buffer\n");
L
Linus Torvalds 已提交
1218 1219 1220 1221
}

static void capinc_tty_set_ldisc(struct tty_struct *tty)
{
1222
	pr_debug("capinc_tty_set_ldisc\n");
L
Linus Torvalds 已提交
1223 1224 1225 1226
}

static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
{
1227
	pr_debug("capinc_tty_send_xchar(%d)\n", ch);
L
Linus Torvalds 已提交
1228 1229
}

J
Jeff Dike 已提交
1230
static const struct tty_operations capinc_ops = {
L
Linus Torvalds 已提交
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
	.open = capinc_tty_open,
	.close = capinc_tty_close,
	.write = capinc_tty_write,
	.put_char = capinc_tty_put_char,
	.flush_chars = capinc_tty_flush_chars,
	.write_room = capinc_tty_write_room,
	.chars_in_buffer = capinc_tty_chars_in_buffer,
	.ioctl = capinc_tty_ioctl,
	.set_termios = capinc_tty_set_termios,
	.throttle = capinc_tty_throttle,
	.unthrottle = capinc_tty_unthrottle,
	.stop = capinc_tty_stop,
	.start = capinc_tty_start,
	.hangup = capinc_tty_hangup,
	.break_ctl = capinc_tty_break_ctl,
	.flush_buffer = capinc_tty_flush_buffer,
	.set_ldisc = capinc_tty_set_ldisc,
	.send_xchar = capinc_tty_send_xchar,
1249 1250
	.install = capinc_tty_install,
	.cleanup = capinc_tty_cleanup,
L
Linus Torvalds 已提交
1251 1252
};

J
Jan Kiszka 已提交
1253
static int __init capinc_tty_init(void)
L
Linus Torvalds 已提交
1254 1255
{
	struct tty_driver *drv;
J
Jan Kiszka 已提交
1256 1257
	int err;

L
Linus Torvalds 已提交
1258 1259 1260 1261 1262
	if (capi_ttyminors > CAPINC_MAX_PORTS)
		capi_ttyminors = CAPINC_MAX_PORTS;
	if (capi_ttyminors <= 0)
		capi_ttyminors = CAPINC_NR_PORTS;

1263 1264 1265
	capiminors = kzalloc(sizeof(struct capi_minor *) * capi_ttyminors,
			     GFP_KERNEL);
	if (!capiminors)
L
Linus Torvalds 已提交
1266 1267
		return -ENOMEM;

1268 1269 1270 1271 1272
	drv = alloc_tty_driver(capi_ttyminors);
	if (!drv) {
		kfree(capiminors);
		return -ENOMEM;
	}
L
Linus Torvalds 已提交
1273
	drv->driver_name = "capi_nc";
1274
	drv->name = "capi!";
1275
	drv->major = 0;
L
Linus Torvalds 已提交
1276 1277 1278 1279 1280 1281 1282 1283
	drv->minor_start = 0;
	drv->type = TTY_DRIVER_TYPE_SERIAL;
	drv->subtype = SERIAL_TYPE_NORMAL;
	drv->init_termios = tty_std_termios;
	drv->init_termios.c_iflag = ICRNL;
	drv->init_termios.c_oflag = OPOST | ONLCR;
	drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	drv->init_termios.c_lflag = 0;
1284 1285 1286
	drv->flags =
		TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS |
		TTY_DRIVER_DYNAMIC_DEV;
L
Linus Torvalds 已提交
1287
	tty_set_operations(drv, &capinc_ops);
J
Jan Kiszka 已提交
1288 1289 1290

	err = tty_register_driver(drv);
	if (err) {
L
Linus Torvalds 已提交
1291
		put_tty_driver(drv);
1292
		kfree(capiminors);
L
Linus Torvalds 已提交
1293
		printk(KERN_ERR "Couldn't register capi_nc driver\n");
J
Jan Kiszka 已提交
1294
		return err;
L
Linus Torvalds 已提交
1295 1296 1297 1298 1299
	}
	capinc_tty_driver = drv;
	return 0;
}

J
Jan Kiszka 已提交
1300
static void __exit capinc_tty_exit(void)
L
Linus Torvalds 已提交
1301
{
J
Jan Kiszka 已提交
1302 1303
	tty_unregister_driver(capinc_tty_driver);
	put_tty_driver(capinc_tty_driver);
1304
	kfree(capiminors);
L
Linus Torvalds 已提交
1305 1306
}

1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
#else /* !CONFIG_ISDN_CAPI_MIDDLEWARE */

static inline int capinc_tty_init(void)
{
	return 0;
}

static inline void capinc_tty_exit(void) { }

#endif /* !CONFIG_ISDN_CAPI_MIDDLEWARE */
L
Linus Torvalds 已提交
1317 1318 1319 1320 1321 1322 1323

/* -------- /proc functions ----------------------------------------- */

/*
 * /proc/capi/capi20:
 *  minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
 */
1324
static int capi20_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
1325
{
1326
	struct capidev *cdev;
L
Linus Torvalds 已提交
1327 1328
	struct list_head *l;

1329
	mutex_lock(&capidev_list_lock);
L
Linus Torvalds 已提交
1330 1331
	list_for_each(l, &capidev_list) {
		cdev = list_entry(l, struct capidev, list);
1332
		seq_printf(m, "0 %d %lu %lu %lu %lu\n",
1333 1334 1335 1336 1337
			   cdev->ap.applid,
			   cdev->ap.nrecvctlpkt,
			   cdev->ap.nrecvdatapkt,
			   cdev->ap.nsentctlpkt,
			   cdev->ap.nsentdatapkt);
L
Linus Torvalds 已提交
1338
	}
1339
	mutex_unlock(&capidev_list_lock);
1340
	return 0;
L
Linus Torvalds 已提交
1341 1342
}

1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
static int capi20_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, capi20_proc_show, NULL);
}

static const struct file_operations capi20_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= capi20_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

L
Linus Torvalds 已提交
1356 1357 1358 1359
/*
 * /proc/capi/capi20ncci:
 *  applid ncci
 */
1360
static int capi20ncci_proc_show(struct seq_file *m, void *v)
L
Linus Torvalds 已提交
1361
{
1362 1363
	struct capidev *cdev;
	struct capincci *np;
L
Linus Torvalds 已提交
1364

1365
	mutex_lock(&capidev_list_lock);
1366
	list_for_each_entry(cdev, &capidev_list, list) {
1367
		mutex_lock(&cdev->lock);
1368 1369
		list_for_each_entry(np, &cdev->nccis, list)
			seq_printf(m, "%d 0x%x\n", cdev->ap.applid, np->ncci);
1370
		mutex_unlock(&cdev->lock);
L
Linus Torvalds 已提交
1371
	}
1372
	mutex_unlock(&capidev_list_lock);
1373
	return 0;
L
Linus Torvalds 已提交
1374 1375
}

1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
static int capi20ncci_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, capi20ncci_proc_show, NULL);
}

static const struct file_operations capi20ncci_proc_fops = {
	.owner		= THIS_MODULE,
	.open		= capi20ncci_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
L
Linus Torvalds 已提交
1387 1388 1389 1390
};

static void __init proc_init(void)
{
1391 1392
	proc_create("capi/capi20", 0, NULL, &capi20_proc_fops);
	proc_create("capi/capi20ncci", 0, NULL, &capi20ncci_proc_fops);
L
Linus Torvalds 已提交
1393 1394 1395 1396
}

static void __exit proc_exit(void)
{
1397 1398
	remove_proc_entry("capi/capi20", NULL);
	remove_proc_entry("capi/capi20ncci", NULL);
L
Linus Torvalds 已提交
1399 1400 1401 1402 1403 1404 1405
}

/* -------- init function and module interface ---------------------- */


static int __init capi_init(void)
{
1406
	const char *compileinfo;
1407
	int major_ret;
L
Linus Torvalds 已提交
1408

1409 1410
	major_ret = register_chrdev(capi_major, "capi20", &capi_fops);
	if (major_ret < 0) {
L
Linus Torvalds 已提交
1411
		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
1412
		return major_ret;
L
Linus Torvalds 已提交
1413
	}
1414
	capi_class = class_create(THIS_MODULE, "capi");
L
Linus Torvalds 已提交
1415 1416 1417 1418 1419
	if (IS_ERR(capi_class)) {
		unregister_chrdev(capi_major, "capi20");
		return PTR_ERR(capi_class);
	}

1420
	device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi20");
L
Linus Torvalds 已提交
1421 1422

	if (capinc_tty_init() < 0) {
1423
		device_destroy(capi_class, MKDEV(capi_major, 0));
1424
		class_destroy(capi_class);
L
Linus Torvalds 已提交
1425 1426 1427 1428 1429 1430
		unregister_chrdev(capi_major, "capi20");
		return -ENOMEM;
	}

	proc_init();

1431
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
1432
	compileinfo = " (middleware)";
L
Linus Torvalds 已提交
1433
#else
1434
	compileinfo = " (no middleware)";
L
Linus Torvalds 已提交
1435
#endif
1436 1437
	printk(KERN_NOTICE "CAPI 2.0 started up with major %d%s\n",
	       capi_major, compileinfo);
L
Linus Torvalds 已提交
1438 1439 1440 1441 1442 1443 1444 1445

	return 0;
}

static void __exit capi_exit(void)
{
	proc_exit();

1446
	device_destroy(capi_class, MKDEV(capi_major, 0));
1447
	class_destroy(capi_class);
L
Linus Torvalds 已提交
1448 1449 1450 1451 1452 1453 1454
	unregister_chrdev(capi_major, "capi20");

	capinc_tty_exit();
}

module_init(capi_init);
module_exit(capi_exit);