dst_ca.c 18.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
	CA-driver for TwinHan DST Frontend/Card

	Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)

	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.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
#include "dvb_frontend.h"
#include "dst_ca.h"
#include "dst_common.h"

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
#define DST_CA_ERROR		0
#define DST_CA_NOTICE		1
#define DST_CA_INFO		2
#define DST_CA_DEBUG		3

#define dprintk(x, y, z, format, arg...) do {						\
	if (z) {									\
		if	((x > DST_CA_ERROR) && (x > y))					\
			printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg);	\
		else if	((x > DST_CA_NOTICE) && (x > y))				\
			printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg);	\
		else if ((x > DST_CA_INFO) && (x > y))					\
			printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg);	\
		else if ((x > DST_CA_DEBUG) && (x > y))					\
			printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg);	\
	} else {									\
		if (x > y)								\
			printk(format, ## arg);						\
	}										\
} while(0)


53
static unsigned int verbose = 5;
54 55 56
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");

57
/*	Need some more work	*/
58 59 60 61 62 63
static int ca_set_slot_descr(void)
{
	/*	We could make this more graceful ?	*/
	return -EOPNOTSUPP;
}

64
/*	Need some more work	*/
65 66 67 68 69 70 71 72 73 74 75
static int ca_set_pid(void)
{
	/*	We could make this more graceful ?	*/
	return -EOPNOTSUPP;
}


static int put_checksum(u8 *check_string, int length)
{
	u8 i = 0, checksum = 0;

76 77 78
	dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ===========================");
	dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length);
	dprintk(verbose, DST_CA_DEBUG, 1, " String=[");
79 80

	while (i < length) {
81
		dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]);
82 83 84
		checksum += check_string[i];
		i++;
	}
85 86
	dprintk(verbose, DST_CA_DEBUG, 0, " ]\n");
	dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum);
87
	check_string[length] = ~checksum + 1;
88 89
	dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]);
	dprintk(verbose, DST_CA_DEBUG, 1, " ==========================================================================");
90 91 92 93 94 95 96 97 98 99 100 101

	return 0;
}

static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
{
	u8 reply;

	dst_comm_init(state);
	msleep(65);

	if (write_dst(state, data, len)) {
102
		dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
103 104 105 106
		dst_error_recovery(state);
		return -1;
	}
	if ((dst_pio_disable(state)) < 0) {
107
		dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
108 109 110
		return -1;
	}
	if (read_dst(state, &reply, GET_ACK) < 0) {
111
		dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
112 113 114 115 116
		dst_error_recovery(state);
		return -1;
	}
	if (read) {
		if (! dst_wait_dst_ready(state, LONG_DELAY)) {
117
			dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
118 119 120
			return -1;
		}
		if (read_dst(state, ca_string, 128) < 0) {	/*	Try to make this dynamic	*/
121
			dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
			dst_error_recovery(state);
			return -1;
		}
	}

	return 0;
}


static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
{
	u8 dst_ca_comm_err = 0;

	while (dst_ca_comm_err < RETRIES) {
		dst_comm_init(state);
137
		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
			dst_error_recovery(state);
			dst_ca_comm_err++; // work required here.
		}
		break;
	}

	return 0;
}



static int ca_get_app_info(struct dst_state *state)
{
	static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};

	put_checksum(&command[0], command[0]);
	if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
156
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
157 158
		return -1;
	}
159 160 161 162 163 164
	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
	dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
	dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
		state->messages[7], (state->messages[8] << 8) | state->messages[9],
		(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
165 166 167 168 169 170 171 172 173 174 175 176

	return 0;
}

static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
{
	int i;
	u8 slot_cap[256];
	static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};

	put_checksum(&slot_command[0], slot_command[0]);
	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
177
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
178 179
		return -1;
	}
180
	dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
181 182 183

	/*	Will implement the rest soon		*/

184 185 186 187 188
	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
	for (i = 0; i < 8; i++)
		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
	dprintk(verbose, DST_CA_INFO, 0, "\n");
189 190 191 192 193 194

	p_ca_caps->slot_num = 1;
	p_ca_caps->slot_type = 1;
	p_ca_caps->descr_num = slot_cap[7];
	p_ca_caps->descr_type = 1;

195
	if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps)))
196 197 198 199 200
		return -EFAULT;

	return 0;
}

201
/*	Need some more work	*/
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
{
	return -EOPNOTSUPP;
}


static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
{
	int i;
	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};

	u8 *slot_info = state->rxbuffer;

	put_checksum(&slot_command[0], 7);
	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
217
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
218 219
		return -1;
	}
220
	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
221 222 223

	/*	Will implement the rest soon		*/

224 225 226 227 228
	dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
	for (i = 0; i < 8; i++)
		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
	dprintk(verbose, DST_CA_INFO, 0, "\n");
229 230 231 232 233

	if (slot_info[4] & 0x80) {
		p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
		p_ca_slot_info->num = 1;
		p_ca_slot_info->type = CA_CI;
234
	} else if (slot_info[4] & 0x40) {
235 236 237
		p_ca_slot_info->flags = CA_CI_MODULE_READY;
		p_ca_slot_info->num = 1;
		p_ca_slot_info->type = CA_CI;
238
	} else
239 240
		p_ca_slot_info->flags = 0;

241
	if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
		return -EFAULT;

	return 0;
}


static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
{
	u8 i = 0;
	u32 command = 0;

	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
		return -EFAULT;

	if (p_ca_message->msg) {
257
		dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
258 259 260 261 262 263

		for (i = 0; i < 3; i++) {
			command = command | p_ca_message->msg[i];
			if (i < 2)
				command = command << 8;
		}
264
		dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
265 266

		switch (command) {
267 268 269 270
		case CA_APP_INFO:
			memcpy(p_ca_message->msg, state->messages, 128);
			if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
				return -EFAULT;
271 272 273 274 275 276 277
			break;
		}
	}

	return 0;
}

278
static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
279
{
280
	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
281 282 283 284
		hw_buffer->msg[2] = p_ca_message->msg[1];	/*	MSB	*/
		hw_buffer->msg[3] = p_ca_message->msg[2];	/*	LSB	*/
	} else {
		if (length > 247) {
285
			dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
286 287
			return -1;
		}
288 289
		hw_buffer->msg[0] = (length & 0xff) + 7;
		hw_buffer->msg[1] = 0x40;
290 291
		hw_buffer->msg[2] = 0x03;
		hw_buffer->msg[3] = 0x00;
292 293 294
		hw_buffer->msg[4] = 0x03;
		hw_buffer->msg[5] = length & 0xff;
		hw_buffer->msg[6] = 0x00;
295 296 297 298 299
		/*
		 *	Need to compute length for EN50221 section 8.3.2, for the time being
		 *	assuming 8.3.2 is not applicable
		 */
		memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
300 301 302 303 304
	}
	return 0;
}


305
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
306
{
307
	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
308 309
		dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
		dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
310 311 312
		rdc_reset_state(state);
		return -1;
	}
313
	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
314 315 316 317

	return 0;
}

318
u32 asn_1_decode(u8 *asn_1_array)
319
{
320 321 322 323
	u8 length_field = 0, word_count = 0, count = 0;
	u32 length = 0;

	length_field = asn_1_array[0];
324
	dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
325 326
	if (length_field < 0x80) {
		length = length_field & 0x7f;
327
		dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
328 329 330 331
	} else {
		word_count = length_field & 0x7f;
		for (count = 0; count < word_count; count++) {
			length = (length | asn_1_array[count + 1]) << 8;
332
			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
333 334
		}
	}
335 336
	return length;
}
337

338 339 340
static int debug_string(u8 *msg, u32 length, u32 offset)
{
	u32 i;
341

342
	dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
343
	for (i = offset; i < length; i++)
344 345
		dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
	dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
346

347 348
	return 0;
}
349

350 351
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
352 353
	u32 length = 0;
	u8 tag_length = 8;
354

355
	length = asn_1_decode(&p_ca_message->msg[3]);
356
	dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
357
	debug_string(&p_ca_message->msg[4], length, 0); /*	length is excluding tag & length	*/
358

359
	memset(hw_buffer->msg, '\0', length);
360
	handle_dst_tag(state, p_ca_message, hw_buffer, length);
361
	put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
362

363 364
	debug_string(hw_buffer->msg, (length + tag_length), 0); /*	tags too	*/
	write_to_8820(state, hw_buffer, (length + tag_length), reply);
365 366 367 368

	return 0;
}

369

370 371 372 373 374 375 376 377 378 379 380
/*	Board supports CA PMT reply ?		*/
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
{
	int ca_pmt_reply_test = 0;

	/*	Do test board			*/
	/*	Not there yet but soon		*/

	/*	CA PMT Reply capable		*/
	if (ca_pmt_reply_test) {
		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
381
			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
382 383 384 385 386
			return -1;
		}

	/*	Process CA PMT Reply		*/
	/*	will implement soon		*/
387
		dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
388 389 390 391
	}
	/*	CA PMT Reply not capable	*/
	if (!ca_pmt_reply_test) {
		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
392
			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
393 394
			return -1;
		}
395
		dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
	/*	put a dummy message		*/

	}
	return 0;
}

static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
{
	int i = 0;
	unsigned int ca_message_header_len;

	u32 command = 0;
	struct ca_msg *hw_buffer;

	if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
411
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
412 413
		return -ENOMEM;
	}
414
	dprintk(verbose, DST_CA_DEBUG, 1, " ");
415 416 417 418 419 420 421 422 423 424 425 426 427 428

	if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
		return -EFAULT;

	if (p_ca_message->msg) {
		ca_message_header_len = p_ca_message->length;	/*	Restore it back when you are done	*/
		/*	EN50221 tag	*/
		command = 0;

		for (i = 0; i < 3; i++) {
			command = command | p_ca_message->msg[i];
			if (i < 2)
				command = command << 8;
		}
429
		dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
430 431

		switch (command) {
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
		case CA_PMT:
			dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
			if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {	// code simplification started
				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
				return -1;
			}
			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
			break;
		case CA_PMT_REPLY:
			dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
			/*      Have to handle the 2 basic types of cards here  */
			if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
				return -1;
			}
			dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
			break;
		case CA_APP_INFO_ENQUIRY:		// only for debugging
			dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");

			if ((ca_get_app_info(state)) < 0) {
				dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
				return -1;
			}
			dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
			break;
458 459 460 461 462 463 464 465 466 467 468 469 470 471
		}
	}
	return 0;
}

static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
{
	struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
	struct dst_state* state = (struct dst_state*) dvbdev->priv;
	struct ca_slot_info *p_ca_slot_info;
	struct ca_caps *p_ca_caps;
	struct ca_msg *p_ca_message;

	if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
472
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
473 474 475
		return -ENOMEM;
	}
	if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
476
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
477 478 479
		return -ENOMEM;
	}
	if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
480
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
481 482 483 484
		return -ENOMEM;
	}
	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
	switch (cmd) {
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
	case CA_SEND_MSG:
		dprintk(verbose, DST_CA_INFO, 1, " Sending message");
		if ((ca_send_message(state, p_ca_message, arg)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
			return -1;
		}
		break;
	case CA_GET_MSG:
		dprintk(verbose, DST_CA_INFO, 1, " Getting message");
		if ((ca_get_message(state, p_ca_message, arg)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
		break;
	case CA_RESET:
		dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
		dst_error_bailout(state);
		msleep(4000);
		break;
	case CA_GET_SLOT_INFO:
		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
		if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
		break;
	case CA_GET_CAP:
		dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
		if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
		break;
	case CA_GET_DESCR_INFO:
		dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
		if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
		break;
	case CA_SET_DESCR:
		dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
		if ((ca_set_slot_descr()) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
		break;
	case CA_SET_PID:
		dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
		if ((ca_set_pid()) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
			return -1;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
	default:
		return -EOPNOTSUPP;
	};
547 548 549 550 551 552

	return 0;
}

static int dst_ca_open(struct inode *inode, struct file *file)
{
553
	dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
554 555 556 557 558 559 560
	try_module_get(THIS_MODULE);

	return 0;
}

static int dst_ca_release(struct inode *inode, struct file *file)
{
561
	dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
562 563 564 565 566
	module_put(THIS_MODULE);

	return 0;
}

567
static int dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
568 569 570
{
	int bytes_read = 0;

571
	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
572 573 574 575

	return bytes_read;
}

576
static int dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
577
{
578
	dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602

	return 0;
}

static struct file_operations dst_ca_fops = {
	.owner = THIS_MODULE,
	.ioctl = (void *)dst_ca_ioctl,
	.open = dst_ca_open,
	.release = dst_ca_release,
	.read = dst_ca_read,
	.write = dst_ca_write
};

static struct dvb_device dvbdev_ca = {
	.priv = NULL,
	.users = 1,
	.readers = 1,
	.writers = 1,
	.fops = &dst_ca_fops
};

int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
{
	struct dvb_device *dvbdev;
603
	dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
604 605 606 607 608 609 610 611 612
	dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
	return 0;
}

EXPORT_SYMBOL(dst_ca_attach);

MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
MODULE_AUTHOR("Manu Abraham");
MODULE_LICENSE("GPL");