/**
 * crystalhd_user_close - Close application handle.
 * @ctx: Command layer contextx.
 * @uc: User ID context.
 *
 * Return:
 *	status
 *
 * Closer application handle and release app specific
 * resources.
 */
enum BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc)
{
	uint32_t mode = uc->mode;

	ctx->user[uc->uid].mode = DTS_MODE_INV;
	ctx->user[uc->uid].in_use = 0;
	ctx->cin_wait_exit = 1;
	ctx->pwr_state_change = 0;

	BCMLOG(BCMLOG_INFO, "Closing user[%x] handle\n", uc->uid);

	if ((mode == DTS_DIAG_MODE) || (mode == DTS_PLAYBACK_MODE)) {
		crystalhd_hw_free_dma_rings(&ctx->hw_ctx);
		crystalhd_destroy_dio_pool(ctx->adp);
	} else if (bc_cproc_get_user_count(ctx)) {
		return BC_STS_SUCCESS;
	}

	crystalhd_hw_close(&ctx->hw_ctx);

	ctx->state = BC_LINK_INVALID;

	return BC_STS_SUCCESS;
}
Esempio n. 2
0
static int chd_dec_close(struct inode *in, struct file *fd)
{
	struct crystalhd_adp *adp = chd_get_adp();
	struct device *dev = &adp->pdev->dev;
	struct crystalhd_cmd *ctx = &adp->cmds;
	struct crystalhd_user *uc;
	uint32_t mode;

	dev_dbg(dev, "Entering %s\n", __func__);
	if (!adp) {
		dev_err(dev, "Invalid adp\n");
		return -EINVAL;
	}

	uc = fd->private_data;
	if (!uc) {
		dev_err(dev, "Failed to get uc\n");
		return -ENODATA;
	}

	/* Check and close only if we have not flush/closed before */
	/* This is needed because release is not guarenteed to be called immediately on close,
	 * if duplicate file handles exist due to fork etc. This causes problems with close and re-open
	 of the device immediately */

	if(uc->in_use) {
		mode = uc->mode;

		ctx->user[uc->uid].mode = DTS_MODE_INV;
		ctx->user[uc->uid].in_use = 0;

		dev_info(chddev(), "Closing user[%x] handle with mode %x\n", uc->uid, mode);

		if (((mode & 0xFF) == DTS_DIAG_MODE) ||
			((mode & 0xFF) == DTS_PLAYBACK_MODE) ||
			((bc_get_userhandle_count(ctx) == 0) && (ctx->hw_ctx != NULL))) {
			ctx->cin_wait_exit = 1;
			ctx->pwr_state_change = BC_HW_RUNNING;
			/* Stop the HW Capture just in case flush did not get called before stop */
			/* And only if we had actually started it */
			if(ctx->hw_ctx->rx_freeq != NULL) {
				crystalhd_hw_stop_capture(ctx->hw_ctx, true);
				crystalhd_hw_free_dma_rings(ctx->hw_ctx);
			}
			if(ctx->adp->fill_byte_pool)
				crystalhd_destroy_dio_pool(ctx->adp);
			if(ctx->adp->elem_pool_head)
				crystalhd_delete_elem_pool(ctx->adp);
			ctx->state = BC_LINK_INVALID;
			crystalhd_hw_close(ctx->hw_ctx, ctx->adp);
			kfree(ctx->hw_ctx);
			ctx->hw_ctx = NULL;
		}

		uc->in_use = 0;

		if(adp->cfg_users > 0)
			adp->cfg_users--;
	}

	return 0;
}