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

📄 dvb_ca_en50221.c

📁 Linux dvb-ci apifor use as an example
💻 C
📖 第 1 页 / 共 3 页
字号:
	int status;	u8 buf[HOST_LINK_BUF_SIZE];	int i;	dprintk("%s\n", __FUNCTION__);	/* check if we have space for a link buf in the rx_buffer */	if (ebuf == NULL) {		int buf_free;		if (ca->slot_info[slot].rx_buffer.data == NULL) {			status = -EIO;			goto exit;		}		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);		if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {			status = -EAGAIN;			goto exit;		}	}	/* check if there is data available */	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)		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 adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",			       ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;			status = -EIO;			goto exit;		}		if (bytes_read < 2) {			printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",			       ca->dvbdev->adapter->num);			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;			status = -EIO;			goto exit;		}	} else {		if (bytes_read > ecount) {			printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",			       ca->dvbdev->adapter->num);			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 be 0) */	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)		goto exit;	if (status & STATUSREG_RE) {		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;		status = -EIO;		goto exit;	}	/* OK, add it to the receive buffer, or copy into external buffer if supplied */	if (ebuf == NULL) {		if (ca->slot_info[slot].rx_buffer.data == NULL) {			status = -EIO;			goto exit;		}		dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);	} else {		memcpy(ebuf, buf, bytes_read);	}	dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,		buf[0], (buf[1] & 0x80) == 0, 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:	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;	/* check if interface is actually waiting for us to read from it, or if a read is in progress */	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)		goto exitnowrite;	if (status & (STATUSREG_DA | STATUSREG_RE)) {		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) {		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;		status = -EIO;		goto exit;	}	status = bytes_write;	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,		buf[0], (buf[1] & 0x80) == 0, bytes_write);exit:	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);exitnowrite:	return status;}EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);/* ******************************************************************************** *//* 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){	dprintk("%s\n", __FUNCTION__);	ca->pub->slot_shutdown(ca->pub, slot);	ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;	/* 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;}EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);/** * 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 = 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);}EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);/** * 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 = 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 = pubca->private;	int flags;	dprintk("FR/DA IRQ slot:%i\n", slot);	switch (ca->slot_info[slot].slot_state) {	case DVB_CA_SLOTSTATE_LINKINIT:		flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);		if (flags & STATUSREG_DA) {			dprintk("CAM supports DA IRQ\n");			ca->slot_info[slot].da_irq_supported = 1;		}		break;	case DVB_CA_SLOTSTATE_RUNNING:		if (ca->open)			dvb_ca_en50221_thread_wakeup(ca);		break;	}}/* ******************************************************************************** *//* EN50221 thread functions *//** * Wake up the DVB CA thread * * @param ca CA instance. */static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca){	dprintk("%s\n", __FUNCTION__);	ca->wakeup = 1;	mb();	wake_up_interruptible(&ca->thread_queue);}/** * Used by the CA thread to determine if an early wakeup is necessary * * @param ca CA instance. */static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca){	if (ca->wakeup) {		ca->wakeup = 0;		return 1;	}	if (ca->exit)		return 1;	return 0;}/** * Update the delay used by the thread. * * @param ca CA instance. */static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca){	int delay;	int curdelay = 100000000;	int slot;	for (slot = 0; slot < ca->slot_count; slot++) {		switch (ca->slot_info[slot].slot_state) {		default:		case DVB_CA_SLOTSTATE_NONE:		case DVB_CA_SLOTSTATE_INVALID:			delay = HZ * 60;			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {				delay = HZ / 10;			}			break;		case DVB_CA_SLOTSTATE_UNINITIALISED:		case DVB_CA_SLOTSTATE_WAITREADY:		case DVB_CA_SLOTSTATE_VALIDATE:		case DVB_CA_SLOTSTATE_WAITFR:		case DVB_CA_SLOTSTATE_LINKINIT:			delay = HZ / 10;			break;		case DVB_CA_SLOTSTATE_RUNNING:			delay = HZ * 60;			if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {				delay = HZ / 10;			}			if (ca->open) {				if ((!ca->slot_info[slot].da_irq_supported) ||				    (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {					delay = HZ / 10;				}			}			break;		}		if (delay < curdelay)			curdelay = delay;	}	ca->delay = curdelay;}/** * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. */static int dvb_ca_en50221_thread(void *data){	struct dvb_ca_private *ca = data;	char name[15];	int slot;	int flags;	int status;	int pktcount;	void *rxbuf;	dprintk("%s\n", __FUNCTION__);	/* setup kernel thread */	snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);	lock_kernel();	daemonize(name);	sigfillset(&current->blocked);	unlock_kernel();	/* choose the correct initial delay */	dvb_ca_en50221_thread_update_delay(ca);	/* main loop */	while (!ca->exit) {		/* sleep for a bit */		if (!ca->wakeup) {			flags = wait_event_interruptible_timeout(ca->thread_queue,								 dvb_ca_en50221_thread_should_wakeup(ca),								 ca->delay);			if ((flags == -ERESTARTSYS) || ca->exit) {				/* got signal or quitting */				break;			}		}		ca->wakeup = 0;		/* go through all the slots processing them */		for (slot = 0; slot < ca->slot_count; slot++) {			// check the cam status + deal with CAMCHANGEs			while (dvb_ca_en50221_check_camstatus(ca, slot)) {				/* clear down an old CI slot if necessary */				if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)					dvb_ca_en50221_slot_shutdown(ca, slot);				/* if a CAM is NOW present, initialise it */				if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;				}				/* we've handled one CAMCHANGE */				dvb_ca_en50221_thread_update_delay(ca);				atomic_dec(&ca->slot_info[slot].camchange_count);			}			// CAM state machine			switch (ca->slot_info[slot].slot_state) {			case DVB_CA_SLOTSTATE_NONE:			case DVB_CA_SLOTSTATE_INVALID:				// no action needed				break;			case DVB_CA_SLOTSTATE_UNINITIALISED:				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;				ca->pub->slot_reset(ca->pub, slot);				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);				break;			case DVB_CA_SLOTSTATE_WAITREADY:				if (time_after(jiffies, ca->slot_info[slot].timeout)) {					printk("dvb_ca adaptor %d: PC card did not respond :(\n",					       ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				// no other action needed; will automatically change state when ready				break;			case DVB_CA_SLOTSTATE_VALIDATE:				if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {					/* we need this extra check for annoying interfaces like the budget-av */					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&					    (ca->pub->poll_slot_status)) {						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;							dvb_ca_en50221_thread_update_delay(ca);							break;						}					}					printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",					       ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {					printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",					       ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				if (ca->pub->write_cam_control(ca->pub, slot,							       CTRLIF_COMMAND, CMDREG_RS) != 0) {					printk("dvb_ca adapter %d: Unable to reset CAM IF\n",					       ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				dprintk("DVB CAM validated successfully\n");				ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;				ca->wakeup = 1;				break;			case DVB_CA_SLOTSTATE_WAITFR:				if (time_after(jiffies, ca->slot_info[slot].timeout)) {					printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",					       ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);				if (flags & STATUSREG_FR) {					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;					ca->wakeup = 1;				}				break;			case DVB_CA_SLOTSTATE_LINKINIT:				if (dvb_ca_en50221_link_init(ca, slot) != 0) {					/* we need this extra check for annoying interfaces like the budget-av */					if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&					    (ca->pub->poll_slot_status)) {						int status = ca->pub->poll_slot_status(ca->pub, slot, 0);						if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {							ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;							dvb_ca_en50221_thread_update_delay(ca);							break;						}					}					printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;					dvb_ca_en50221_thread_update_delay(ca);					break;				}				if (ca->slot_info[slot].rx_buffer.data == NULL) {					rxbuf = vmalloc(RX_BUFFER_SIZE);					if (rxbuf == NULL) {						printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);						ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;						dvb_ca_en50221_thread_update_delay(ca);						break;					}					dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);				}				ca->pub->slot_ts_enable(ca->pub, slot);				ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;				dvb_ca_en50221_thread_update_delay(ca);				printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);				break;			case DVB_CA_SLOTSTATE_RUNNING:				if (!ca->open)					continue;				// poll slots for data				pktcount = 0;				while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {					if (!ca->open)						break;					/* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */					if (dvb_ca_en50221_check_camstatus(ca, slot)) {						// we dont want to sleep on the next iteration so we can handle the cam change						ca->wakeup = 1;						break;					}					/* check if we've hit our limit this time */					if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {						// dont sleep; there is likely to be more data to read						ca->wakeup = 1;						break;					}				}				break;			}		}	}

⌨️ 快捷键说明

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