dst_ca.c 20.9 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
/*
	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>
23
#include <linux/slab.h>
24
#include <linux/init.h>
25
#include <linux/mutex.h>
26 27 28 29 30 31 32
#include <linux/string.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
#include "dvb_frontend.h"
#include "dst_ca.h"
#include "dst_common.h"

33 34 35 36 37 38 39 40
#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))					\
41
			printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);	\
42
		else if	((x > DST_CA_NOTICE) && (x > y))				\
43
			printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);	\
44
		else if ((x > DST_CA_INFO) && (x > y))					\
45
			printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);	\
46
		else if ((x > DST_CA_DEBUG) && (x > y))					\
47
			printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);	\
48 49 50 51 52 53 54
	} else {									\
		if (x > y)								\
			printk(format, ## arg);						\
	}										\
} while(0)


55
static DEFINE_MUTEX(dst_ca_mutex);
56
static unsigned int verbose = 5;
57 58 59
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");

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

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

74 75 76 77 78 79 80
static void put_command_and_length(u8 *data, int command, int length)
{
	data[0] = (command >> 16) & 0xff;
	data[1] = (command >> 8) & 0xff;
	data[2] = command & 0xff;
	data[3] = length;
}
81

82
static void put_checksum(u8 *check_string, int length)
83
{
84 85 86 87
	dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
	dprintk(verbose, DST_CA_DEBUG, 1, "  -> string length : 0x%02x", length);
	check_string[length] = dst_check_sum (check_string, length);
	dprintk(verbose, DST_CA_DEBUG, 1, "  -> checksum      : 0x%02x", check_string[length]);
88 89 90 91 92 93
}

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

94
	mutex_lock(&state->dst_mutex);
95 96 97 98
	dst_comm_init(state);
	msleep(65);

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

error:
127
	mutex_unlock(&state->dst_mutex);
128
	return -EIO;
129 130 131 132 133 134 135 136
}


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) {
137
		dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
138 139 140
		if (dst_ci_command(state, data, ca_string, len, read)) {	// If error
			dst_error_recovery(state);
			dst_ca_comm_err++; // work required here.
141 142
		} else {
			break;
143 144 145
		}
	}

146 147 148
	if(dst_ca_comm_err == RETRIES)
		return -1;

149 150 151 152 153 154 155
	return 0;
}



static int ca_get_app_info(struct dst_state *state)
{
156
	int length, str_length;
157 158 159 160
	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) {
161
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
162 163
		return -1;
	}
164 165 166 167
	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],
168
		(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
169
	dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
170

171 172 173 174 175 176 177 178 179 180 181 182
	// Transform dst message to correct application_info message
	length = state->messages[5];
	str_length = length - 6;
	if (str_length < 0) {
		str_length = 0;
		dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
	}

	// First, the command and length fields
	put_command_and_length(&state->messages[0], CA_APP_INFO, length);

	// Copy application_type, application_manufacturer and manufacturer_code
183
	memmove(&state->messages[4], &state->messages[7], 5);
184 185 186

	// Set string length and copy string
	state->messages[9] = str_length;
187
	memmove(&state->messages[10], &state->messages[12], str_length);
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

	return 0;
}

static int ca_get_ca_info(struct dst_state *state)
{
	int srcPtr, dstPtr, i, num_ids;
	static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
	const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;

	put_checksum(&slot_command[0], slot_command[0]);
	if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
		return -1;
	}
	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");

	// Print raw data
	dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
	for (i = 0; i < state->messages[0] + 1; i++) {
		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
	}
	dprintk(verbose, DST_CA_INFO, 0, "]\n");

	// Set the command and length of the output
	num_ids = state->messages[in_num_ids_pos];
	if (num_ids >= 100) {
		num_ids = 100;
		dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
	}
	put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);

	dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
	srcPtr = in_system_id_pos;
	dstPtr = out_system_id_pos;
	for(i = 0; i < num_ids; i++) {
		dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
		// Append to output
		state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
		state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
		srcPtr += 2;
		dstPtr += 2;
	}
	dprintk(verbose, DST_CA_INFO, 0, "]\n");

233 234 235
	return 0;
}

P
Peter Hagervall 已提交
236
static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
237 238 239 240 241 242 243
{
	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) {
244
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
245 246
		return -1;
	}
247
	dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
248 249 250

	/*	Will implement the rest soon		*/

251 252
	dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
	dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
253
	for (i = 0; i < slot_cap[0] + 1; i++)
254 255
		dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
	dprintk(verbose, DST_CA_INFO, 0, "\n");
256 257 258 259 260 261

	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;

P
Peter Hagervall 已提交
262
	if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
263 264 265 266 267
		return -EFAULT;

	return 0;
}

268
/*	Need some more work	*/
P
Peter Hagervall 已提交
269
static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
270 271 272 273 274
{
	return -EOPNOTSUPP;
}


P
Peter Hagervall 已提交
275
static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
276 277 278 279
{
	int i;
	static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};

280
	u8 *slot_info = state->messages;
281 282 283

	put_checksum(&slot_command[0], 7);
	if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
284
		dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
285 286
		return -1;
	}
287
	dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
288 289 290

	/*	Will implement the rest soon		*/

291 292 293 294 295
	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");
296 297 298 299 300

	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;
301
	} else if (slot_info[4] & 0x40) {
302 303 304
		p_ca_slot_info->flags = CA_CI_MODULE_READY;
		p_ca_slot_info->num = 1;
		p_ca_slot_info->type = CA_CI;
305
	} else
306 307
		p_ca_slot_info->flags = 0;

P
Peter Hagervall 已提交
308
	if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
309 310 311 312 313 314
		return -EFAULT;

	return 0;
}


P
Peter Hagervall 已提交
315
static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
316 317 318 319
{
	u8 i = 0;
	u32 command = 0;

P
Peter Hagervall 已提交
320
	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
321 322
		return -EFAULT;

323 324
	dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]",
		3, p_ca_message->msg);
325

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
	for (i = 0; i < 3; i++) {
		command = command | p_ca_message->msg[i];
		if (i < 2)
			command = command << 8;
	}
	dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);

	switch (command) {
	case CA_APP_INFO:
		memcpy(p_ca_message->msg, state->messages, 128);
		if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
			return -EFAULT;
		break;
	case CA_INFO:
		memcpy(p_ca_message->msg, state->messages, 128);
		if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
			return -EFAULT;
		break;
344 345 346 347 348
	}

	return 0;
}

349
static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
350
{
351
	if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
352 353 354 355
		hw_buffer->msg[2] = p_ca_message->msg[1];	/*	MSB	*/
		hw_buffer->msg[3] = p_ca_message->msg[2];	/*	LSB	*/
	} else {
		if (length > 247) {
356
			dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
357 358
			return -1;
		}
359 360
		hw_buffer->msg[0] = (length & 0xff) + 7;
		hw_buffer->msg[1] = 0x40;
361 362
		hw_buffer->msg[2] = 0x03;
		hw_buffer->msg[3] = 0x00;
363 364 365
		hw_buffer->msg[4] = 0x03;
		hw_buffer->msg[5] = length & 0xff;
		hw_buffer->msg[6] = 0x00;
366

367 368 369 370 371
		/*
		 *	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);
372
	}
373

374 375 376
	return 0;
}

377
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
378
{
379
	if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
380 381
		dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
		dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
382 383 384
		rdc_reset_state(state);
		return -1;
	}
385
	dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
386 387 388 389

	return 0;
}

P
Peter Hagervall 已提交
390
static u32 asn_1_decode(u8 *asn_1_array)
391
{
392 393 394 395
	u8 length_field = 0, word_count = 0, count = 0;
	u32 length = 0;

	length_field = asn_1_array[0];
396
	dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
397 398
	if (length_field < 0x80) {
		length = length_field & 0x7f;
399
		dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
400 401 402
	} else {
		word_count = length_field & 0x7f;
		for (count = 0; count < word_count; count++) {
403 404
			length = length  << 8;
			length += asn_1_array[count + 1];
405
			dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
406 407
		}
	}
408 409
	return length;
}
410

411 412 413
static int debug_string(u8 *msg, u32 length, u32 offset)
{
	u32 i;
414

415
	dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
416
	for (i = offset; i < length; i++)
417 418
		dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
	dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
419

420 421
	return 0;
}
422

M
Manu Abraham 已提交
423

424 425
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
426 427
	u32 length = 0;
	u8 tag_length = 8;
428

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

433
	memset(hw_buffer->msg, '\0', length);
434
	handle_dst_tag(state, p_ca_message, hw_buffer, length);
435
	put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
436

437 438
	debug_string(hw_buffer->msg, (length + tag_length), 0); /*	tags too	*/
	write_to_8820(state, hw_buffer, (length + tag_length), reply);
439 440 441 442

	return 0;
}

443

444 445 446 447 448 449 450 451 452 453 454
/*	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) {
455
			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
456 457 458 459 460
			return -1;
		}

	/*	Process CA PMT Reply		*/
	/*	will implement soon		*/
461
		dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
462 463 464 465
	}
	/*	CA PMT Reply not capable	*/
	if (!ca_pmt_reply_test) {
		if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
466
			dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
467 468
			return -1;
		}
469
		dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
470 471 472 473 474 475
	/*	put a dummy message		*/

	}
	return 0;
}

P
Peter Hagervall 已提交
476
static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
477 478 479 480 481
{
	int i = 0;

	u32 command = 0;
	struct ca_msg *hw_buffer;
482
	int result = 0;
483

484
	if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
485
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
486 487
		return -ENOMEM;
	}
488
	dprintk(verbose, DST_CA_DEBUG, 1, " ");
489

490
	if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
491 492 493 494
		result = -EFAULT;
		goto free_mem_and_exit;
	}

495 496
	/*	EN50221 tag	*/
	command = 0;
497

498 499 500 501 502 503 504 505 506 507 508 509 510 511
	for (i = 0; i < 3; i++) {
		command = command | p_ca_message->msg[i];
		if (i < 2)
			command = command << 8;
	}
	dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);

	switch (command) {
	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 !");
			result = -1;
			goto free_mem_and_exit;
512
		}
513 514 515 516 517 518 519 520 521
		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 !");
			result = -1;
			goto free_mem_and_exit;
522
		}
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
		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 !");
			result = -1;
			goto free_mem_and_exit;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
		break;
	case CA_INFO_ENQUIRY:
		dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");

		if ((ca_get_ca_info(state)) < 0) {
			dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
			result = -1;
			goto free_mem_and_exit;
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
		break;
545
	}
546

547 548 549 550
free_mem_and_exit:
	kfree (hw_buffer);

	return result;
551 552
}

553
static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
554
{
555 556
	struct dvb_device *dvbdev;
	struct dst_state *state;
557 558 559
	struct ca_slot_info *p_ca_slot_info;
	struct ca_caps *p_ca_caps;
	struct ca_msg *p_ca_message;
P
Peter Hagervall 已提交
560
	void __user *arg = (void __user *)ioctl_arg;
561
	int result = 0;
562

563
	mutex_lock(&dst_ca_mutex);
564
	dvbdev = file->private_data;
565
	state = (struct dst_state *)dvbdev->priv;
566 567 568 569
	p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
	p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
	p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
	if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
570
		dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
571 572
		result = -ENOMEM;
		goto free_mem_and_exit;
573
	}
574

575 576
	/*	We have now only the standard ioctl's, the driver is upposed to handle internals.	*/
	switch (cmd) {
577 578 579 580
	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 !");
581 582
			result = -1;
			goto free_mem_and_exit;
583 584 585 586 587 588
		}
		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 !");
589 590
			result = -1;
			goto free_mem_and_exit;
591 592 593 594 595 596 597 598 599 600 601 602
		}
		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 !");
603 604
			result = -1;
			goto free_mem_and_exit;
605 606 607 608 609 610 611
		}
		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 !");
612 613
			result = -1;
			goto free_mem_and_exit;
614 615 616 617 618 619 620
		}
		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 !");
621 622
			result = -1;
			goto free_mem_and_exit;
623 624 625 626 627 628 629
		}
		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 !");
630 631
			result = -1;
			goto free_mem_and_exit;
632 633 634 635 636 637 638
		}
		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 !");
639 640
			result = -1;
			goto free_mem_and_exit;
641 642 643
		}
		dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
	default:
644
		result = -EOPNOTSUPP;
645
	}
646 647 648 649
 free_mem_and_exit:
	kfree (p_ca_message);
	kfree (p_ca_slot_info);
	kfree (p_ca_caps);
650

651
	mutex_unlock(&dst_ca_mutex);
652
	return result;
653 654 655 656
}

static int dst_ca_open(struct inode *inode, struct file *file)
{
657
	dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
658 659 660 661 662 663 664
	try_module_get(THIS_MODULE);

	return 0;
}

static int dst_ca_release(struct inode *inode, struct file *file)
{
665
	dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
666 667 668 669 670
	module_put(THIS_MODULE);

	return 0;
}

671
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
672
{
673
	dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
674

675
	return 0;
676 677
}

678
static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
679
{
680
	dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
681 682 683 684

	return 0;
}

685
static const struct file_operations dst_ca_fops = {
686
	.owner = THIS_MODULE,
687
	.unlocked_ioctl = dst_ca_ioctl,
688 689 690
	.open = dst_ca_open,
	.release = dst_ca_release,
	.read = dst_ca_read,
691 692
	.write = dst_ca_write,
	.llseek = noop_llseek,
693 694 695 696 697 698 699 700 701 702
};

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

703
struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
704 705
{
	struct dvb_device *dvbdev;
706

707
	dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
708 709 710 711 712 713
	if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
		dst->dst_ca = dvbdev;
		return dst->dst_ca;
	}

	return NULL;
714 715 716 717 718 719 720
}

EXPORT_SYMBOL(dst_ca_attach);

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