/** * 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; }
BC_STATUS crystalhd_hw_setup_dma_rings(struct crystalhd_hw *hw) { struct device *dev; unsigned int i; void *mem; size_t mem_len; dma_addr_t phy_addr; BC_STATUS sts = BC_STS_SUCCESS; struct crystalhd_rx_dma_pkt *rpkt; if (!hw || !hw->adp) { printk(KERN_ERR "%s: Invalid Arguments\n", __func__); return BC_STS_INV_ARG; } dev = &hw->adp->pdev->dev; sts = crystalhd_hw_create_ioqs(hw); if (sts != BC_STS_SUCCESS) { dev_err(dev, "Failed to create IOQs..\n"); return sts; } mem_len = BC_LINK_MAX_SGLS * sizeof(struct dma_descriptor); for (i = 0; i < BC_TX_LIST_CNT; i++) { mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr); if (mem) { memset(mem, 0, mem_len); } else { dev_err(dev, "Insufficient Memory For TX\n"); crystalhd_hw_free_dma_rings(hw); return BC_STS_INSUFF_RES; } /* rx_pkt_pool -- static memory allocation */ hw->tx_pkt_pool[i].desc_mem.pdma_desc_start = mem; hw->tx_pkt_pool[i].desc_mem.phy_addr = phy_addr; hw->tx_pkt_pool[i].desc_mem.sz = BC_LINK_MAX_SGLS * sizeof(struct dma_descriptor); hw->tx_pkt_pool[i].list_tag = 0; /* Add TX dma requests to Free Queue..*/ sts = crystalhd_dioq_add(hw->tx_freeq, &hw->tx_pkt_pool[i], false, 0); if (sts != BC_STS_SUCCESS) { crystalhd_hw_free_dma_rings(hw); return sts; } } for (i = 0; i < BC_RX_LIST_CNT; i++) { rpkt = kzalloc(sizeof(*rpkt), GFP_KERNEL); if (!rpkt) { dev_err(dev, "Insufficient Memory For RX\n"); crystalhd_hw_free_dma_rings(hw); return BC_STS_INSUFF_RES; } mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr); if (mem) { memset(mem, 0, mem_len); } else { dev_err(dev, "Insufficient Memory For RX\n"); crystalhd_hw_free_dma_rings(hw); return BC_STS_INSUFF_RES; } rpkt->desc_mem.pdma_desc_start = mem; rpkt->desc_mem.phy_addr = phy_addr; rpkt->desc_mem.sz = BC_LINK_MAX_SGLS * sizeof(struct dma_descriptor); rpkt->pkt_tag = hw->rx_pkt_tag_seed + i; crystalhd_hw_free_rx_pkt(hw, rpkt); } return BC_STS_SUCCESS; }
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; }