⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvb_ca_en50221.c

📁 Linux dvb-ci apifor use as an example
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <linux/errno.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <linux/sched.h>#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");#define dprintk if (dvb_ca_en50221_debug) printk#define INIT_TIMEOUT_SECS 10#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 STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)	/* general transfer error */#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;	/* 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 {	/* 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 */	pid_t thread_pid;	/* Wait queue used when shutting thread down */	wait_queue_head_t thread_queue;	/* Flag indicating when thread should exit */	unsigned int exit:1;	/* 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;};static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);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);/** * Safely find needle in haystack. * * @param haystack Buffer to look in. * @param hlen Number of bytes in haystack. * @param needle Buffer to find. * @param nlen Number of bytes in needle. * @return Pointer into haystack needle was found at, or NULL if not found. */static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen){	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 *//** * Check CAM status. */static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot){	int slot_status;	int cam_present_now;	int cam_changed;	/* IRQ mode */	if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {		return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);	}	/* 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) {		int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);		cam_changed = (cam_present_now != cam_present_old);	}	if (cam_changed) {		if (!cam_present_now) {			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;		} else {			ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;		}		atomic_set(&ca->slot_info[slot].camchange_count, 1);	} else {		if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&		    (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {			// move to validate state if reset is completed			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;		}	}	return cam_changed;}/** * Wait for flags to become set on the STATUS register on a CAM interface, * checking for errors and timeout. * * @param ca CA instance. * @param slot Slot on interface. * @param waitfor Flags to wait for. * @param timeout_ms Timeout in milliseconds. * * @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;	dprintk("%s\n", __FUNCTION__);	/* loop until timeout elapsed */	start = jiffies;	timeout = jiffies + timeout_hz;	while (1) {		/* read the status and check for error */		int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);		if (res < 0)			return -EIO;		/* if we got the flags, it was successful! */		if (res & waitfor) {			dprintk("%s succeeded timeout:%lu\n", __FUNCTION__, jiffies - start);			return 0;		}		/* check for timeout */		if (time_after(jiffies, timeout)) {			break;		}		/* wait for a bit */		msleep(1);	}	dprintk("%s failed timeout:%lu\n", __FUNCTION__, jiffies - start);	/* if we get here, we've timed out */	return -ETIMEDOUT;}/** * Initialise the link layer connection to a CAM. * * @param ca CA instance. * @param slot Slot id. * * @return 0 on success, nonzero on failure. */static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot){	int ret;	int buf_size;	u8 buf[2];	dprintk("%s\n", __FUNCTION__);	/* we'll be determining these during this function */	ca->slot_info[slot].da_irq_supported = 0;	/* set the host link buffer size temporarily. it will be overwritten with the	 * real negotiated size later. */	ca->slot_info[slot].link_buf_size = 2;	/* read the buffer size from the CAM */	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)		return ret;	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)		return ret;	if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)		return -EIO;	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)		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;	ca->slot_info[slot].link_buf_size = buf_size;	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 */	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)		return ret;	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)		return ret;	if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)		return -EIO;	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)		return ret;	/* success */	return 0;}/** * Read a tuple from attribute memory. * * @param ca CA instance. * @param slot Slot id. * @param address Address to read from. Updated. * @param tupleType Tuple id byte. Updated. * @param tupleLength Tuple length. Updated. * @param tuple Dest buffer for tuple (must be 256 bytes). Updated. * * @return 0 on success, nonzero on error. */static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,				     int *address, int *tupleType, int *tupleLength, u8 * tuple){	int i;	int _tupleType;	int _tupleLength;	int _address = *address;	/* grab the next tuple length and type */	if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)		return _tupleType;	if (_tupleType == 0xff) {		dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);		*address += 2;		*tupleType = _tupleType;		*tupleLength = 0;		return 0;	}	if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)		return _tupleLength;	_address += 4;	dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);	/* read in the whole tuple */	for (i = 0; i < _tupleLength; i++) {		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] : '.');	}	_address += (_tupleLength * 2);	// success	*tupleType = _tupleType;	*tupleLength = _tupleLength;	*address = _address;	return 0;}/** * Parse attribute memory of a CAM module, extracting Config register, and checking * it is a DVB CAM module. * * @param ca CA instance. * @param slot Slot id. * * @return 0 on success, <0 on failure. */static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot){	int address = 0;	int tupleLength;	int tupleType;	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;	// CISTPL_DEVICE_0A	if ((status =	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)		return status;	if (tupleType != 0x1D)		return -EINVAL;	// CISTPL_DEVICE_0C	if ((status =	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)		return status;	if (tupleType != 0x1C)		return -EINVAL;	// CISTPL_VERS_1	if ((status =	     dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)		return status;	if (tupleType != 0x15)		return -EINVAL;	// CISTPL_MANFID	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,						&tupleLength, tuple)) < 0)		return status;	if (tupleType != 0x20)		return -EINVAL;	if (tupleLength != 4)		return -EINVAL;	manfid = (tuple[1] << 8) | tuple[0];	devid = (tuple[3] << 8) | tuple[2];	// CISTPL_CONFIG	if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,						&tupleLength, tuple)) < 0)		return status;	if (tupleType != 0x1A)		return -EINVAL;	if (tupleLength < 3)		return -EINVAL;	/* extract the configbase */	rasz = tuple[0] & 3;	if (tupleLength < (3 + rasz + 14))		return -EINVAL;	ca->slot_info[slot].config_base = 0;	for (i = 0; i < rasz + 1; i++) {		ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));	}	/* check it contains the correct DVB string */	dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);	if (dvb_str == NULL)		return -EINVAL;	if (tupleLength < ((dvb_str - (char *) tuple) + 12))		return -EINVAL;	/* is it a version we support? */	if (strncmp(dvb_str + 8, "1.00", 4)) {		printk("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]);		return -EINVAL;	}	/* process the CFTABLE_ENTRY tuples, and any after those */	while ((!end_chain) && (address < 0x1000)) {		if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,							&tupleLength, tuple)) < 0)			return status;		switch (tupleType) {		case 0x1B:	// CISTPL_CFTABLE_ENTRY			if (tupleLength < (2 + 11 + 17))				break;			/* if we've already parsed one, just use it */			if (got_cftableentry)				break;			/* get the config option */			ca->slot_info[slot].config_option = tuple[0] & 0x3f;			/* OK, check it contains the correct strings */			if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||			    (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))				break;			got_cftableentry = 1;			break;		case 0x14:	// CISTPL_NO_LINK			break;		case 0xFF:	// CISTPL_END			end_chain = 1;			break;		default:	/* Unknown tuple type - just skip this tuple and move to the next one */			dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,				tupleLength);			break;		}	}	if ((address > 0x1000) || (!got_cftableentry))		return -EINVAL;	dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",		manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);	// success!	return 0;}/** * Set CAM's configoption correctly. * * @param ca CA instance. * @param slot Slot containing the CAM. */static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot){	int configoption;	dprintk("%s\n", __FUNCTION__);	/* set the config option */	ca->pub->write_attribute_mem(ca->pub, slot,				     ca->slot_info[slot].config_base,				     ca->slot_info[slot].config_option);	/* check it */	configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);	dprintk("Set configoption 0x%x, read configoption 0x%x\n",		ca->slot_info[slot].config_option, configoption & 0x3f);	/* fine! */	return 0;}/** * 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. * * @param ca CA instance. * @param slot Slot to read from. * @param ebuf If non-NULL, the data will be written to this buffer. If NULL, * the data will be added into the buffering system as a normal fragment. * @param ecount Size of ebuf. Ignored if ebuf is NULL. * * @return Number of bytes read, or < 0 on error */static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount){	int bytes_read;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -