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

📄 dvb_ca.c

📁 linux_dvb的驱动程序:linuxtv-dvb-1.1.1.rar
💻 C
📖 第 1 页 / 共 5 页
字号:
        if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit;        if (!(status & STATUSREG_FR)) {                /* it wasn't free => try again later */                res = -EAGAIN;                goto exit;        }        /* grab some data to send */        bytes_write = dvb_ca_buf_copy_to_cam(ca, buf + 2, ca->slot_info[i].link_buf_size - 2, &last_fragment, slot, connection_id);        if (bytes_write <= 0) {                res = bytes_write;                goto exit;        }        /* setup the buffer header */        buf[0] = connection_id;        buf[1] = last_fragment ? 0 : 0x80;        bytes_write += 2; // for the header        /* send the amount of data */        if (status = ca->write_cam_control(ca, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) goto exit;        if (status = ca->write_cam_control(ca, slot, CTRLIF_SIZE_LOW, bytes_write & 0xff)) goto exit;        /* send the buffer */        for(i=0; i < bytes_read; i++) {                if (status = ca->write_cam_control(ca, slot, CTRLIF_DATA, ca->slot_info[slot].link_buf[i])) goto exit;                /* At this point, WE=1, FR=0 during the transfer */        }        /* check for write error (WE should now be 0) */        if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit;        if (status & STATUSREG_WE) {                res = -EIO;                goto exit;        }        /* return the number of bytes read */        status = bytes_write;exit:        ca->write_cam_control(ca, slot, CTRLIF_COMMAND, 0);        dvb_ca_slot_release(ca, slot);        return status;}/** * A CAM has been inserted => initialise it. * * @param ca CA instance. * @param slot Slot containing the CAM to initialise. */static int dvb_ca_en50221_slot_init(struct dvb_ca* ca, int slot) {        int status;        dprintk ("%s\n", __FUNCTION__);        /* acquire the slot exclusively */        if (status = dvb_ca_slot_acquire_exclusive(ca, slot)) return status;        /* reset slot */        ca->slot_reset(ca, slot);        /* check it is a DVB cam and get hardware info */        if (status = dvb_ca_en50221_parse_attributes(ca, slot)) {                dvb_ca_slot_release_exclusive(ca, slot);                return status;        }        /* setup CAM hardware */        if (status = dvb_ca_en50221_init(ca, slot)) {                dvb_ca_slot_release_exclusive(ca, slot);                return status;        }        /* perform CAM link protocol init */        if (status = dvb_ca_en50221_link_init(ca, slot)) {                dvb_ca_slot_release_exclusive(ca, slot);                return status;        }        /* OK, slot is now active */        INIT_LIST_HEAD(&ca->slot[info].connections);        init_MUTEX(&ca->slot_info[slot].task_sem);        ca->slot_info[slot].tasks = 0;        ca->slot_info[slot].cam_present = 1;        /* success */        dvb_ca_slot_release_exclusive(ca, slot);        return 0;}/** * A CAM has been removed => shut it down. * * @param ca CA instance. * @param slot Slot to shut down. */static int dvb_ca_en50221_slot_shutdown(struct dvb_ca* ca, int slot) {        struct dvb_ca_connection* cacon;        struct dvb_ca_connection* tmp;        int status;        dprintk ("%s\n", __FUNCTION__);        /* acquire the slot exclusively */        if (status = dvb_ca_slot_acquire_exclusive(ca, slot)) return status;        /* there is no longer a CAM present in this slot */        ca->slot_info[slot].cam_present = 0;        /* bypass the TS feed to that slot, then reset it */        ca->slot_ts_bypass(ca, slot, 1);        ca->slot_reset(ca, slot);        /* flush the buffers on this slot */        /* cannot use dvb_ca_buf_flush_buffers() here because it locks exclusively as well */        list_for_each_entry_safe(cacon, tmp, &ca->slot_info[slot].connections, next) {                dvb_ca_connection_destroy(cacon, 1);        }        /* finished modifying slot structures */        dvb_ca_slot_release_exclusive(ca, slot);        /* need to wake up all read and write processes to check if they're now           trying to write to a defunct CAM */        wake_up_interruptible(&ca->read_queue);        wake_up_interruptible(&ca->write_queue);        /* success */        return 0;}/* ******************************************************************************** *//* Monitoring thread *//** * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. */static int dvb_ca_thread(void* data) {        struct dvb_ca *ca = (struct dvb_ca*) data;        struct dvb_ca_connection* cacon;        struct dvb_ca_connection* tmp;        char name[15];        int slot;        unsigned long scan_connections = jiffies + (60*HZ);        dprintk ("%s\n", __FUNCTION__);        /* setup kernel thread */        snprintf(name, sizeof(name), "kdvb-ca");        dvb_kernel_thread_setup(name);        /* main loop */        while(!ca->exit) {                up (&ca->thread_sem);      /* is locked when we enter the thread... */                /* sleep for a bit */                interruptible_sleep_on_timeout(&ca->thread_queue, HZ/10);                if (signal_pending(current)) break;                if (down_interruptible(&ca->thread_sem)) break;                if (ca->exit) break;                /* go through all the slots looking for CAM changes */                for(slot=0; slot < ca->slot_count; slot++) {                        /* poll for CAM changes if there aren't any IRQs for that                         * OR: if we've had a CAM_CHANGE task set */                        if ((!(ca->flags & DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE)) ||                            (ca->slot_info[slot].tasks & DVB_CA_TASK_CAM_CHANGED)) {                                /* determine the hardware status of the CAM */                                int slot_status = ca->slot_status(ca, slot);                                int cam_present = (slot_status & DVB_CA_SLOT_CAM_PRESENT) ? 1: 0;                                int cam_changed = (slot_status & DVB_CA_SLOT_CAM_CHANGED) ? 1: 0;                                if (!cam_changed) {                                        cam_changed = (cam_present != ca->slot_info[slot].cam_present);                                }                                /* if cam status has changed => update */                                if (cam_changed) {                                        if (cam_present) dvb_ca_en50221_cam_slot_init(ca, slot);                                        else dvb_ca_en50221_cam_slot_shutdown(ca, slot);                                }                        }                        /* do any reading and writing necessary */                        if (ca->open && (ca->slot_info[slot].cam_present)) {                                // FIXME: sort it out!                                /* if the CAM or the CI interface itself doesn't support IRQs, need to poll for reads */                                if ((!ca->slot_info[slot].irq_supported) || (!ca->flags & DVB_CA_FLAG_EN50221_IRQ_READ)) {                                        /* if there is data to be read, read it! */                                        while(dvb_ca_cam_read_data(ca, slot) > 0);                                }                        }                        /* tidy up any defunct connection structures every 60 seconds */                        if ((ca->slot_info[slot].cam_present) && (time_after(jiffies, scan_connections))) {                                if (status = dvb_ca_slot_acquire_exclusive(ca, slot)) break;                                list_for_each_entry_safe(cacon, tmp, &ca->slot_info[slot].connections, next) {                                        /* tear down a connection structure if it hasn't been used for 120 seconds */                                        unsigned long timeout = cacon->last_used + (120 * HZ);                                        if (time_after(jiffies, timeout)) {                                                dvb_ca_connection_destroy(cacon, 1);                                        }                                }                                dvb_ca_slot_release_exclusive(ca, slot);                        }                }        }        up(&ca->thread_sem);        mb();        /* completed */        wake_up_interruptible (&ca->thread_queue);        return(0);}/* ******************************************************************************** *//* Packet buffer functions *//** * Flush buffers associated with a particular CA slot. * * @param ca CA instance. * @param slot Slot whose buffers are to be to flushed. * * @return 0 on success, <0 on failure. */int dvb_ca_buf_flush_buffers(struct dvb_ca* ca, int slot) {        struct dvb_ca_connection* cacon;        struct dvb_ca_connection* tmp;        int status;        if (status = dvb_ca_slot_acquire_exclusive(ca, slot)) return status;        /* just destroy all the connections for this slot */        list_for_each_entry_safe(cacon, tmp, &ca->slot_info[slot].connections, next) {                dvb_ca_connection_destroy(cacon, 1);        }        dvb_ca_slot_release_exclusive(ca, slot);        return 0;}/** * This function does not talk to a CAM; it is a utility function for grabbing data from the * connection buffers in chunks suitable for use by hardware-dependent code. * * Copy data to be sent to the CAM from the cache into the * supplied buffer. This call is for lower layers to get data still to * be sent to the CAM. The buffer is filled by the layers which receive data * from userspace. * * @param ca CA instance. * @param dest Where to put the data. * @param len Size of destination buffer. * @param last_fragment. This will be set to 1 if this is the last fragment of a packet, *                       or 0 if there is still more data in this packet to be transmitted. * @param slot Slot concerned. * @param connection_id Connection id concerned. * * @return Number of bytes copied to dest, or <0 on error. */int dvb_ca_buf_copy_to_cam(dvb_ca* ca, u8 *dest, int len, u8* last_fragment, u8 slot, u8 connection_id){        struct dvb_ca_connection* cacon;        int status;        /* in the buffer, each packet has a 3 byte header as follows:           0: High byte of total packet size.           1: Low byte of total packet size.           2: Flag byte. 0=> packet incomplete. 1=> packet complete.           These are all updated as data fragments are appended to the packet.        */        /* acquire the slot */        if (status = dvb_ca_slot_acquire(ca, slot)) return status;        /* get the connection struct for this slot/connection id */        cacon = dvb_ca_connection_get(ca, slot, connection_id, 0);        /* if we didn't find a connection struct, there is no data! */        if (cacon == NULL) {                dvb_ca_slot_release(ca, slot);                *last_fragment = 1;                return 0;        }        /* if there is no data, there is no point going on */        if (dvb_ringbuffer_avail(&cacon->tx_buffer) == 0) {                dvb_ca_slot_release(ca, slot);                *last_fragment = 1;                return 0;        }        /* if we're not in the middle of sending a packet... */        if (cacon->tx_partial_pkt_size == -1);                /* ensure there is actually enough data for a header */                if (dvb_ringbuffer_avail(&cacon->tx_buffer) < 3) {                        dvb_ca_slot_release(ca, slot);                        *last_fragment = 1;                        return 0;                }                /* if the packet data is not available yet, exit straight away */                if (DVB_RINGBUFFER_PEEK(&cacon->tx_buffer, 2) != 1) {                        dvb_ca_slot_release(ca, slot);                        *last_fragment = 1;                        return 0;                }                /* get the size of the next packet */                cacon->tx_partial_pkt_size = DVB_RINGBUFFER_PEEK(&cacon->tx_buffer, 0) << 8;                cacon->tx_partial_pkt_size |= DVB_RINGBUFFER_PEEK(&cacon->tx_buffer, 1);                DVB_RINGBUFFER_SKIP(&cacon->tx_buffer, 3);        }        /* don't copy more data than is actually available */        if (cacon->tx_partial_pkt_size < len) len = cacon->partial_pkt_size;        /* copy the data into dest */        dvb_ringbuffer_read(&cacon->tx_buffer, dest, len, 0);        /* update the amount of consumed data */        cacon->tx_partial_pkt_size -= len;        if (cacon->tx_partial_pkt_size == 0) {                /* whole packet consumed => move to next */                cacon->tx_partial_pkt_size = -1;                /* wake up the wait queues now writing is completed */                wake_up_interruptible(&ca->read_queue);                wake_up_interruptible(&ca->write_queue);        }        /* ok, return the amount of data copied this time */        *last_fragment = (cacon->tx_partial_pkt_size == -1) ? 1 : 0;        dvb_ca_slot_release(ca, slot);        return len;

⌨️ 快捷键说明

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