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

📄 dvb_ca_en50221.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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/rwsem.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 5#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;        /* semaphore for syncing access to slot structure */        struct rw_semaphore sem;        /* 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 */        int exit:1;        /* Flag indicating if the CA device is open */        int open:1;        /* Flag indicating the thread should wake up now */        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

⌨️ 快捷键说明

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