static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp) { struct crystalhd_ioctl_data *temp; struct device *dev; int rc = -ENODEV, i = 0; if (!adp) goto fail; adp->chd_dec_major = register_chrdev(0, CRYSTALHD_API_NAME, &chd_dec_fops); if (adp->chd_dec_major < 0) { BCMLOG_ERR("Failed to create config dev\n"); rc = adp->chd_dec_major; goto fail; } /* register crystalhd class */ crystalhd_class = class_create(THIS_MODULE, "crystalhd"); if (IS_ERR(crystalhd_class)) { BCMLOG_ERR("failed to create class\n"); goto fail; } dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd"); if (IS_ERR(dev)) { BCMLOG_ERR("failed to create device\n"); goto device_create_fail; } rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ); if (rc) { BCMLOG_ERR("failed to create device\n"); goto elem_pool_fail; } /* Allocate general purpose ioctl pool. */ for (i = 0; i < CHD_IODATA_POOL_SZ; i++) { temp = kzalloc(sizeof(struct crystalhd_ioctl_data), GFP_KERNEL); if (!temp) { BCMLOG_ERR("ioctl data pool kzalloc failed\n"); rc = -ENOMEM; goto kzalloc_fail; } /* Add to global pool.. */ chd_dec_free_iodata(adp, temp, 0); } return 0; kzalloc_fail: crystalhd_delete_elem_pool(adp); elem_pool_fail: device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0)); device_create_fail: class_destroy(crystalhd_class); fail: return rc; }
static void __devexit chd_dec_release_chdev(struct crystalhd_adp *adp) { struct crystalhd_ioctl_data *temp = NULL; if (!adp) return; if (adp->chd_dec_major > 0) { /* unregister crystalhd class */ device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0)); unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME); BCMLOG(BCMLOG_INFO, "released api device - %d\n", adp->chd_dec_major); class_destroy(crystalhd_class); } adp->chd_dec_major = 0; /* Clear iodata pool.. */ do { temp = chd_dec_alloc_iodata(adp, 0); if (temp) kfree(temp); } while (temp); crystalhd_delete_elem_pool(adp); }
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; }