dvb_ca_en50221.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,628 行 · 第 1/4 页

C
1,628
字号
        // 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: Unsupported DVB CAM module version %c%c%c%c\n",                        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;        int status;        u8 buf[HOST_LINK_BUF_SIZE];        int i;        dprintk ("%s\n", __FUNCTION__);        /* acquire the slot */        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;        /* check if we have space for a link buf in the rx_buffer */        if (ebuf == NULL) {                if (dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer) <                    (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {                        status = -EAGAIN;                        goto exit;                }        }        /* reset the interface if there's been a tx error */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;        if (status & STATUSREG_TXERR) {                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;                status = -EIO;                goto exit;        }        if (!(status & STATUSREG_DA)) {                /* no data */                status = 0;                goto exit;        }        /* read the amount of data */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) goto exit;        bytes_read = status << 8;        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) goto exit;        bytes_read |= status;        /* check it will fit */        if (ebuf == NULL) {                if (bytes_read > ca->slot_info[slot].link_buf_size) {                        printk("dvb_ca: CAM tried to send a buffer larger than the link buffer size!\n");                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;                        status = -EIO;                        goto exit;                }                if (bytes_read < 2) {                        printk("dvb_ca: CAM sent a buffer that was less than 2 bytes!\n");                        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;                        status = -EIO;                        goto exit;                }        } else {                if (bytes_read > ecount) {                        printk("dvb_ca: CAM tried to send a buffer larger than the ecount size!\n");                        status = -EIO;                        goto exit;                }        }        /* fill the buffer */        for(i=0; i < bytes_read; i++) {                /* read byte and check */                if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) goto exit;                /* OK, store it in the buffer */                buf[i] = status;        }        /* check for read error (RE should now go to 0) */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;        if (status & STATUSREG_RE) {                status = -EIO;                goto exit;        }        /* OK, add it to the receive buffer, or copy into external buffer if supplied */        if (ebuf == NULL) {                dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);        } else {                memcpy(ebuf, buf, bytes_read);        }        /* wake up readers when a last_fragment is received */        if ((buf[1] & 0x80) == 0x00) {                wake_up_interruptible(&ca->wait_queue);        }        status = bytes_read;exit:        up(&ca->slot_info[slot].sem);        return status;}/** * This function talks to an EN50221 CAM control interface. It writes a buffer of data * to a CAM. * * @param ca CA instance. * @param slot Slot to write to. * @param ebuf The data in this buffer is treated as a complete link-level packet to * be written. * @param count Size of ebuf. * * @return Number of bytes written, or < 0 on error. */static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* buf, int bytes_write){        int status;        int i;        dprintk ("%s\n", __FUNCTION__);        // sanity check        if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL;        /* acquire the slot */        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;        /* reset the interface if there's been a tx error */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite;        if (status & STATUSREG_TXERR) {                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;                status = -EIO;                goto exitnowrite;        }        /* check if interface is actually waiting for us to read from it */        if (status & STATUSREG_DA) {                status = -EAGAIN;                goto exitnowrite;        }        /* OK, set HC bit */        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_HC)) != 0) goto exit;        /* check if interface is still free */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;        if (!(status & STATUSREG_FR)) {                /* it wasn't free => try again later */                status = -EAGAIN;                goto exit;        }        /* send the amount of data */        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit;        if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, bytes_write & 0xff)) != 0) goto exit;        /* send the buffer */        for(i=0; i < bytes_write; i++) {                if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) goto exit;        }        /* check for write error (WE should now be 0) */        if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;        if (status & STATUSREG_WE) {                status = -EIO;                goto exit;        }        status = bytes_write;exit:        ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);exitnowrite:        up(&ca->slot_info[slot].sem);        return status;}/* ******************************************************************************** *//* EN50221 higher level functions *//** * 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_private* ca, int slot){        int status;        dprintk ("%s\n", __FUNCTION__);        if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;        ca->pub->slot_shutdown(ca->pub, slot);        ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;        if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data);        ca->slot_info[slot].rx_buffer.data = NULL;        up(&ca->slot_info[slot].sem);        /* need to wake up all processes to check if they're now           trying to write to a defunct CAM */        wake_up_interruptible(&ca->wait_queue);        dprintk("Slot %i shutdown\n", slot);        /* success */        return 0;}/** * A CAMCHANGE IRQ has occurred. * * @param ca CA instance. * @param slot Slot concerned. * @param change_type One of the DVB_CA_CAMCHANGE_* values. */void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type){        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;        dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);        switch(change_type) {        case DVB_CA_EN50221_CAMCHANGE_REMOVED:        case DVB_CA_EN50221_CAMCHANGE_INSERTED:                break;        default:                return;        }        ca->slot_info[slot].camchange_type = change_type;        atomic_inc(&ca->slot_info[slot].camchange_count);        dvb_ca_en50221_thread_wakeup(ca);}/** * A CAMREADY IRQ has occurred. * * @param ca CA instance. * @param slot Slot concerned. */void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot){        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;        dprintk("CAMREADY IRQ slot:%i\n", slot);        if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {                ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;                dvb_ca_en50221_thread_wakeup(ca);        }}/** * An FR or DA IRQ has occurred. * * @param ca CA instance. * @param slot Slot concerned. */void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot){        struct dvb_ca_private* ca = (struct dvb_ca_private*) pubca->private;        int flags;        dprintk("FR/DA IRQ slot:%i\n", slot);        switch(ca->slot_info[slot].slot_state) {

⌨️ 快捷键说明

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