From 62877913ba55b3f2e5ac34dbc1a2975868ea8d25 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 22 Nov 2010 10:33:51 +0000 Subject: [PATCH] Staging: sst: add ioctls for post processing algorithm interface This patch adds two new ioctls to intel_sst_ctrl device. This i/f can be used by application to send algorithm parameters Signed-off-by: Vinod Koul [This will need further discussion in the context of the final ALSA interface but is fine for staging, ie anyone who relies on it should expect changes Also fixed a missing kmalloc fail check] Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intel_sst.c | 27 ++-- .../intel_sst/intel_sst_app_interface.c | 143 ++++++++++++++++++ drivers/staging/intel_sst/intel_sst_common.h | 2 +- drivers/staging/intel_sst/intel_sst_fw_ipc.h | 2 + drivers/staging/intel_sst/intel_sst_ioctl.h | 15 +- drivers/staging/intel_sst/intel_sst_ipc.c | 49 ++++++ 6 files changed, 215 insertions(+), 23 deletions(-) diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index bd92549893a6..ce4a9f79ccd2 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -306,19 +306,19 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, goto do_unmap_dram; pr_debug("Registered IRQ 0x%x\n", pci->irq); + /*Register LPE Control as misc driver*/ + ret = misc_register(&lpe_ctrl); + if (ret) { + pr_err("couldn't register control device\n"); + goto do_free_irq; + } + if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { ret = misc_register(&lpe_dev); if (ret) { - pr_err("couldn't register LPE device\n"); - goto do_free_irq; - } - - /*Register LPE Control as misc driver*/ - ret = misc_register(&lpe_ctrl); - if (ret) { - pr_err("couldn't register misc driver\n"); - goto do_free_irq; - } + pr_err("couldn't register misc driver\n"); + goto do_free_misc; + } } sst_drv_ctx->lpe_stalled = 0; pm_runtime_set_active(&pci->dev); @@ -327,6 +327,8 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, pr_debug("...successfully done!!!\n"); return ret; +do_free_misc: + misc_deregister(&lpe_ctrl); do_free_irq: free_irq(pci->irq, sst_drv_ctx); do_unmap_dram: @@ -371,10 +373,9 @@ static void __devexit intel_sst_remove(struct pci_dev *pci) mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_UN_INIT; mutex_unlock(&sst_drv_ctx->sst_lock); - if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) { + misc_deregister(&lpe_ctrl); + if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) misc_deregister(&lpe_dev); - misc_deregister(&lpe_ctrl); - } free_irq(pci->irq, sst_drv_ctx); iounmap(sst_drv_ctx->dram); iounmap(sst_drv_ctx->iram); diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index 4b316ccab411..ce2c755a1766 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -827,6 +827,141 @@ static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm) return; } +/** + * sst_create_algo_ipc - create ipc msg for algorithm parameters + * + * @algo_params: Algorithm parameters + * @msg: post msg pointer + * + * This function is called to create ipc msg + */ +int sst_create_algo_ipc(struct snd_ppp_params *algo_params, + struct ipc_post **msg) +{ + if (sst_create_large_msg(msg)) + return -ENOMEM; + sst_fill_header(&(*msg)->header, + IPC_IA_ALG_PARAMS, 1, algo_params->str_id); + (*msg)->header.part.data = sizeof(u32) + + sizeof(*algo_params) + algo_params->size; + memcpy((*msg)->mailbox_data, &(*msg)->header, sizeof(u32)); + memcpy((*msg)->mailbox_data + sizeof(u32), + algo_params, sizeof(*algo_params)); + return 0; +} + +/** + * sst_send_algo_ipc - send ipc msg for algorithm parameters + * + * @msg: post msg pointer + * + * This function is called to send ipc msg + */ +int sst_send_algo_ipc(struct ipc_post **msg) +{ + sst_drv_ctx->ppp_params_blk.condition = false; + sst_drv_ctx->ppp_params_blk.ret_code = 0; + sst_drv_ctx->ppp_params_blk.on = true; + sst_drv_ctx->ppp_params_blk.data = NULL; + spin_lock(&sst_drv_ctx->list_spin_lock); + list_add_tail(&(*msg)->node, &sst_drv_ctx->ipc_dispatch_list); + spin_unlock(&sst_drv_ctx->list_spin_lock); + sst_post_message(&sst_drv_ctx->ipc_post_msg_wq); + return sst_wait_interruptible_timeout(sst_drv_ctx, + &sst_drv_ctx->ppp_params_blk, SST_BLOCK_TIMEOUT); +} + +/** + * intel_sst_ioctl_dsp - recieves the device ioctl's + * + * @cmd:Ioctl cmd + * @arg:data + * + * This function is called when a user space component + * sends a DSP Ioctl to SST driver + */ +long intel_sst_ioctl_dsp(unsigned int cmd, unsigned long arg) +{ + int retval = 0; + struct snd_ppp_params algo_params; + struct snd_ppp_params *algo_params_copied; + struct ipc_post *msg; + + switch (_IOC_NR(cmd)) { + case _IOC_NR(SNDRV_SST_SET_ALGO): + if (copy_from_user(&algo_params, (void __user *)arg, + sizeof(algo_params))) + return -EFAULT; + if (algo_params.size > SST_MAILBOX_SIZE) + return -EMSGSIZE; + + pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", + algo_params.algo_id, algo_params.str_id, + algo_params.enable, algo_params.size); + retval = sst_create_algo_ipc(&algo_params, &msg); + if (retval) + break; + algo_params.reserved = 0; + if (copy_from_user(msg->mailbox_data + sizeof(algo_params), + algo_params.params, algo_params.size)) + return -EFAULT; + + retval = sst_send_algo_ipc(&msg); + if (retval) { + pr_debug("Error in sst_set_algo = %d\n", retval); + retval = -EIO; + } + break; + + case _IOC_NR(SNDRV_SST_GET_ALGO): + if (copy_from_user(&algo_params, (void __user *)arg, + sizeof(algo_params))) + return -EFAULT; + pr_debug("Algo ID %d Str id %d Enable %d Size %d\n", + algo_params.algo_id, algo_params.str_id, + algo_params.enable, algo_params.size); + retval = sst_create_algo_ipc(&algo_params, &msg); + if (retval) + break; + algo_params.reserved = 1; + retval = sst_send_algo_ipc(&msg); + if (retval) { + pr_debug("Error in sst_get_algo = %d\n", retval); + retval = -EIO; + break; + } + algo_params_copied = (struct snd_ppp_params *) + sst_drv_ctx->ppp_params_blk.data; + if (algo_params_copied->size > algo_params.size) { + pr_debug("mem insufficient to copy\n"); + retval = -EMSGSIZE; + goto free_mem; + } else { + char __user *tmp; + + if (copy_to_user(algo_params.params, + algo_params_copied->params, + algo_params_copied->size)) { + retval = -EFAULT; + goto free_mem; + } + tmp = (char __user *)arg + offsetof( + struct snd_ppp_params, size); + if (copy_to_user(tmp, &algo_params_copied->size, + sizeof(__u32))) { + retval = -EFAULT; + goto free_mem; + } + + } +free_mem: + kfree(algo_params_copied->params); + kfree(algo_params_copied); + break; + } + return retval; +} + /** * intel_sst_ioctl - receives the device ioctl's * @file_ptr:pointer to file @@ -1270,6 +1405,14 @@ free_iobufs: kfree(fw_info); break; } + case _IOC_NR(SNDRV_SST_GET_ALGO): + case _IOC_NR(SNDRV_SST_SET_ALGO): + if (minor != AM_MODULE) { + retval = -EBADRQC; + break; + } + retval = intel_sst_ioctl_dsp(cmd, arg); + break; default: retval = -EINVAL; } diff --git a/drivers/staging/intel_sst/intel_sst_common.h b/drivers/staging/intel_sst/intel_sst_common.h index e0c6339ca0ae..0a60e865b696 100644 --- a/drivers/staging/intel_sst/intel_sst_common.h +++ b/drivers/staging/intel_sst/intel_sst_common.h @@ -392,7 +392,7 @@ struct intel_sst_drv { struct stream_info streams[MAX_NUM_STREAMS]; struct stream_alloc_block alloc_block[MAX_ACTIVE_STREAM]; - struct sst_block tgt_dev_blk, fw_info_blk, + struct sst_block tgt_dev_blk, fw_info_blk, ppp_params_blk, vol_info_blk, mute_info_blk, hs_info_blk; struct mutex list_lock;/* mutex for IPC list locking */ spinlock_t list_spin_lock; /* mutex for IPC list locking */ diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h index 75c187672450..8df313d10d2a 100644 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h @@ -68,6 +68,8 @@ #define IPC_IA_CAPT_VOICE 0x17 #define IPC_IA_DECODE_FRAMES 0x18 +#define IPC_IA_ALG_PARAMS 0x1A + /* I2L Stream config/control msgs */ #define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ #define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ diff --git a/drivers/staging/intel_sst/intel_sst_ioctl.h b/drivers/staging/intel_sst/intel_sst_ioctl.h index 03b931619a3e..bebc395a3c1f 100644 --- a/drivers/staging/intel_sst/intel_sst_ioctl.h +++ b/drivers/staging/intel_sst/intel_sst_ioctl.h @@ -190,21 +190,15 @@ struct snd_prp_params { __u32 reserved; /* No pre-processing defined yet */ }; -struct snd_params_block { - __u32 type; /*Type of the parameter*/ - __u32 size; /*size of the parameters in the block*/ - __u8 params[0]; /*Parameters of the algorithm*/ -}; - /* Pre and post processing params structure */ struct snd_ppp_params { - enum sst_algo_types algo_id;/* Post/Pre processing algorithm ID */ + __u8 algo_id;/* Post/Pre processing algorithm ID */ __u8 str_id; /*Only 5 bits used 0 - 31 are valid*/ __u8 enable; /* 0= disable, 1= enable*/ __u8 reserved; __u32 size; /*Size of parameters for all blocks*/ - struct snd_params_block params[0]; -}; + void *params; +} __attribute__ ((packed)); struct snd_sst_postproc_info { __u32 src_min; /* Supported SRC Min sampling freq */ @@ -431,5 +425,8 @@ struct snd_sst_dbufs { #define SNDRV_SST_FW_INFO _IOR('L', 0x20, struct snd_sst_fw_info *) #define SNDRV_SST_SET_TARGET_DEVICE _IOW('L', 0x21, \ struct snd_sst_target_device *) +/*DSP Ioctls on /dev/intel_sst_ctrl only*/ +#define SNDRV_SST_SET_ALGO _IOW('L', 0x30, struct snd_ppp_params *) +#define SNDRV_SST_GET_ALGO _IOWR('L', 0x31, struct snd_ppp_params *) #endif /* __INTEL_SST_IOCTL_H__ */ diff --git a/drivers/staging/intel_sst/intel_sst_ipc.c b/drivers/staging/intel_sst/intel_sst_ipc.c index 5aa92ba9018c..0742dde2685d 100644 --- a/drivers/staging/intel_sst/intel_sst_ipc.c +++ b/drivers/staging/intel_sst/intel_sst_ipc.c @@ -336,6 +336,55 @@ void sst_process_reply(struct work_struct *work) wake_up(&sst_drv_ctx->wait_queue); } break; + case IPC_IA_ALG_PARAMS: { + pr_debug("sst:IPC_ALG_PARAMS response %x\n", msg->header.full); + pr_debug("sst: data value %x\n", msg->header.part.data); + pr_debug("sst: large value %x\n", msg->header.part.large); + + if (!msg->header.part.large) { + if (!msg->header.part.data) { + pr_debug("sst: alg set success\n"); + sst_drv_ctx->ppp_params_blk.ret_code = 0; + } else { + pr_debug("sst: alg set failed\n"); + sst_drv_ctx->ppp_params_blk.ret_code = + -msg->header.part.data; + } + + } else if (msg->header.part.data) { + struct snd_ppp_params *mailbox_params, *get_params; + char *params; + + pr_debug("sst: alg get success\n"); + mailbox_params = (struct snd_ppp_params *)msg->mailbox; + get_params = kzalloc(sizeof(*get_params), GFP_KERNEL); + if (get_params == NULL) { + pr_err("sst: out of memory for ALG PARAMS"); + break; + } + memcpy_fromio(get_params, mailbox_params, + sizeof(*get_params)); + get_params->params = kzalloc(mailbox_params->size, + GFP_KERNEL); + if (get_params->params == NULL) { + kfree(get_params); + pr_err("sst: out of memory for ALG PARAMS block"); + break; + } + params = msg->mailbox; + params = params + sizeof(*mailbox_params) - sizeof(u32); + memcpy_fromio(get_params->params, params, + get_params->size); + sst_drv_ctx->ppp_params_blk.ret_code = 0; + sst_drv_ctx->ppp_params_blk.data = get_params; + } + + if (sst_drv_ctx->ppp_params_blk.on == true) { + sst_drv_ctx->ppp_params_blk.condition = true; + wake_up(&sst_drv_ctx->wait_queue); + } + break; + } case IPC_IA_GET_FW_INFO: { struct snd_sst_fw_info *fw_info = (struct snd_sst_fw_info *)msg->mailbox; -- 2.20.1