dvb_ca_en50221.c 46.9 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 21 22 23
/*
 * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
 *
 * Copyright (C) 2004 Andrew de Quincey
 *
 * Parts of this file were based on sources as follows:
 *
 * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
 *
 * based on code:
 *
 * Copyright (C) 1999-2002 Ralph  Metzler
 *                       & Marcus Metzler for convergence integrated media GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
24 25
 * To obtain the license, point your browser to
 * http://www.gnu.org/copyleft/gpl.html
L
Linus Torvalds 已提交
26 27
 */

28 29
#define pr_fmt(fmt) "dvb_ca_en50221: " fmt

L
Linus Torvalds 已提交
30 31 32 33 34 35
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
36
#include <linux/spinlock.h>
37
#include <linux/sched/signal.h>
38
#include <linux/kthread.h>
L
Linus Torvalds 已提交
39 40 41 42 43 44 45 46 47

#include "dvb_ca_en50221.h"
#include "dvb_ringbuffer.h"

static int dvb_ca_en50221_debug;

module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");

48 49 50 51
#define dprintk(fmt, arg...) do {					\
	if (dvb_ca_en50221_debug)					\
		printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg);\
} while (0)
L
Linus Torvalds 已提交
52

53
#define INIT_TIMEOUT_SECS 10
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

#define HOST_LINK_BUF_SIZE 0x200

#define RX_BUFFER_SIZE 65535

#define MAX_RX_PACKETS_PER_ITERATION 10

#define CTRLIF_DATA      0
#define CTRLIF_COMMAND   1
#define CTRLIF_STATUS    1
#define CTRLIF_SIZE_LOW  2
#define CTRLIF_SIZE_HIGH 3

#define CMDREG_HC        1	/* Host control */
#define CMDREG_SW        2	/* Size write */
#define CMDREG_SR        4	/* Size read */
#define CMDREG_RS        8	/* Reset interface */
#define CMDREG_FRIE   0x40	/* Enable FR interrupt */
#define CMDREG_DAIE   0x80	/* Enable DA interrupt */
#define IRQEN (CMDREG_DAIE)

#define STATUSREG_RE     1	/* read error */
#define STATUSREG_WE     2	/* write error */
#define STATUSREG_FR  0x40	/* module free */
#define STATUSREG_DA  0x80	/* data available */

#define DVB_CA_SLOTSTATE_NONE           0
#define DVB_CA_SLOTSTATE_UNINITIALISED  1
#define DVB_CA_SLOTSTATE_RUNNING        2
#define DVB_CA_SLOTSTATE_INVALID        3
#define DVB_CA_SLOTSTATE_WAITREADY      4
#define DVB_CA_SLOTSTATE_VALIDATE       5
#define DVB_CA_SLOTSTATE_WAITFR         6
#define DVB_CA_SLOTSTATE_LINKINIT       7


/* Information on a CA slot */
struct dvb_ca_slot {

	/* current state of the CAM */
	int slot_state;

96 97 98
	/* mutex used for serializing access to one CI slot */
	struct mutex slot_lock;

L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	/* Number of CAMCHANGES that have occurred since last processing */
	atomic_t camchange_count;

	/* Type of last CAMCHANGE */
	int camchange_type;

	/* base address of CAM config */
	u32 config_base;

	/* value to write into Config Control register */
	u8 config_option;

	/* if 1, the CAM supports DA IRQs */
	u8 da_irq_supported:1;

	/* size of the buffer to use when talking to the CAM */
	int link_buf_size;

	/* buffer for incoming packets */
	struct dvb_ringbuffer rx_buffer;

	/* timer used during various states of the slot */
	unsigned long timeout;
};

/* Private CA-interface information */
struct dvb_ca_private {
126
	struct kref refcount;
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146

	/* pointer back to the public data structure */
	struct dvb_ca_en50221 *pub;

	/* the DVB device */
	struct dvb_device *dvbdev;

	/* Flags describing the interface (DVB_CA_FLAG_*) */
	u32 flags;

	/* number of slots supported by this CA interface */
	unsigned int slot_count;

	/* information on each slot */
	struct dvb_ca_slot *slot_info;

	/* wait queues for read() and write() operations */
	wait_queue_head_t wait_queue;

	/* PID of the monitoring thread */
147
	struct task_struct *thread;
L
Linus Torvalds 已提交
148 149 150 151 152 153 154 155 156 157 158 159

	/* Flag indicating if the CA device is open */
	unsigned int open:1;

	/* Flag indicating the thread should wake up now */
	unsigned int wakeup:1;

	/* Delay the main thread should use */
	unsigned long delay;

	/* Slot to start looking for data to read from in the next user-space read operation */
	int next_read_slot;
160 161 162

	/* mutex serializing ioctls */
	struct mutex ioctl_mutex;
L
Linus Torvalds 已提交
163 164
};

165 166 167 168
static void dvb_ca_private_free(struct dvb_ca_private *ca)
{
	unsigned int i;

169
	dvb_free_device(ca->dvbdev);
170 171 172 173 174 175 176
	for (i = 0; i < ca->slot_count; i++)
		vfree(ca->slot_info[i].rx_buffer.data);

	kfree(ca->slot_info);
	kfree(ca);
}

177 178
static void dvb_ca_private_release(struct kref *ref)
{
179 180 181
	struct dvb_ca_private *ca;

	ca = container_of(ref, struct dvb_ca_private, refcount);
182 183 184 185 186 187 188 189 190 191 192 193 194
	dvb_ca_private_free(ca);
}

static void dvb_ca_private_get(struct dvb_ca_private *ca)
{
	kref_get(&ca->refcount);
}

static void dvb_ca_private_put(struct dvb_ca_private *ca)
{
	kref_put(&ca->refcount, dvb_ca_private_release);
}

L
Linus Torvalds 已提交
195
static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
196 197 198 199
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
				    u8 *ebuf, int ecount);
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
				     u8 *ebuf, int ecount);
L
Linus Torvalds 已提交
200 201 202 203 204


/**
 * Safely find needle in haystack.
 *
205 206 207 208
 * @haystack: Buffer to look in.
 * @hlen: Number of bytes in haystack.
 * @needle: Buffer to find.
 * @nlen: Number of bytes in needle.
L
Linus Torvalds 已提交
209 210
 * @return Pointer into haystack needle was found at, or NULL if not found.
 */
211
static char *findstr(char *haystack, int hlen, char *needle, int nlen)
L
Linus Torvalds 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
{
	int i;

	if (hlen < nlen)
		return NULL;

	for (i = 0; i <= hlen - nlen; i++) {
		if (!strncmp(haystack + i, needle, nlen))
			return haystack + i;
	}

	return NULL;
}



/* ******************************************************************************** */
/* EN50221 physical interface functions */


/**
233
 * dvb_ca_en50221_check_camstatus - Check CAM status.
L
Linus Torvalds 已提交
234 235 236
 */
static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
{
237
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
238 239 240 241 242
	int slot_status;
	int cam_present_now;
	int cam_changed;

	/* IRQ mode */
243
	if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
244
		return (atomic_read(&sl->camchange_count) != 0);
L
Linus Torvalds 已提交
245 246 247 248 249 250 251

	/* poll mode */
	slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);

	cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
	cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
	if (!cam_changed) {
252 253
		int cam_present_old = (sl->slot_state != DVB_CA_SLOTSTATE_NONE);

L
Linus Torvalds 已提交
254 255 256 257
		cam_changed = (cam_present_now != cam_present_old);
	}

	if (cam_changed) {
258
		if (!cam_present_now)
259
			sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
260
		else
261 262
			sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
		atomic_set(&sl->camchange_count, 1);
L
Linus Torvalds 已提交
263
	} else {
264
		if ((sl->slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
L
Linus Torvalds 已提交
265
		    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
266
			/* move to validate state if reset is completed */
267
			sl->slot_state = DVB_CA_SLOTSTATE_VALIDATE;
L
Linus Torvalds 已提交
268 269 270 271 272 273 274 275
		}
	}

	return cam_changed;
}


/**
276 277
 * dvb_ca_en50221_wait_if_status - Wait for flags to become set on the STATUS
 *	 register on a CAM interface, checking for errors and timeout.
L
Linus Torvalds 已提交
278
 *
279 280 281 282
 * @ca: CA instance.
 * @slot: Slot on interface.
 * @waitfor: Flags to wait for.
 * @timeout_ms: Timeout in milliseconds.
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291
 *
 * @return 0 on success, nonzero on error.
 */
static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
					 u8 waitfor, int timeout_hz)
{
	unsigned long timeout;
	unsigned long start;

292
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
293 294 295 296 297

	/* loop until timeout elapsed */
	start = jiffies;
	timeout = jiffies + timeout_hz;
	while (1) {
298 299
		int res;

L
Linus Torvalds 已提交
300
		/* read the status and check for error */
301
		res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
L
Linus Torvalds 已提交
302 303 304 305 306
		if (res < 0)
			return -EIO;

		/* if we got the flags, it was successful! */
		if (res & waitfor) {
307 308
			dprintk("%s succeeded timeout:%lu\n",
				__func__, jiffies - start);
L
Linus Torvalds 已提交
309 310 311 312
			return 0;
		}

		/* check for timeout */
313
		if (time_after(jiffies, timeout))
L
Linus Torvalds 已提交
314 315 316
			break;

		/* wait for a bit */
317
		usleep_range(1000, 1100);
L
Linus Torvalds 已提交
318 319
	}

320
	dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
L
Linus Torvalds 已提交
321 322 323 324 325 326 327

	/* if we get here, we've timed out */
	return -ETIMEDOUT;
}


/**
328
 * dvb_ca_en50221_link_init - Initialise the link layer connection to a CAM.
L
Linus Torvalds 已提交
329
 *
330 331
 * @ca: CA instance.
 * @slot: Slot id.
L
Linus Torvalds 已提交
332 333 334 335 336
 *
 * @return 0 on success, nonzero on failure.
 */
static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
{
337
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
338 339 340 341
	int ret;
	int buf_size;
	u8 buf[2];

342
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
343 344

	/* we'll be determining these during this function */
345
	sl->da_irq_supported = 0;
L
Linus Torvalds 已提交
346

347 348 349 350
	/*
	 * set the host link buffer size temporarily. it will be overwritten
	 * with the real negotiated size later.
	 */
351
	sl->link_buf_size = 2;
L
Linus Torvalds 已提交
352 353

	/* read the buffer size from the CAM */
354 355 356
	ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
					 IRQEN | CMDREG_SR);
	if (ret)
L
Linus Torvalds 已提交
357
		return ret;
358
	ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ);
359
	if (ret)
L
Linus Torvalds 已提交
360
		return ret;
361 362
	ret = dvb_ca_en50221_read_data(ca, slot, buf, 2);
	if (ret != 2)
L
Linus Torvalds 已提交
363
		return -EIO;
364 365
	ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
	if (ret)
L
Linus Torvalds 已提交
366 367 368 369 370 371
		return ret;

	/* store it, and choose the minimum of our buffer and the CAM's buffer size */
	buf_size = (buf[0] << 8) | buf[1];
	if (buf_size > HOST_LINK_BUF_SIZE)
		buf_size = HOST_LINK_BUF_SIZE;
372
	sl->link_buf_size = buf_size;
L
Linus Torvalds 已提交
373 374 375 376 377
	buf[0] = buf_size >> 8;
	buf[1] = buf_size & 0xff;
	dprintk("Chosen link buffer size of %i\n", buf_size);

	/* write the buffer size to the CAM */
378 379 380
	ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
					 IRQEN | CMDREG_SW);
	if (ret)
L
Linus Torvalds 已提交
381
		return ret;
382 383
	ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10);
	if (ret)
L
Linus Torvalds 已提交
384
		return ret;
385 386
	ret = dvb_ca_en50221_write_data(ca, slot, buf, 2);
	if (ret != 2)
L
Linus Torvalds 已提交
387
		return -EIO;
388 389
	ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
	if (ret)
L
Linus Torvalds 已提交
390 391 392 393 394 395 396
		return ret;

	/* success */
	return 0;
}

/**
397
 * dvb_ca_en50221_read_tuple - Read a tuple from attribute memory.
L
Linus Torvalds 已提交
398
 *
399 400 401 402 403 404
 * @ca: CA instance.
 * @slot: Slot id.
 * @address: Address to read from. Updated.
 * @tupleType: Tuple id byte. Updated.
 * @tupleLength: Tuple length. Updated.
 * @tuple: Dest buffer for tuple (must be 256 bytes). Updated.
L
Linus Torvalds 已提交
405 406 407 408
 *
 * @return 0 on success, nonzero on error.
 */
static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
409 410
				     int *address, int *tuple_type,
				     int *tuple_length, u8 *tuple)
L
Linus Torvalds 已提交
411 412
{
	int i;
413 414
	int _tuple_type;
	int _tuple_length;
L
Linus Torvalds 已提交
415 416 417
	int _address = *address;

	/* grab the next tuple length and type */
418 419 420 421 422
	_tuple_type = ca->pub->read_attribute_mem(ca->pub, slot, _address);
	if (_tuple_type < 0)
		return _tuple_type;
	if (_tuple_type == 0xff) {
		dprintk("END OF CHAIN TUPLE type:0x%x\n", _tuple_type);
L
Linus Torvalds 已提交
423
		*address += 2;
424 425
		*tuple_type = _tuple_type;
		*tuple_length = 0;
L
Linus Torvalds 已提交
426 427
		return 0;
	}
428 429 430 431
	_tuple_length = ca->pub->read_attribute_mem(ca->pub, slot,
						    _address + 2);
	if (_tuple_length < 0)
		return _tuple_length;
L
Linus Torvalds 已提交
432 433
	_address += 4;

434
	dprintk("TUPLE type:0x%x length:%i\n", _tuple_type, _tuple_length);
L
Linus Torvalds 已提交
435 436

	/* read in the whole tuple */
437
	for (i = 0; i < _tuple_length; i++) {
L
Linus Torvalds 已提交
438 439 440 441 442
		tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
		dprintk("  0x%02x: 0x%02x %c\n",
			i, tuple[i] & 0xff,
			((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
	}
443
	_address += (_tuple_length * 2);
L
Linus Torvalds 已提交
444

445
	/* success */
446 447
	*tuple_type = _tuple_type;
	*tuple_length = _tuple_length;
L
Linus Torvalds 已提交
448 449 450 451 452 453
	*address = _address;
	return 0;
}


/**
454 455
 * dvb_ca_en50221_parse_attributes - Parse attribute memory of a CAM module,
 *	extracting Config register, and checking it is a DVB CAM module.
L
Linus Torvalds 已提交
456
 *
457 458
 * @ca: CA instance.
 * @slot: Slot id.
L
Linus Torvalds 已提交
459 460 461 462 463
 *
 * @return 0 on success, <0 on failure.
 */
static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
{
464
	struct dvb_ca_slot *sl;
L
Linus Torvalds 已提交
465
	int address = 0;
466 467
	int tuple_length;
	int tuple_type;
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476 477 478
	u8 tuple[257];
	char *dvb_str;
	int rasz;
	int status;
	int got_cftableentry = 0;
	int end_chain = 0;
	int i;
	u16 manfid = 0;
	u16 devid = 0;


479
	/* CISTPL_DEVICE_0A */
480 481 482
	status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type,
					   &tuple_length, tuple);
	if (status < 0)
L
Linus Torvalds 已提交
483
		return status;
484
	if (tuple_type != 0x1D)
L
Linus Torvalds 已提交
485 486 487 488
		return -EINVAL;



489
	/* CISTPL_DEVICE_0C */
490 491 492
	status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type,
					   &tuple_length, tuple);
	if (status < 0)
L
Linus Torvalds 已提交
493
		return status;
494
	if (tuple_type != 0x1C)
L
Linus Torvalds 已提交
495 496 497 498
		return -EINVAL;



499
	/* CISTPL_VERS_1 */
500 501 502
	status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type,
					   &tuple_length, tuple);
	if (status < 0)
L
Linus Torvalds 已提交
503
		return status;
504
	if (tuple_type != 0x15)
L
Linus Torvalds 已提交
505 506 507 508
		return -EINVAL;



509
	/* CISTPL_MANFID */
510 511 512
	status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type,
					   &tuple_length, tuple);
	if (status < 0)
L
Linus Torvalds 已提交
513
		return status;
514
	if (tuple_type != 0x20)
L
Linus Torvalds 已提交
515
		return -EINVAL;
516
	if (tuple_length != 4)
L
Linus Torvalds 已提交
517 518 519 520 521 522
		return -EINVAL;
	manfid = (tuple[1] << 8) | tuple[0];
	devid = (tuple[3] << 8) | tuple[2];



523
	/* CISTPL_CONFIG */
524 525 526
	status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tuple_type,
					   &tuple_length, tuple);
	if (status < 0)
L
Linus Torvalds 已提交
527
		return status;
528
	if (tuple_type != 0x1A)
L
Linus Torvalds 已提交
529
		return -EINVAL;
530
	if (tuple_length < 3)
L
Linus Torvalds 已提交
531 532 533 534
		return -EINVAL;

	/* extract the configbase */
	rasz = tuple[0] & 3;
535
	if (tuple_length < (3 + rasz + 14))
L
Linus Torvalds 已提交
536
		return -EINVAL;
537 538 539 540
	sl = &ca->slot_info[slot];
	sl->config_base = 0;
	for (i = 0; i < rasz + 1; i++)
		sl->config_base |= (tuple[2 + i] << (8 * i));
L
Linus Torvalds 已提交
541 542

	/* check it contains the correct DVB string */
543
	dvb_str = findstr((char *)tuple, tuple_length, "DVB_CI_V", 8);
L
Linus Torvalds 已提交
544 545
	if (dvb_str == NULL)
		return -EINVAL;
546
	if (tuple_length < ((dvb_str - (char *)tuple) + 12))
L
Linus Torvalds 已提交
547 548 549 550
		return -EINVAL;

	/* is it a version we support? */
	if (strncmp(dvb_str + 8, "1.00", 4)) {
551 552 553
		pr_err("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
		       ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9],
		       dvb_str[10], dvb_str[11]);
L
Linus Torvalds 已提交
554 555 556 557 558
		return -EINVAL;
	}

	/* process the CFTABLE_ENTRY tuples, and any after those */
	while ((!end_chain) && (address < 0x1000)) {
559 560 561 562
		status = dvb_ca_en50221_read_tuple(ca, slot, &address,
						   &tuple_type, &tuple_length,
						   tuple);
		if (status < 0)
L
Linus Torvalds 已提交
563
			return status;
564
		switch (tuple_type) {
565
		case 0x1B:	/* CISTPL_CFTABLE_ENTRY */
566
			if (tuple_length < (2 + 11 + 17))
L
Linus Torvalds 已提交
567 568 569 570 571 572 573
				break;

			/* if we've already parsed one, just use it */
			if (got_cftableentry)
				break;

			/* get the config option */
574
			sl->config_option = tuple[0] & 0x3f;
L
Linus Torvalds 已提交
575 576

			/* OK, check it contains the correct strings */
577 578 579 580
			if (!findstr((char *)tuple, tuple_length,
				     "DVB_HOST", 8) ||
			    !findstr((char *)tuple, tuple_length,
				     "DVB_CI_MODULE", 13))
L
Linus Torvalds 已提交
581 582 583 584 585
				break;

			got_cftableentry = 1;
			break;

586
		case 0x14:	/* CISTPL_NO_LINK */
L
Linus Torvalds 已提交
587 588
			break;

589
		case 0xFF:	/* CISTPL_END */
L
Linus Torvalds 已提交
590 591 592 593
			end_chain = 1;
			break;

		default:	/* Unknown tuple type - just skip this tuple and move to the next one */
594
			dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n",
595
				tuple_type, tuple_length);
L
Linus Torvalds 已提交
596 597 598 599 600 601 602 603
			break;
		}
	}

	if ((address > 0x1000) || (!got_cftableentry))
		return -EINVAL;

	dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
604
		manfid, devid, sl->config_base, sl->config_option);
L
Linus Torvalds 已提交
605

606
	/* success! */
L
Linus Torvalds 已提交
607 608 609 610 611
	return 0;
}


/**
612
 * dvb_ca_en50221_set_configoption - Set CAM's configoption correctly.
L
Linus Torvalds 已提交
613
 *
614 615
 * @ca: CA instance.
 * @slot: Slot containing the CAM.
L
Linus Torvalds 已提交
616 617 618
 */
static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
{
619
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
620 621
	int configoption;

622
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
623 624

	/* set the config option */
625 626
	ca->pub->write_attribute_mem(ca->pub, slot, sl->config_base,
				     sl->config_option);
L
Linus Torvalds 已提交
627 628

	/* check it */
629 630
	configoption = ca->pub->read_attribute_mem(ca->pub, slot,
						   sl->config_base);
L
Linus Torvalds 已提交
631
	dprintk("Set configoption 0x%x, read configoption 0x%x\n",
632
		sl->config_option, configoption & 0x3f);
L
Linus Torvalds 已提交
633 634 635 636 637 638 639 640

	/* fine! */
	return 0;

}


/**
641 642 643 644
 * dvb_ca_en50221_read_data - This function talks to an EN50221 CAM control
 *	interface. It reads a buffer of data from the CAM. The data can either
 *	be stored in a supplied buffer, or automatically be added to the slot's
 *	rx_buffer.
L
Linus Torvalds 已提交
645
 *
646 647 648
 * @ca: CA instance.
 * @slot: Slot to read from.
 * @ebuf: If non-NULL, the data will be written to this buffer. If NULL,
L
Linus Torvalds 已提交
649
 * the data will be added into the buffering system as a normal fragment.
650
 * @ecount: Size of ebuf. Ignored if ebuf is NULL.
L
Linus Torvalds 已提交
651 652 653
 *
 * @return Number of bytes read, or < 0 on error
 */
654 655
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
				    u8 *ebuf, int ecount)
L
Linus Torvalds 已提交
656
{
657
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
658 659 660 661 662
	int bytes_read;
	int status;
	u8 buf[HOST_LINK_BUF_SIZE];
	int i;

663
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
664 665 666 667 668

	/* check if we have space for a link buf in the rx_buffer */
	if (ebuf == NULL) {
		int buf_free;

669
		if (!sl->rx_buffer.data) {
L
Linus Torvalds 已提交
670 671 672
			status = -EIO;
			goto exit;
		}
673
		buf_free = dvb_ringbuffer_free(&sl->rx_buffer);
L
Linus Torvalds 已提交
674

675
		if (buf_free < (sl->link_buf_size +
676
				DVB_RINGBUFFER_PKTHDRSIZE)) {
L
Linus Torvalds 已提交
677 678 679 680 681
			status = -EAGAIN;
			goto exit;
		}
	}

682
	if (ca->pub->read_data &&
683
	    (sl->slot_state != DVB_CA_SLOTSTATE_LINKINIT)) {
684 685 686 687 688 689 690 691 692 693 694
		if (ebuf == NULL)
			status = ca->pub->read_data(ca->pub, slot, buf,
						    sizeof(buf));
		else
			status = ca->pub->read_data(ca->pub, slot, buf, ecount);
		if (status < 0)
			return status;
		bytes_read =  status;
		if (status == 0)
			goto exit;
	} else {
L
Linus Torvalds 已提交
695

696 697 698 699
		/* check if there is data available */
		status = ca->pub->read_cam_control(ca->pub, slot,
						   CTRLIF_STATUS);
		if (status < 0)
L
Linus Torvalds 已提交
700
			goto exit;
701 702 703
		if (!(status & STATUSREG_DA)) {
			/* no data */
			status = 0;
L
Linus Torvalds 已提交
704 705
			goto exit;
		}
706 707 708 709 710 711 712 713 714 715

		/* read the amount of data */
		status = ca->pub->read_cam_control(ca->pub, slot,
						   CTRLIF_SIZE_HIGH);
		if (status < 0)
			goto exit;
		bytes_read = status << 8;
		status = ca->pub->read_cam_control(ca->pub, slot,
						   CTRLIF_SIZE_LOW);
		if (status < 0)
L
Linus Torvalds 已提交
716
			goto exit;
717 718 719 720
		bytes_read |= status;

		/* check it will fit */
		if (ebuf == NULL) {
721
			if (bytes_read > sl->link_buf_size) {
722 723
				pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
				       ca->dvbdev->adapter->num, bytes_read,
724 725
				       sl->link_buf_size);
				sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT;
726 727 728 729 730 731
				status = -EIO;
				goto exit;
			}
			if (bytes_read < 2) {
				pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
				       ca->dvbdev->adapter->num);
732
				sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT;
733 734 735 736 737 738 739 740 741 742
				status = -EIO;
				goto exit;
			}
		} else {
			if (bytes_read > ecount) {
				pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
				       ca->dvbdev->adapter->num);
				status = -EIO;
				goto exit;
			}
L
Linus Torvalds 已提交
743 744
		}

745 746 747 748 749 750 751
		/* fill the buffer */
		for (i = 0; i < bytes_read; i++) {
			/* read byte and check */
			status = ca->pub->read_cam_control(ca->pub, slot,
							   CTRLIF_DATA);
			if (status < 0)
				goto exit;
L
Linus Torvalds 已提交
752

753 754 755
			/* OK, store it in the buffer */
			buf[i] = status;
		}
L
Linus Torvalds 已提交
756

757 758 759 760 761 762
		/* check for read error (RE should now be 0) */
		status = ca->pub->read_cam_control(ca->pub, slot,
						   CTRLIF_STATUS);
		if (status < 0)
			goto exit;
		if (status & STATUSREG_RE) {
763
			sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT;
764 765 766
			status = -EIO;
			goto exit;
		}
L
Linus Torvalds 已提交
767 768 769 770
	}

	/* OK, add it to the receive buffer, or copy into external buffer if supplied */
	if (ebuf == NULL) {
771
		if (!sl->rx_buffer.data) {
L
Linus Torvalds 已提交
772 773 774
			status = -EIO;
			goto exit;
		}
775
		dvb_ringbuffer_pkt_write(&sl->rx_buffer, buf, bytes_read);
L
Linus Torvalds 已提交
776 777 778 779 780 781 782 783
	} else {
		memcpy(ebuf, buf, bytes_read);
	}

	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
		buf[0], (buf[1] & 0x80) == 0, bytes_read);

	/* wake up readers when a last_fragment is received */
784
	if ((buf[1] & 0x80) == 0x00)
L
Linus Torvalds 已提交
785
		wake_up_interruptible(&ca->wait_queue);
786

L
Linus Torvalds 已提交
787 788 789 790 791 792 793 794
	status = bytes_read;

exit:
	return status;
}


/**
795 796
 * dvb_ca_en50221_write_data - This function talks to an EN50221 CAM control
 *				interface. It writes a buffer of data to a CAM.
L
Linus Torvalds 已提交
797
 *
798 799 800
 * @ca: CA instance.
 * @slot: Slot to write to.
 * @ebuf: The data in this buffer is treated as a complete link-level packet to
L
Linus Torvalds 已提交
801
 * be written.
802
 * @count: Size of ebuf.
L
Linus Torvalds 已提交
803 804 805
 *
 * @return Number of bytes written, or < 0 on error.
 */
806 807
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
				     u8 *buf, int bytes_write)
L
Linus Torvalds 已提交
808
{
809
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
810 811 812
	int status;
	int i;

813
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
814 815


816
	/* sanity check */
817
	if (bytes_write > sl->link_buf_size)
L
Linus Torvalds 已提交
818 819
		return -EINVAL;

820
	if (ca->pub->write_data &&
821
	    (sl->slot_state != DVB_CA_SLOTSTATE_LINKINIT))
822 823
		return ca->pub->write_data(ca->pub, slot, buf, bytes_write);

824 825 826 827 828 829
	/*
	 * it is possible we are dealing with a single buffer implementation,
	 * thus if there is data available for read or if there is even a read
	 * already in progress, we do nothing but awake the kernel thread to
	 * process the data if necessary.
	 */
830 831
	status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
	if (status < 0)
L
Linus Torvalds 已提交
832 833
		goto exitnowrite;
	if (status & (STATUSREG_DA | STATUSREG_RE)) {
834 835 836
		if (status & STATUSREG_DA)
			dvb_ca_en50221_thread_wakeup(ca);

L
Linus Torvalds 已提交
837 838 839 840 841
		status = -EAGAIN;
		goto exitnowrite;
	}

	/* OK, set HC bit */
842 843 844
	status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
					    IRQEN | CMDREG_HC);
	if (status)
L
Linus Torvalds 已提交
845 846 847
		goto exit;

	/* check if interface is still free */
848 849
	status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
	if (status < 0)
L
Linus Torvalds 已提交
850 851 852 853 854 855 856
		goto exit;
	if (!(status & STATUSREG_FR)) {
		/* it wasn't free => try again later */
		status = -EAGAIN;
		goto exit;
	}

857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
	/*
	 * It may need some time for the CAM to settle down, or there might
	 * be a race condition between the CAM, writing HC and our last
	 * check for DA. This happens, if the CAM asserts DA, just after
	 * checking DA before we are setting HC. In this case it might be
	 * a bug in the CAM to keep the FR bit, the lower layer/HW
	 * communication requires a longer timeout or the CAM needs more
	 * time internally. But this happens in reality!
	 * We need to read the status from the HW again and do the same
	 * we did for the previous check for DA
	 */
	status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
	if (status < 0)
		goto exit;

	if (status & (STATUSREG_DA | STATUSREG_RE)) {
		if (status & STATUSREG_DA)
			dvb_ca_en50221_thread_wakeup(ca);

		status = -EAGAIN;
		goto exit;
	}

L
Linus Torvalds 已提交
880
	/* send the amount of data */
881 882 883
	status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH,
					    bytes_write >> 8);
	if (status)
L
Linus Torvalds 已提交
884
		goto exit;
885 886 887
	status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
					    bytes_write & 0xff);
	if (status)
L
Linus Torvalds 已提交
888 889 890 891
		goto exit;

	/* send the buffer */
	for (i = 0; i < bytes_write; i++) {
892 893 894
		status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA,
						    buf[i]);
		if (status)
L
Linus Torvalds 已提交
895 896 897 898
			goto exit;
	}

	/* check for write error (WE should now be 0) */
899 900
	status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
	if (status < 0)
L
Linus Torvalds 已提交
901 902
		goto exit;
	if (status & STATUSREG_WE) {
903
		sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT;
L
Linus Torvalds 已提交
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
		status = -EIO;
		goto exit;
	}
	status = bytes_write;

	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
		buf[0], (buf[1] & 0x80) == 0, bytes_write);

exit:
	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);

exitnowrite:
	return status;
}



/* ******************************************************************************** */
/* EN50221 higher level functions */


/**
926
 * dvb_ca_en50221_slot_shutdown - A CAM has been removed => shut it down.
L
Linus Torvalds 已提交
927
 *
928 929
 * @ca: CA instance.
 * @slot: Slot to shut down.
L
Linus Torvalds 已提交
930 931 932
 */
static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
{
933
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
934 935 936 937

	ca->pub->slot_shutdown(ca->pub, slot);
	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;

938 939 940 941
	/*
	 * need to wake up all processes to check if they're now trying to
	 * write to a defunct CAM
	 */
L
Linus Torvalds 已提交
942 943 944 945 946 947 948 949 950 951
	wake_up_interruptible(&ca->wait_queue);

	dprintk("Slot %i shutdown\n", slot);

	/* success */
	return 0;
}


/**
952
 * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
L
Linus Torvalds 已提交
953
 *
954 955 956
 * @ca: CA instance.
 * @slot: Slot concerned.
 * @change_type: One of the DVB_CA_CAMCHANGE_* values.
L
Linus Torvalds 已提交
957 958 959
 */
void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
{
960
	struct dvb_ca_private *ca = pubca->private;
961
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
962 963 964 965 966 967 968 969 970 971 972 973

	dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);

	switch (change_type) {
	case DVB_CA_EN50221_CAMCHANGE_REMOVED:
	case DVB_CA_EN50221_CAMCHANGE_INSERTED:
		break;

	default:
		return;
	}

974 975
	sl->camchange_type = change_type;
	atomic_inc(&sl->camchange_count);
L
Linus Torvalds 已提交
976 977
	dvb_ca_en50221_thread_wakeup(ca);
}
978
EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
L
Linus Torvalds 已提交
979 980 981


/**
982
 * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
L
Linus Torvalds 已提交
983
 *
984 985
 * @ca: CA instance.
 * @slot: Slot concerned.
L
Linus Torvalds 已提交
986 987 988
 */
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
{
989
	struct dvb_ca_private *ca = pubca->private;
990
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
991 992 993

	dprintk("CAMREADY IRQ slot:%i\n", slot);

994 995
	if (sl->slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
		sl->slot_state = DVB_CA_SLOTSTATE_VALIDATE;
L
Linus Torvalds 已提交
996 997 998
		dvb_ca_en50221_thread_wakeup(ca);
	}
}
999
EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
L
Linus Torvalds 已提交
1000 1001 1002


/**
1003
 * dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred.
L
Linus Torvalds 已提交
1004
 *
1005 1006
 * @ca: CA instance.
 * @slot: Slot concerned.
L
Linus Torvalds 已提交
1007 1008 1009
 */
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
{
1010
	struct dvb_ca_private *ca = pubca->private;
1011
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
1012 1013 1014 1015
	int flags;

	dprintk("FR/DA IRQ slot:%i\n", slot);

1016
	switch (sl->slot_state) {
L
Linus Torvalds 已提交
1017 1018 1019 1020
	case DVB_CA_SLOTSTATE_LINKINIT:
		flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
		if (flags & STATUSREG_DA) {
			dprintk("CAM supports DA IRQ\n");
1021
			sl->da_irq_supported = 1;
L
Linus Torvalds 已提交
1022 1023 1024 1025 1026
		}
		break;

	case DVB_CA_SLOTSTATE_RUNNING:
		if (ca->open)
1027
			dvb_ca_en50221_thread_wakeup(ca);
L
Linus Torvalds 已提交
1028 1029 1030
		break;
	}
}
1031
EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
L
Linus Torvalds 已提交
1032 1033 1034 1035 1036 1037 1038 1039


/* ******************************************************************************** */
/* EN50221 thread functions */

/**
 * Wake up the DVB CA thread
 *
1040
 * @ca: CA instance.
L
Linus Torvalds 已提交
1041 1042 1043 1044
 */
static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
{

1045
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1046 1047 1048

	ca->wakeup = 1;
	mb();
1049
	wake_up_process(ca->thread);
L
Linus Torvalds 已提交
1050 1051 1052 1053 1054
}

/**
 * Update the delay used by the thread.
 *
1055
 * @ca: CA instance.
L
Linus Torvalds 已提交
1056 1057 1058 1059 1060 1061 1062
 */
static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
{
	int delay;
	int curdelay = 100000000;
	int slot;

1063 1064 1065
	/* Beware of too high polling frequency, because one polling
	 * call might take several hundred milliseconds until timeout!
	 */
L
Linus Torvalds 已提交
1066
	for (slot = 0; slot < ca->slot_count; slot++) {
1067 1068 1069
		struct dvb_ca_slot *sl = &ca->slot_info[slot];

		switch (sl->slot_state) {
L
Linus Torvalds 已提交
1070 1071
		default:
		case DVB_CA_SLOTSTATE_NONE:
1072 1073 1074 1075
			delay = HZ * 60;  /* 60s */
			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
				delay = HZ * 5;  /* 5s */
			break;
L
Linus Torvalds 已提交
1076
		case DVB_CA_SLOTSTATE_INVALID:
1077 1078 1079
			delay = HZ * 60;  /* 60s */
			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
				delay = HZ / 10;  /* 100ms */
L
Linus Torvalds 已提交
1080 1081 1082 1083 1084 1085 1086
			break;

		case DVB_CA_SLOTSTATE_UNINITIALISED:
		case DVB_CA_SLOTSTATE_WAITREADY:
		case DVB_CA_SLOTSTATE_VALIDATE:
		case DVB_CA_SLOTSTATE_WAITFR:
		case DVB_CA_SLOTSTATE_LINKINIT:
1087
			delay = HZ / 10;  /* 100ms */
L
Linus Torvalds 已提交
1088 1089 1090
			break;

		case DVB_CA_SLOTSTATE_RUNNING:
1091 1092 1093
			delay = HZ * 60;  /* 60s */
			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
				delay = HZ / 10;  /* 100ms */
L
Linus Torvalds 已提交
1094
			if (ca->open) {
1095
				if ((!sl->da_irq_supported) ||
1096 1097
				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
					delay = HZ / 10;  /* 100ms */
L
Linus Torvalds 已提交
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
			}
			break;
		}

		if (delay < curdelay)
			curdelay = delay;
	}

	ca->delay = curdelay;
}

1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
/**
 * Poll if the CAM is gone.
 *
 * @ca: CA instance.
 * @slot: Slot to process.
 * @return: 0 .. no change
 *          1 .. CAM state changed
 */

static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot)
{
	int changed = 0;
	int status;

	/*
	 * we need this extra check for annoying interfaces like the
	 * budget-av
	 */
	if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
	    (ca->pub->poll_slot_status)) {
		status = ca->pub->poll_slot_status(ca->pub, slot, 0);
		if (!(status &
			DVB_CA_EN50221_POLL_CAM_PRESENT)) {
			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
			dvb_ca_en50221_thread_update_delay(ca);
			changed = 1;
		}
	}
	return changed;
}

L
Linus Torvalds 已提交
1140
/**
1141 1142 1143 1144
 * Thread state machine for one CA slot to perform the data transfer.
 *
 * @ca: CA instance.
 * @slot: Slot to process.
L
Linus Torvalds 已提交
1145
 */
1146 1147
static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
						int slot)
L
Linus Torvalds 已提交
1148
{
1149
	struct dvb_ca_slot *sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
1150 1151 1152 1153
	int flags;
	int pktcount;
	void *rxbuf;

1154
	mutex_lock(&sl->slot_lock);
L
Linus Torvalds 已提交
1155

1156 1157 1158 1159 1160
	/* check the cam status + deal with CAMCHANGEs */
	while (dvb_ca_en50221_check_camstatus(ca, slot)) {
		/* clear down an old CI slot if necessary */
		if (sl->slot_state != DVB_CA_SLOTSTATE_NONE)
			dvb_ca_en50221_slot_shutdown(ca, slot);
L
Linus Torvalds 已提交
1161

1162 1163 1164
		/* if a CAM is NOW present, initialise it */
		if (sl->camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED)
			sl->slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
L
Linus Torvalds 已提交
1165

1166 1167 1168 1169
		/* we've handled one CAMCHANGE */
		dvb_ca_en50221_thread_update_delay(ca);
		atomic_dec(&sl->camchange_count);
	}
L
Linus Torvalds 已提交
1170

1171 1172 1173 1174 1175 1176
	/* CAM state machine */
	switch (sl->slot_state) {
	case DVB_CA_SLOTSTATE_NONE:
	case DVB_CA_SLOTSTATE_INVALID:
		/* no action needed */
		break;
L
Linus Torvalds 已提交
1177

1178 1179 1180 1181 1182
	case DVB_CA_SLOTSTATE_UNINITIALISED:
		sl->slot_state = DVB_CA_SLOTSTATE_WAITREADY;
		ca->pub->slot_reset(ca->pub, slot);
		sl->timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
		break;
L
Linus Torvalds 已提交
1183

1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
	case DVB_CA_SLOTSTATE_WAITREADY:
		if (time_after(jiffies, sl->timeout)) {
			pr_err("dvb_ca adaptor %d: PC card did not respond :(\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
		/*
		 * no other action needed; will automatically change state when
		 * ready
		 */
		break;
L
Linus Torvalds 已提交
1197

1198 1199
	case DVB_CA_SLOTSTATE_VALIDATE:
		if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
1200 1201
			if (dvb_ca_en50221_poll_cam_gone(ca, slot))
				break;
L
Linus Torvalds 已提交
1202

1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
			pr_err("dvb_ca adapter %d: Invalid PC card inserted :(\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
		if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
			pr_err("dvb_ca adapter %d: Unable to initialise CAM :(\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
		if (ca->pub->write_cam_control(ca->pub, slot,
					       CTRLIF_COMMAND,
					       CMDREG_RS) != 0) {
			pr_err("dvb_ca adapter %d: Unable to reset CAM IF\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
		dprintk("DVB CAM validated successfully\n");
L
Linus Torvalds 已提交
1226

1227 1228 1229 1230
		sl->timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
		sl->slot_state = DVB_CA_SLOTSTATE_WAITFR;
		ca->wakeup = 1;
		break;
L
Linus Torvalds 已提交
1231

1232 1233 1234 1235 1236 1237 1238 1239
	case DVB_CA_SLOTSTATE_WAITFR:
		if (time_after(jiffies, sl->timeout)) {
			pr_err("dvb_ca adapter %d: DVB CAM did not respond :(\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
L
Linus Torvalds 已提交
1240

1241 1242 1243 1244 1245 1246
		flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
		if (flags & STATUSREG_FR) {
			sl->slot_state = DVB_CA_SLOTSTATE_LINKINIT;
			ca->wakeup = 1;
		}
		break;
L
Linus Torvalds 已提交
1247

1248 1249
	case DVB_CA_SLOTSTATE_LINKINIT:
		if (dvb_ca_en50221_link_init(ca, slot) != 0) {
1250 1251
			if (dvb_ca_en50221_poll_cam_gone(ca, slot))
				break;
L
Linus Torvalds 已提交
1252

1253 1254 1255 1256 1257 1258
			pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n",
			       ca->dvbdev->adapter->num);
			sl->slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
			dvb_ca_en50221_thread_update_delay(ca);
			break;
		}
L
Linus Torvalds 已提交
1259

1260 1261 1262 1263
		if (!sl->rx_buffer.data) {
			rxbuf = vmalloc(RX_BUFFER_SIZE);
			if (!rxbuf) {
				pr_err("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n",
1264
				       ca->dvbdev->adapter->num);
1265 1266
				sl->slot_state = DVB_CA_SLOTSTATE_INVALID;
				dvb_ca_en50221_thread_update_delay(ca);
L
Linus Torvalds 已提交
1267
				break;
1268 1269 1270 1271
			}
			dvb_ringbuffer_init(&sl->rx_buffer, rxbuf,
					    RX_BUFFER_SIZE);
		}
L
Linus Torvalds 已提交
1272

1273 1274 1275 1276 1277 1278
		ca->pub->slot_ts_enable(ca->pub, slot);
		sl->slot_state = DVB_CA_SLOTSTATE_RUNNING;
		dvb_ca_en50221_thread_update_delay(ca);
		pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
		       ca->dvbdev->adapter->num);
		break;
L
Linus Torvalds 已提交
1279

1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
	case DVB_CA_SLOTSTATE_RUNNING:
		if (!ca->open)
			break;

		/* poll slots for data */
		pktcount = 0;
		while (dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) {
			if (!ca->open)
				break;

			/*
			 * if a CAMCHANGE occurred at some point, do not do any
			 * more processing of this slot
			 */
			if (dvb_ca_en50221_check_camstatus(ca, slot)) {
				/*
				 * we dont want to sleep on the next iteration
				 * so we can handle the cam change
				 */
				ca->wakeup = 1;
L
Linus Torvalds 已提交
1300 1301
				break;
			}
1302

1303 1304 1305 1306 1307 1308 1309 1310 1311
			/* check if we've hit our limit this time */
			if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
				/*
				 * dont sleep; there is likely to be more data
				 * to read
				 */
				ca->wakeup = 1;
				break;
			}
L
Linus Torvalds 已提交
1312
		}
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
		break;
	}

	mutex_unlock(&sl->slot_lock);
}

/**
 * Kernel thread which monitors CA slots for CAM changes, and performs data
 * transfers.
 */
static int dvb_ca_en50221_thread(void *data)
{
	struct dvb_ca_private *ca = data;
	int slot;

	dprintk("%s\n", __func__);

	/* choose the correct initial delay */
	dvb_ca_en50221_thread_update_delay(ca);

	/* main loop */
	while (!kthread_should_stop()) {
		/* sleep for a bit */
		if (!ca->wakeup) {
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(ca->delay);
			if (kthread_should_stop())
				return 0;
		}
		ca->wakeup = 0;

		/* go through all the slots processing them */
		for (slot = 0; slot < ca->slot_count; slot++)
			dvb_ca_en50221_thread_state_machine(ca, slot);
L
Linus Torvalds 已提交
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
	}

	return 0;
}



/* ******************************************************************************** */
/* EN50221 IO interface functions */

/**
 * Real ioctl implementation.
 * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
 *
1361 1362 1363 1364
 * @inode: Inode concerned.
 * @file: File concerned.
 * @cmd: IOCTL command.
 * @arg: Associated argument.
L
Linus Torvalds 已提交
1365 1366 1367
 *
 * @return 0 on success, <0 on error.
 */
1368
static int dvb_ca_en50221_io_do_ioctl(struct file *file,
L
Linus Torvalds 已提交
1369 1370
				      unsigned int cmd, void *parg)
{
1371 1372
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
L
Linus Torvalds 已提交
1373 1374 1375
	int err = 0;
	int slot;

1376
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1377

1378 1379 1380
	if (mutex_lock_interruptible(&ca->ioctl_mutex))
		return -ERESTARTSYS;

L
Linus Torvalds 已提交
1381 1382 1383
	switch (cmd) {
	case CA_RESET:
		for (slot = 0; slot < ca->slot_count; slot++) {
1384 1385 1386 1387
			struct dvb_ca_slot *sl = &ca->slot_info[slot];

			mutex_lock(&sl->slot_lock);
			if (sl->slot_state != DVB_CA_SLOTSTATE_NONE) {
L
Linus Torvalds 已提交
1388 1389 1390 1391 1392 1393
				dvb_ca_en50221_slot_shutdown(ca, slot);
				if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
					dvb_ca_en50221_camchange_irq(ca->pub,
								     slot,
								     DVB_CA_EN50221_CAMCHANGE_INSERTED);
			}
1394
			mutex_unlock(&sl->slot_lock);
L
Linus Torvalds 已提交
1395 1396 1397 1398 1399 1400
		}
		ca->next_read_slot = 0;
		dvb_ca_en50221_thread_wakeup(ca);
		break;

	case CA_GET_CAP: {
1401
		struct ca_caps *caps = parg;
L
Linus Torvalds 已提交
1402 1403 1404 1405 1406 1407 1408 1409 1410

		caps->slot_num = ca->slot_count;
		caps->slot_type = CA_CI_LINK;
		caps->descr_num = 0;
		caps->descr_type = 0;
		break;
	}

	case CA_GET_SLOT_INFO: {
1411
		struct ca_slot_info *info = parg;
1412
		struct dvb_ca_slot *sl;
L
Linus Torvalds 已提交
1413

1414 1415
		slot = info->num;
		if ((slot > ca->slot_count) || (slot < 0)) {
1416 1417 1418
			err = -EINVAL;
			goto out_unlock;
		}
L
Linus Torvalds 已提交
1419 1420 1421

		info->type = CA_CI_LINK;
		info->flags = 0;
1422 1423 1424
		sl = &ca->slot_info[slot];
		if ((sl->slot_state != DVB_CA_SLOTSTATE_NONE) &&
		    (sl->slot_state != DVB_CA_SLOTSTATE_INVALID)) {
L
Linus Torvalds 已提交
1425 1426
			info->flags = CA_CI_MODULE_PRESENT;
		}
1427
		if (sl->slot_state == DVB_CA_SLOTSTATE_RUNNING)
L
Linus Torvalds 已提交
1428 1429 1430 1431 1432 1433 1434 1435 1436
			info->flags |= CA_CI_MODULE_READY;
		break;
	}

	default:
		err = -EINVAL;
		break;
	}

1437
out_unlock:
1438
	mutex_unlock(&ca->ioctl_mutex);
L
Linus Torvalds 已提交
1439 1440 1441 1442 1443 1444 1445
	return err;
}


/**
 * Wrapper for ioctl implementation.
 *
1446 1447 1448 1449
 * @inode: Inode concerned.
 * @file: File concerned.
 * @cmd: IOCTL command.
 * @arg: Associated argument.
L
Linus Torvalds 已提交
1450 1451 1452
 *
 * @return 0 on success, <0 on error.
 */
1453 1454
static long dvb_ca_en50221_io_ioctl(struct file *file,
				    unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
1455
{
A
Arnd Bergmann 已提交
1456
	return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
L
Linus Torvalds 已提交
1457 1458 1459 1460 1461 1462
}


/**
 * Implementation of write() syscall.
 *
1463 1464 1465 1466
 * @file: File structure.
 * @buf: Source buffer.
 * @count: Size of source buffer.
 * @ppos: Position in file (ignored).
L
Linus Torvalds 已提交
1467 1468 1469 1470
 *
 * @return Number of bytes read, or <0 on error.
 */
static ssize_t dvb_ca_en50221_io_write(struct file *file,
1471 1472
				       const char __user *buf, size_t count,
				       loff_t *ppos)
L
Linus Torvalds 已提交
1473
{
1474 1475
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
1476
	struct dvb_ca_slot *sl;
L
Linus Torvalds 已提交
1477 1478
	u8 slot, connection_id;
	int status;
1479
	u8 fragbuf[HOST_LINK_BUF_SIZE];
L
Linus Torvalds 已提交
1480 1481 1482 1483 1484
	int fragpos = 0;
	int fraglen;
	unsigned long timeout;
	int written;

1485
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497

	/* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
	if (count < 2)
		return -EINVAL;

	/* extract slot & connection id */
	if (copy_from_user(&slot, buf, 1))
		return -EFAULT;
	if (copy_from_user(&connection_id, buf + 1, 1))
		return -EFAULT;
	buf += 2;
	count -= 2;
1498
	sl = &ca->slot_info[slot];
L
Linus Torvalds 已提交
1499 1500

	/* check if the slot is actually running */
1501
	if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING)
L
Linus Torvalds 已提交
1502 1503 1504 1505
		return -EINVAL;

	/* fragment the packets & store in the buffer */
	while (fragpos < count) {
1506
		fraglen = sl->link_buf_size - 2;
1507 1508 1509 1510
		if (fraglen < 0)
			break;
		if (fraglen > HOST_LINK_BUF_SIZE - 2)
			fraglen = HOST_LINK_BUF_SIZE - 2;
L
Linus Torvalds 已提交
1511 1512 1513 1514 1515
		if ((count - fragpos) < fraglen)
			fraglen = count - fragpos;

		fragbuf[0] = connection_id;
		fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
1516 1517 1518
		status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
		if (status) {
			status = -EFAULT;
L
Linus Torvalds 已提交
1519
			goto exit;
1520
		}
L
Linus Torvalds 已提交
1521 1522 1523 1524 1525

		timeout = jiffies + HZ / 2;
		written = 0;
		while (!time_after(jiffies, timeout)) {
			/* check the CAM hasn't been removed/reset in the meantime */
1526
			if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING) {
L
Linus Torvalds 已提交
1527 1528 1529 1530
				status = -EIO;
				goto exit;
			}

1531
			mutex_lock(&sl->slot_lock);
L
Linus Torvalds 已提交
1532
			status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
1533
			mutex_unlock(&sl->slot_lock);
L
Linus Torvalds 已提交
1534 1535 1536 1537 1538 1539 1540
			if (status == (fraglen + 2)) {
				written = 1;
				break;
			}
			if (status != -EAGAIN)
				goto exit;

1541
			usleep_range(1000, 1100);
L
Linus Torvalds 已提交
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
		}
		if (!written) {
			status = -EIO;
			goto exit;
		}

		fragpos += fraglen;
	}
	status = count + 2;

exit:
	return status;
}


/**
 * Condition for waking up in dvb_ca_en50221_io_read_condition
 */
1560 1561
static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
					    int *result, int *_slot)
L
Linus Torvalds 已提交
1562 1563 1564 1565
{
	int slot;
	int slot_count = 0;
	int idx;
1566
	size_t fraglen;
L
Linus Torvalds 已提交
1567 1568 1569 1570 1571 1572
	int connection_id = -1;
	int found = 0;
	u8 hdr[2];

	slot = ca->next_read_slot;
	while ((slot_count < ca->slot_count) && (!found)) {
1573 1574 1575
		struct dvb_ca_slot *sl = &ca->slot_info[slot];

		if (sl->slot_state != DVB_CA_SLOTSTATE_RUNNING)
L
Linus Torvalds 已提交
1576 1577
			goto nextslot;

1578
		if (!sl->rx_buffer.data)
L
Linus Torvalds 已提交
1579 1580
			return 0;

1581
		idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, -1, &fraglen);
L
Linus Torvalds 已提交
1582
		while (idx != -1) {
1583
			dvb_ringbuffer_pkt_read(&sl->rx_buffer, idx, 0, hdr, 2);
L
Linus Torvalds 已提交
1584 1585 1586 1587 1588 1589 1590 1591
			if (connection_id == -1)
				connection_id = hdr[0];
			if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
				*_slot = slot;
				found = 1;
				break;
			}

1592 1593
			idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, idx,
						      &fraglen);
L
Linus Torvalds 已提交
1594 1595
		}

1596
nextslot:
L
Linus Torvalds 已提交
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
		slot = (slot + 1) % ca->slot_count;
		slot_count++;
	}

	ca->next_read_slot = slot;
	return found;
}


/**
 * Implementation of read() syscall.
 *
1609 1610 1611 1612
 * @file: File structure.
 * @buf: Destination buffer.
 * @count: Size of destination buffer.
 * @ppos: Position in file (ignored).
L
Linus Torvalds 已提交
1613 1614 1615
 *
 * @return Number of bytes read, or <0 on error.
 */
1616 1617
static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf,
				      size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
1618
{
1619 1620
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
1621
	struct dvb_ca_slot *sl;
L
Linus Torvalds 已提交
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
	int status;
	int result = 0;
	u8 hdr[2];
	int slot;
	int connection_id = -1;
	size_t idx, idx2;
	int last_fragment = 0;
	size_t fraglen;
	int pktlen;
	int dispose = 0;

1633
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1634 1635 1636 1637 1638 1639

	/* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
	if (count < 2)
		return -EINVAL;

	/* wait for some data */
1640 1641
	status = dvb_ca_en50221_io_read_condition(ca, &result, &slot);
	if (status == 0) {
L
Linus Torvalds 已提交
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657

		/* if we're in nonblocking mode, exit immediately */
		if (file->f_flags & O_NONBLOCK)
			return -EWOULDBLOCK;

		/* wait for some data */
		status = wait_event_interruptible(ca->wait_queue,
						  dvb_ca_en50221_io_read_condition
						  (ca, &result, &slot));
	}
	if ((status < 0) || (result < 0)) {
		if (result)
			return result;
		return status;
	}

1658 1659
	sl = &ca->slot_info[slot];
	idx = dvb_ringbuffer_pkt_next(&sl->rx_buffer, -1, &fraglen);
L
Linus Torvalds 已提交
1660 1661 1662
	pktlen = 2;
	do {
		if (idx == -1) {
1663 1664
			pr_err("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n",
			       ca->dvbdev->adapter->num);
L
Linus Torvalds 已提交
1665 1666 1667 1668
			status = -EIO;
			goto exit;
		}

1669
		dvb_ringbuffer_pkt_read(&sl->rx_buffer, idx, 0, hdr, 2);
L
Linus Torvalds 已提交
1670 1671 1672 1673
		if (connection_id == -1)
			connection_id = hdr[0];
		if (hdr[0] == connection_id) {
			if (pktlen < count) {
1674
				if ((pktlen + fraglen - 2) > count)
L
Linus Torvalds 已提交
1675
					fraglen = count - pktlen;
1676
				else
L
Linus Torvalds 已提交
1677 1678
					fraglen -= 2;

1679 1680 1681 1682 1683 1684
				status =
				   dvb_ringbuffer_pkt_read_user(&sl->rx_buffer,
								idx, 2,
								buf + pktlen,
								fraglen);
				if (status < 0)
L
Linus Torvalds 已提交
1685
					goto exit;
1686

L
Linus Torvalds 已提交
1687 1688 1689 1690 1691 1692 1693 1694
				pktlen += fraglen;
			}

			if ((hdr[1] & 0x80) == 0)
				last_fragment = 1;
			dispose = 1;
		}

1695
		idx2 = dvb_ringbuffer_pkt_next(&sl->rx_buffer, idx, &fraglen);
L
Linus Torvalds 已提交
1696
		if (dispose)
1697
			dvb_ringbuffer_pkt_dispose(&sl->rx_buffer, idx);
L
Linus Torvalds 已提交
1698 1699 1700 1701 1702 1703
		idx = idx2;
		dispose = 0;
	} while (!last_fragment);

	hdr[0] = slot;
	hdr[1] = connection_id;
1704 1705 1706
	status = copy_to_user(buf, hdr, 2);
	if (status) {
		status = -EFAULT;
L
Linus Torvalds 已提交
1707
		goto exit;
1708
	}
L
Linus Torvalds 已提交
1709 1710
	status = pktlen;

1711
exit:
L
Linus Torvalds 已提交
1712 1713 1714 1715 1716 1717 1718
	return status;
}


/**
 * Implementation of file open syscall.
 *
1719 1720
 * @inode: Inode concerned.
 * @file: File concerned.
L
Linus Torvalds 已提交
1721 1722 1723 1724 1725
 *
 * @return 0 on success, <0 on failure.
 */
static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
{
1726 1727
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
L
Linus Torvalds 已提交
1728 1729 1730
	int err;
	int i;

1731
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1732 1733 1734 1735 1736

	if (!try_module_get(ca->pub->owner))
		return -EIO;

	err = dvb_generic_open(inode, file);
1737 1738
	if (err < 0) {
		module_put(ca->pub->owner);
L
Linus Torvalds 已提交
1739
		return err;
1740
	}
L
Linus Torvalds 已提交
1741 1742

	for (i = 0; i < ca->slot_count; i++) {
1743
		struct dvb_ca_slot *sl = &ca->slot_info[i];
L
Linus Torvalds 已提交
1744

1745 1746
		if (sl->slot_state == DVB_CA_SLOTSTATE_RUNNING) {
			if (!sl->rx_buffer.data) {
1747 1748 1749 1750 1751
				/*
				 * it is safe to call this here without locks
				 * because ca->open == 0. Data is not read in
				 * this case
				 */
1752
				dvb_ringbuffer_flush(&sl->rx_buffer);
L
Linus Torvalds 已提交
1753 1754 1755 1756 1757 1758 1759 1760
			}
		}
	}

	ca->open = 1;
	dvb_ca_en50221_thread_update_delay(ca);
	dvb_ca_en50221_thread_wakeup(ca);

1761 1762
	dvb_ca_private_get(ca);

L
Linus Torvalds 已提交
1763 1764 1765 1766 1767 1768 1769
	return 0;
}


/**
 * Implementation of file close syscall.
 *
1770 1771
 * @inode: Inode concerned.
 * @file: File concerned.
L
Linus Torvalds 已提交
1772 1773 1774 1775 1776
 *
 * @return 0 on success, <0 on failure.
 */
static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{
1777 1778
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
1779
	int err;
L
Linus Torvalds 已提交
1780

1781
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1782 1783 1784 1785 1786 1787 1788 1789 1790

	/* mark the CA device as closed */
	ca->open = 0;
	dvb_ca_en50221_thread_update_delay(ca);

	err = dvb_generic_release(inode, file);

	module_put(ca->pub->owner);

1791 1792
	dvb_ca_private_put(ca);

1793
	return err;
L
Linus Torvalds 已提交
1794 1795 1796 1797 1798 1799
}


/**
 * Implementation of poll() syscall.
 *
1800 1801
 * @file: File concerned.
 * @wait: poll wait table.
L
Linus Torvalds 已提交
1802 1803 1804
 *
 * @return Standard poll mask.
 */
1805
static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
L
Linus Torvalds 已提交
1806
{
1807 1808
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_ca_private *ca = dvbdev->priv;
L
Linus Torvalds 已提交
1809 1810 1811 1812
	unsigned int mask = 0;
	int slot;
	int result = 0;

1813
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1814

1815
	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
L
Linus Torvalds 已提交
1816 1817 1818 1819 1820 1821 1822 1823 1824
		mask |= POLLIN;

	/* if there is something, return now */
	if (mask)
		return mask;

	/* wait for something to happen */
	poll_wait(file, &ca->wait_queue, wait);

1825
	if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
L
Linus Torvalds 已提交
1826 1827 1828 1829 1830 1831 1832
		mask |= POLLIN;

	return mask;
}
EXPORT_SYMBOL(dvb_ca_en50221_init);


1833
static const struct file_operations dvb_ca_fops = {
L
Linus Torvalds 已提交
1834 1835 1836
	.owner = THIS_MODULE,
	.read = dvb_ca_en50221_io_read,
	.write = dvb_ca_en50221_io_write,
1837
	.unlocked_ioctl = dvb_ca_en50221_io_ioctl,
L
Linus Torvalds 已提交
1838 1839 1840
	.open = dvb_ca_en50221_io_open,
	.release = dvb_ca_en50221_io_release,
	.poll = dvb_ca_en50221_io_poll,
1841
	.llseek = noop_llseek,
L
Linus Torvalds 已提交
1842 1843
};

1844
static const struct dvb_device dvbdev_ca = {
L
Linus Torvalds 已提交
1845 1846 1847 1848
	.priv = NULL,
	.users = 1,
	.readers = 1,
	.writers = 1,
1849
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
1850
	.name = "dvb-ca-en50221",
1851
#endif
L
Linus Torvalds 已提交
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861
	.fops = &dvb_ca_fops,
};

/* ******************************************************************************** */
/* Initialisation/shutdown functions */


/**
 * Initialise a new DVB CA EN50221 interface device.
 *
1862 1863 1864 1865
 * @dvb_adapter: DVB adapter to attach the new CA device to.
 * @ca: The dvb_ca instance.
 * @flags: Flags describing the CA device (DVB_CA_FLAG_*).
 * @slot_count: Number of slots supported.
L
Linus Torvalds 已提交
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
 *
 * @return 0 on success, nonzero on failure
 */
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
			struct dvb_ca_en50221 *pubca, int flags, int slot_count)
{
	int ret;
	struct dvb_ca_private *ca = NULL;
	int i;

1876
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1877 1878 1879 1880 1881

	if (slot_count < 1)
		return -EINVAL;

	/* initialise the system data */
1882 1883
	ca = kzalloc(sizeof(*ca), GFP_KERNEL);
	if (!ca) {
L
Linus Torvalds 已提交
1884
		ret = -ENOMEM;
1885
		goto exit;
L
Linus Torvalds 已提交
1886
	}
1887
	kref_init(&ca->refcount);
L
Linus Torvalds 已提交
1888 1889 1890
	ca->pub = pubca;
	ca->flags = flags;
	ca->slot_count = slot_count;
1891 1892 1893
	ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot),
				GFP_KERNEL);
	if (!ca->slot_info) {
L
Linus Torvalds 已提交
1894
		ret = -ENOMEM;
1895
		goto free_ca;
L
Linus Torvalds 已提交
1896 1897 1898 1899 1900 1901 1902 1903
	}
	init_waitqueue_head(&ca->wait_queue);
	ca->open = 0;
	ca->wakeup = 0;
	ca->next_read_slot = 0;
	pubca->private = ca;

	/* register the DVB device */
1904
	ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0);
L
Linus Torvalds 已提交
1905
	if (ret)
1906
		goto free_slot_info;
L
Linus Torvalds 已提交
1907 1908 1909

	/* now initialise each slot */
	for (i = 0; i < slot_count; i++) {
1910 1911 1912 1913 1914 1915 1916
		struct dvb_ca_slot *sl = &ca->slot_info[i];

		memset(sl, 0, sizeof(struct dvb_ca_slot));
		sl->slot_state = DVB_CA_SLOTSTATE_NONE;
		atomic_set(&sl->camchange_count, 0);
		sl->camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
		mutex_init(&sl->slot_lock);
L
Linus Torvalds 已提交
1917 1918
	}

1919 1920
	mutex_init(&ca->ioctl_mutex);

L
Linus Torvalds 已提交
1921 1922
	if (signal_pending(current)) {
		ret = -EINTR;
1923
		goto unregister_device;
L
Linus Torvalds 已提交
1924 1925 1926 1927
	}
	mb();

	/* create a kthread for monitoring this CA device */
1928 1929 1930 1931
	ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
				 ca->dvbdev->adapter->num, ca->dvbdev->id);
	if (IS_ERR(ca->thread)) {
		ret = PTR_ERR(ca->thread);
1932 1933
		pr_err("dvb_ca_init: failed to start kernel_thread (%d)\n",
		       ret);
1934
		goto unregister_device;
L
Linus Torvalds 已提交
1935 1936 1937
	}
	return 0;

1938 1939 1940 1941 1942 1943 1944
unregister_device:
	dvb_unregister_device(ca->dvbdev);
free_slot_info:
	kfree(ca->slot_info);
free_ca:
	kfree(ca);
exit:
L
Linus Torvalds 已提交
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
	pubca->private = NULL;
	return ret;
}
EXPORT_SYMBOL(dvb_ca_en50221_release);



/**
 * Release a DVB CA EN50221 interface device.
 *
1955 1956
 * @ca_dev: The dvb_device_t instance for the CA device.
 * @ca: The associated dvb_ca instance.
L
Linus Torvalds 已提交
1957 1958 1959
 */
void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
{
1960
	struct dvb_ca_private *ca = pubca->private;
L
Linus Torvalds 已提交
1961 1962
	int i;

1963
	dprintk("%s\n", __func__);
L
Linus Torvalds 已提交
1964 1965

	/* shutdown the thread if there was one */
1966
	kthread_stop(ca->thread);
L
Linus Torvalds 已提交
1967

1968
	for (i = 0; i < ca->slot_count; i++)
L
Linus Torvalds 已提交
1969
		dvb_ca_en50221_slot_shutdown(ca, i);
1970

1971
	dvb_remove_device(ca->dvbdev);
1972
	dvb_ca_private_put(ca);
L
Linus Torvalds 已提交
1973 1974
	pubca->private = NULL;
}