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

📄 dvb_ca.c

📁 linux_dvb的驱动程序:linuxtv-dvb-1.1.1.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * dvb_ca.c: generic DVB CA functions * * Copyright (C) 2004 Andrew de Quincey * * 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 *//* * In the following, public functions always do locking of slots, private functions do not * necessarily do locking of slots - they may expect the caller to have locked */#include <linux/errno.h>#include <linux/slab.h>#include <linux/list.h>#include <linux/module.h>#include <asm/semaphore.h>#include "dvb_ca.h"#include "dvb_functions.h"static int dvb_ca_debug = 0;#define dprintk if (dvb_ca_debug) printk#define HOST_LINK_BUF_SIZE 0x200#define RX_BUFFER_SIZE 65540#define TX_BUFFER_SIZE 65540#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 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 */static int dvb_ca_en50221_link_init(struct dvb_ca* ca, int slot);static u8* findstr(u8* haystack, int hlen, u8* needle, int nlen) {        int i;        for(i=0; i<= hlen - nlen; i++) {                  if (!strncmp(haystack+i, needle, nlen)) return haystack+i;        }        return NULL;}/* ******************************************************************************** *//* Modified version of wait_event_interruptible so we can check for errors */#define __dvb_ca_wait_event_interruptible(wq, condition, ret)                 \do {                                                                          \        wait_queue_t __wait;                                                  \        init_waitqueue_entry(&__wait, current);                               \                                                                              \        add_wait_queue(&wq, &__wait);                                         \        for (;;) {                                                            \                set_current_state(TASK_INTERRUPTIBLE);                        \                if (ret = condition)                                          \                        break;                                                \                if (!signal_pending(current)) {                               \                        schedule();                                           \                        continue;                                             \                }                                                             \                ret = -ERESTARTSYS;                                           \                break;                                                        \        }                                                                     \        current->state = TASK_RUNNING;                                        \        remove_wait_queue(&wq, &__wait);                                      \} while (0)#define dvb_ca_wait_event_interruptible(wq, condition)                        \({                                                                            \        int __ret = 0;                                                        \        if (!(condition))                                                     \                __dvb_ca_wait_event_interruptible(wq, condition, __ret);      \        __ret;                                                                \})/* ******************************************************************************** *//* Functions for controlling access to slots *//** * Safely increment the usage counter for a CA slot. * * @param ca CA instance. * @param slot Slot concerned. * * @return 0 on success, <0 on failure. * */int dvb_ca_slot_acquire(struct dvb_ca* ca, int slot) {        int status;        if (status = down_interruptible(&ca->slot_info[slot].sem)) return status;        if (!ca->slot_info[slot].cam_present) {                up(&ca->slot_info[slot].sem);                return -EIO;        }        ca->slot_info[slot].usage_counter++;        up(&ca->slot_info[slot].sem);        return 0;}/** * Safely decrement the usage counter for a CA slot. * * @param ca CA instance. * @param slot Slot concerned. * * @return 0 on success, <0 on failure. * */int dvb_ca_slot_release(struct dvb_ca* ca, int slot) {        int status;        if (status = down_interruptible(&ca->slot_info[slot].sem)) return status;        ca->slot_info[slot].usage_counter--;        up(&ca->slot_info[slot].sem);        return(0);}/** * Acquire a slot exclusively. The slot semaphore will be left locked on successful * exit of this function. * * @param ca CA instance. * @param slot Slot concerned. * * @return 0 on success, <0 on failure. * */int dvb_ca_slot_acquire_exclusive(struct dvb_ca* ca, int slot) {        int status;        while(1) {                /* lock the slot */                if (status = down_interruptible(&ca->slot_info[slot].sem)) return status;                /* if there is no CAM, exit straight away */                if (!ca->slot_info[slot].cam_present) {                        up(&ca->slot_info[slot].sem);                        return -EIO;                }                /* if there are no other users of the slot, we've finished */                if (ca->slot_info[slot].usage_counter == 0) {                        ca->slot_info[slot].usage_counter++;                        break;                }                /* sleep a bit and try again */                up(&ca->slot_info[slot].sem);                dvb_delay(1);        }        /* DO NOT UNLOCK! */        return 0;}/** * Release an exclusively owned slot. The slot semaphore will be unlocked by this function. * * @param ca CA instance. * @param slot Slot concerned. * * @return 0 on success, <0 on failure. * */int dvb_ca_slot_release_exclusive(struct dvb_ca* ca, int slot) {        ca->slot_info[slot].usage_counter--;        up(&ca->slot_info[slot].sem);        return(0);}/* ******************************************************************************** *//* Functions for link level connection_ids *//** * Internal function to destroy and unlink a dvb_ca_connection structure. * * @param cacon The structure to destroy. * @param unlink If 1, it will be unlinked from the list. */static void dvb_ca_connection_destroy(struct dvb_ca_connection* cacon, int unlink) {        /* unlink it from the list. */        if (unlink)                list_del(&cacon->connection);        /* destroy buffers etc */        if (cacon->rx_buffer.data) vfree(cacon->rx_buffer.data);        if (cacon->tx_buffer.data) vfree(cacon->tx_buffer.data);        vfree(cacon);}/** * Get or create a dvb_ca_connection structure for a particular slot/connection_id. * * @param ca CA device instance. * @param slot Slot id. * @param connection_id Connection id to retrieve structure for. * @param create If 1, and a connection struct was not found, a new one will be created. * * @return A dvb_ca_connection structure, or NULL. */static struct dvb_ca_connection* dvb_ca_connection_get(struct dvb_ca* ca, int slot, int connection_id, int create) {        struct dvb_ca_connection* cacon;        u8* mem;        /* is there already a record for this connection_id */        list_for_each_entry(cacon, &ca->slot_info[slot].connections, next) {                /* if we found it, return it immediately */                if (cacon->connection_id == connection_id) {                        cacon->last_used = jiffies;                        return cacon;                }        }        /* if we get here, and we've been asked not to create a structure, just return NULL */        if (!create) {                return NULL;        }        /* did not find it => create a new connection */        cacon = vmalloc(sizeof(struct dvb_ca_connection));        if (cacon == NULL) {                goto error;        }        /* setup the structure */        memset(cacon, 0, sizeof(struct dvb_ca_connection));        cacon->connection_id = connection_id;        cacon->rx_partial_pkt = -1;        cacon->tx_partial_pkt_size = -1;        cacon->last_used = jiffies;        if (!(mem = vmalloc(RX_BUFFER_SIZE))) {                goto error;        }        dvb_ringbuffer_init(&cacon->rx_buffer, mem, RX_BUFFER_SIZE);        if (!(mem = vmalloc(TX_BUFFER_SIZE))) {                goto error;        }        dvb_ringbuffer_init(&cacon->tx_buffer, mem, TX_BUFFER_SIZE);        /* success */        list_add_tail(&cacon->next, &ca->slot_info[slot].connections);        return cacon;error:        if (cacon != NULL) {                dvb_ca_connection_destroy(cacon, 0);        }        return NULL;}/* ******************************************************************************** *//* EN50221 physical interface functions *//** * 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* ca, int slot, u8 waitfor, int timeout_ms) {        unsigned long timeout;        /* loop until timeout elapsed */        timeout = jiffies + ((HZ * timeout_ms) / 1000);        while(1) {                /* read the status and check for error */                int res = ca->read_cam_control(ca, slot, CTRLIF_STATUS);                if (res < 0) return -EIO;                /* if we got the flags, it was successful! */                if (res & waitfor) {                        return 0;                }                /* check for timeout */                if (time_after(jiffies,timeout)) {                        break;                }                /* wait for a bit */                mdelay(100); // FIXME: is this timeout good? need to investigate        }        /* if we get here, we've timed out */        return -ETIMEDOUT;}/** * Reset the CAM control interface. * * @param ca CA instance. * @param slot Slot id. * * @return 0 on success, nonzero on failure. */static int dvb_ca_en50221_reset_if(struct dvb_ca* ca, int slot) {        int ret;        /* reset the interface and wait for FR to be set */        if (ret = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, CMDREG_RS)) return ret;        if (ret = dvb_ca_cam_wait_if_status(ca, slot, STATUSREG_FR, 2)) return ret;

⌨️ 快捷键说明

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