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 + -
显示快捷键?