📄 dvb_ca.c
字号:
/* need to perform link initialisation again */ return dvb_ca_en50221_link_init(ca, slot);}/** * 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* ca, int slot) { int ret; int buf_size; u8 buf[2]; /* reset the interface */ if (ret = dvb_ca_en50221_reset_if(ca, slot)) return ret; /* set the host link buffer size temporarily. it will be overwritten with the * real negotiated size later. */ ca->slot_info[i]->link_buf_size = 2; /* OK, setup to read the buffer size */ if (ret = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, CMDREG_SR)) return ret; if (ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, 2)) return ret; /* read the buffer size from the CAM */ if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) return ret; /* set everything back to 0 again */ if (ret = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, 0)) return ret; /* store it, and choose the minimum of our buffer and the CAM's buffer size */ bufsize = (buf[0] << 8) | buf[1]; if (bufsize > HOST_LINK_BUF_SIZE) bufsize = HOST_LINK_BUF_SIZE; ca->slot_info[i]->link_buf_size = bufsize; /* setup the buffer size in the link_buf */ buf[0] = bufsize >> 8; buf[1] = bufsize & 0xff; /* OK, setup to write chosen buffer size to CAM */ if (ret = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, CMDREG_SW)) return ret; if (ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, 2)) return ret; /* write the buffer size to the CAM */ if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) return ret; /* set everything back to 0 again */ if (ret = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, 0)) return ret; /* success */ 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* ca, int slot) { int address = 0; int tupleLength; int tupleType; char tuple[257]; char* dvb_str; int i; int rasz; int got_device0a = 0; int got_device0c = 0; int got_vers1 = 0; int got_manfid = 0; int got_config = 0; int got_cftableentry = 0; int end_chain = 0; while(!end_chain) { /* grab the next tuple length and type */ if ((tupleType = ca->read_attribute_mem(ca, slot, address++)) < 0) return tupleType; if ((tupleLength = ca->read_attribute_mem(ca, slot, address++)) < 0) return tupleLength; /* read in the whole tuple */ for(i=0; i< tupleLength; i++) { tuple[i] = ca->read_attribute_mem(ca, slot, address+i); } address += tupleLength; /* deal with the types of tuple */ switch(tupleType) { case 0x1D: // CISTPL_DEVICE_0A got_device0a = 1; break; /* don't bother parsing */ case 0x1C: // CISTPL_DEVICE_0C got_device0c = 1; break; /* don't bother parsng */ case 0x15: // CISTPL_VERS_1 got_vers1 = 1; break; /* don't bother parsing */ case 0x20: // CISTPL_MANFID /* check tuple length is valid */ if (tupleLength != 4) break; /* OK, extract manid and devid */ ca->slot_info[i].manid = (tuple[1] << 8) | tuple[0]; ca->slot_info[i].devid = (tuple[3] << 8) | tuple[2]; got_manfid = 1; break; case 0x1A: // CISTPL_CONFIG /* check tuple length is valid */ if (tupleLength < 3) break; /* OK, grab length of configbase */ rasz = tuple[0] & 3; /* check there is enough space for everything */ if (tupleLength < (3 + rasz + 14)) break; /* extract the configbase */ ca->slot_info[i].config_base = 0; for(i=0; i< rasz+1; i++) { ca->slot_info[i].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) break; if (tupleLength < ((dvb_str - tuple) + 12)) break; /* 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; } got_config = 1; break; case 0x1D: // CISTPL_CFTABLE_ENTRY if (tupleLength < (2+11+17)) break; /* get the config option */ ca->slot_info[i].config_option = tuple[0] & 0x3f; /* does it contain an interrupt descriptor structure? */ i = 1; if (tuple[0] & 0x80) i++; if (tuple[i] & 0x10) { ca->slot_info[i].irq_supported = 1; } else ca->slot_info[i].irq_supported = 0; } /* 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 0xFF: // end of chain end_chain = true; break; default: /* Unknown tuple type */ /* just skip this tuple and move to the next one */ break; } } // OK, did we get everything we were looking for? if (!got_device0a || !got_device0c || !got_vers1 || !got_manfid || !got_config || !got_cftablenentry) { printk("dvb_ca: Non-CAM PC card detected\n"); return -EINVAL; } // success! return 0;}/** * Initialise a CAM module. * * @param ca CA instance. * @param slot Slot containing the CAM. */static void dvb_ca_en50221_init(struct dvb_ca* ca, int slot) { int tmp; /* reset the CAM module */ tmp = ca->read_attribute_mem(ca, slot, ca->slot_info[slot].config_base); ca->write_attribute_mem(ca, slot, ca->slot_info[slot].config_base, tmp | 0x80); dvb_delay(1); ca->write_attribute_mem(ca, slot, ca->slot_info[slot].config_base, tmp); dvb_delay(1); /* set the config option */ tmp = (tmp & 0x3f) | ca->slot_info[slot].config_option; ca->write_attribute_mem(ca, slot, ca->slot_info[slot].config_base, tmp);}/** * 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 correct place in the CA slot/connection buffer structures. * * @param ca CA instance. * @param slot Slot to read from. * @param buf 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 count Size of buf. Ignored if buf is NULL. * * @return Number of bytes read, or < 0 on error */static int dvb_ca_en50221_read_data(struct dvb_ca* ca, int slot, u8* buf, int count) { int bytes_read; int status; u8 buf[HOST_LINK_BUF_SIZE]; u8 last_fragment; u8 connection_id; /* if the CA device is not open, do not attempt to receive data from it */ if (!ca->open) return -EIO; /* acquire the slot */ if (status = dvb_ca_slot_acquire(ca, slot)) return status; /* reset the interface if there's been a tx error */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit; if (status & STATUSREG_TXERR) dvb_ca_en50221_reset_if(ca, slot); /* check if data is available */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit; if (!(status & STATUSREG_DA)) { /* no data */ status = 0; goto exit; } /* read the amount of data */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_SIZE_HIGH)) < 0) goto exit; bytes_read = status << 8; if ((status = ca->read_cam_control(ca, slot, CTRLIF_SIZE_LOW)) < 0) goto exit; bytes_read |= status; /* check it will fit */ if (bytes_read > ca->slot_info[i].link_buf_size) { printk("dvb_ca: CAM tried to send a buffer larger than the link buffer size!\n"); status = -EIO; goto exit; } /* fill the buffer */ for(i=0; i < bytes_read; i++) { /* read byte and check */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_DATA)) < 0) goto exit; /* OK, store it in the buffer */ buf[i] = res; /* at this point, RE=1, DA=0 during the transfer */ } /* check for read error (RE should now go to 0) */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit; if (status & STATUSREG_RE) { status = -EIO; goto exit; } /* check there are at least two bytes received! */ if (bytes_read < 2) { printk("dvb_ca: CAM sent a buffer that was less than 2 bytes!\n"); status = -EIO; goto exit; } /* extract information about this buffer */ connection_id = buf[0]; last_fragment = (buf[1] & 0x80) ? 0 : 1; // received bit clear => last fragment /* OK, add it to the receive buffer */ if ((status = dvb_ca_buf_copy_from_cam(ca, buf+2, bytes_read-2, last_fragment, slot, connection_id)) < 0) { goto exit; } /* return the number of bytes read */ status = bytes_read; exit: ca->write_cam_control(ca, slot, CTRLIF_COMMAND, 0); dvb_ca_slot_release(ca, slot); return status;}/** * This function talks to an EN50221 CAM control interface. It writes a buffer of data * to a CAM. The data to write will can either come from a supplied buffer, or from the * buffering system identified by the slot/connection_id. * * @param ca CA instance. * @param slot Slot to read from. * @param connection_id Connection id to write data from. Ignored if buf is non-NULL. * @param buf If non-NULL, the data in this buffer is treated as a complete link-level packet to * be written. If NULL, the data will be extracted from the buffering system for the slot/connection_id. * @param count Size of buf. Ignored if buf is NULL. * * @return Number of bytes written, or < 0 on error. */static int dvb_ca_en50221_write_data(struct dvb_ca* ca, int slot, int connection_id, u8* buf, int count) { int status; u8 buf[HOST_LINK_BUF_SIZE]; u8 last_fragment; int bytes_write; /* if the CA device is not open, do not attempt to send data to it */ if (!ca->open) return -EIO; /* acquire the slot */ if (status = dvb_ca_slot_acquire(ca, slot)) return status; /* reset the interface if there's been a tx error */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit; if (status & STATUSREG_TXERR) dvb_cam_reset_if(ca, slot); /* check if interface does not have data available */ if ((status = ca->read_cam_control(ca, slot, CTRLIF_STATUS)) < 0) goto exit; if (status & STATUSREG_DA) { status = -EAGAIN; goto exit; } /* OK, set HC bit */ if (status = ca->write_cam_control(ca, slot, CTRLIF_COMMAND, CMDREG_HC)) goto exit; /* check if interface is free */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -