1/*
2 * dspapi.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Common DSP API functions, also includes the wrapper
7 * functions called directly by the DeviceIOControl interface.
8 *
9 * Copyright (C) 2005-2006 Texas Instruments, Inc.
10 *
11 * This package is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19#include <linux/types.h>
20
21/*  ----------------------------------- Host OS */
22#include <dspbridge/host_os.h>
23
24/*  ----------------------------------- DSP/BIOS Bridge */
25#include <dspbridge/dbdefs.h>
26
27/*  ----------------------------------- OS Adaptation Layer */
28#include <dspbridge/ntfy.h>
29
30/*  ----------------------------------- Platform Manager */
31#include <dspbridge/chnl.h>
32#include <dspbridge/dev.h>
33#include <dspbridge/drv.h>
34
35#include <dspbridge/proc.h>
36#include <dspbridge/strm.h>
37
38/*  ----------------------------------- Resource Manager */
39#include <dspbridge/disp.h>
40#include <dspbridge/mgr.h>
41#include <dspbridge/node.h>
42#include <dspbridge/rmm.h>
43
44/*  ----------------------------------- Others */
45#include <dspbridge/msg.h>
46#include <dspbridge/cmm.h>
47#include <dspbridge/io.h>
48
49/*  ----------------------------------- This */
50#include <dspbridge/dspapi.h>
51#include <dspbridge/dbdcd.h>
52
53#include <dspbridge/resourcecleanup.h>
54
55/*  ----------------------------------- Defines, Data Structures, Typedefs */
56#define MAX_TRACEBUFLEN 255
57#define MAX_LOADARGS    16
58#define MAX_NODES       64
59#define MAX_STREAMS     16
60#define MAX_BUFS	64
61
62/* Used to get dspbridge ioctl table */
63#define DB_GET_IOC_TABLE(cmd)	(DB_GET_MODULE(cmd) >> DB_MODULE_SHIFT)
64
65/* Device IOCtl function pointer */
66struct api_cmd {
67	u32(*fxn) (union trapped_args *args, void *pr_ctxt);
68	u32 index;
69};
70
71/*  ----------------------------------- Globals */
72static u32 api_c_refs;
73
74/*
75 *  Function tables.
76 *  The order of these functions MUST be the same as the order of the command
77 *  numbers defined in dspapi-ioctl.h  This is how an IOCTL number in user mode
78 *  turns into a function call in kernel mode.
79 */
80
81/* MGR wrapper functions */
82static struct api_cmd mgr_cmd[] = {
83	{mgrwrap_enum_node_info},	/* MGR_ENUMNODE_INFO */
84	{mgrwrap_enum_proc_info},	/* MGR_ENUMPROC_INFO */
85	{mgrwrap_register_object},	/* MGR_REGISTEROBJECT */
86	{mgrwrap_unregister_object},	/* MGR_UNREGISTEROBJECT */
87	{mgrwrap_wait_for_bridge_events},	/* MGR_WAIT */
88	{mgrwrap_get_process_resources_info},	/* MGR_GET_PROC_RES */
89};
90
91/* PROC wrapper functions */
92static struct api_cmd proc_cmd[] = {
93	{procwrap_attach},	/* PROC_ATTACH */
94	{procwrap_ctrl},	/* PROC_CTRL */
95	{procwrap_detach},	/* PROC_DETACH */
96	{procwrap_enum_node_info},	/* PROC_ENUMNODE */
97	{procwrap_enum_resources},	/* PROC_ENUMRESOURCES */
98	{procwrap_get_state},	/* PROC_GET_STATE */
99	{procwrap_get_trace},	/* PROC_GET_TRACE */
100	{procwrap_load},	/* PROC_LOAD */
101	{procwrap_register_notify},	/* PROC_REGISTERNOTIFY */
102	{procwrap_start},	/* PROC_START */
103	{procwrap_reserve_memory},	/* PROC_RSVMEM */
104	{procwrap_un_reserve_memory},	/* PROC_UNRSVMEM */
105	{procwrap_map},		/* PROC_MAPMEM */
106	{procwrap_un_map},	/* PROC_UNMAPMEM */
107	{procwrap_flush_memory},	/* PROC_FLUSHMEMORY */
108	{procwrap_stop},	/* PROC_STOP */
109	{procwrap_invalidate_memory},	/* PROC_INVALIDATEMEMORY */
110	{procwrap_begin_dma},	/* PROC_BEGINDMA */
111	{procwrap_end_dma},	/* PROC_ENDDMA */
112};
113
114/* NODE wrapper functions */
115static struct api_cmd node_cmd[] = {
116	{nodewrap_allocate},	/* NODE_ALLOCATE */
117	{nodewrap_alloc_msg_buf},	/* NODE_ALLOCMSGBUF */
118	{nodewrap_change_priority},	/* NODE_CHANGEPRIORITY */
119	{nodewrap_connect},	/* NODE_CONNECT */
120	{nodewrap_create},	/* NODE_CREATE */
121	{nodewrap_delete},	/* NODE_DELETE */
122	{nodewrap_free_msg_buf},	/* NODE_FREEMSGBUF */
123	{nodewrap_get_attr},	/* NODE_GETATTR */
124	{nodewrap_get_message},	/* NODE_GETMESSAGE */
125	{nodewrap_pause},	/* NODE_PAUSE */
126	{nodewrap_put_message},	/* NODE_PUTMESSAGE */
127	{nodewrap_register_notify},	/* NODE_REGISTERNOTIFY */
128	{nodewrap_run},		/* NODE_RUN */
129	{nodewrap_terminate},	/* NODE_TERMINATE */
130	{nodewrap_get_uuid_props},	/* NODE_GETUUIDPROPS */
131};
132
133/* STRM wrapper functions */
134static struct api_cmd strm_cmd[] = {
135	{strmwrap_allocate_buffer},	/* STRM_ALLOCATEBUFFER */
136	{strmwrap_close},	/* STRM_CLOSE */
137	{strmwrap_free_buffer},	/* STRM_FREEBUFFER */
138	{strmwrap_get_event_handle},	/* STRM_GETEVENTHANDLE */
139	{strmwrap_get_info},	/* STRM_GETINFO */
140	{strmwrap_idle},	/* STRM_IDLE */
141	{strmwrap_issue},	/* STRM_ISSUE */
142	{strmwrap_open},	/* STRM_OPEN */
143	{strmwrap_reclaim},	/* STRM_RECLAIM */
144	{strmwrap_register_notify},	/* STRM_REGISTERNOTIFY */
145	{strmwrap_select},	/* STRM_SELECT */
146};
147
148/* CMM wrapper functions */
149static struct api_cmd cmm_cmd[] = {
150	{cmmwrap_calloc_buf},	/* CMM_ALLOCBUF */
151	{cmmwrap_free_buf},	/* CMM_FREEBUF */
152	{cmmwrap_get_handle},	/* CMM_GETHANDLE */
153	{cmmwrap_get_info},	/* CMM_GETINFO */
154};
155
156/* Array used to store ioctl table sizes. It can hold up to 8 entries */
157static u8 size_cmd[] = {
158	ARRAY_SIZE(mgr_cmd),
159	ARRAY_SIZE(proc_cmd),
160	ARRAY_SIZE(node_cmd),
161	ARRAY_SIZE(strm_cmd),
162	ARRAY_SIZE(cmm_cmd),
163};
164
165static inline void _cp_fm_usr(void *to, const void __user * from,
166			      int *err, unsigned long bytes)
167{
168	if (*err)
169		return;
170
171	if (unlikely(!from)) {
172		*err = -EFAULT;
173		return;
174	}
175
176	if (unlikely(copy_from_user(to, from, bytes)))
177		*err = -EFAULT;
178}
179
180#define CP_FM_USR(to, from, err, n)				\
181	_cp_fm_usr(to, from, &(err), (n) * sizeof(*(to)))
182
183static inline void _cp_to_usr(void __user *to, const void *from,
184			      int *err, unsigned long bytes)
185{
186	if (*err)
187		return;
188
189	if (unlikely(!to)) {
190		*err = -EFAULT;
191		return;
192	}
193
194	if (unlikely(copy_to_user(to, from, bytes)))
195		*err = -EFAULT;
196}
197
198#define CP_TO_USR(to, from, err, n)				\
199	_cp_to_usr(to, from, &(err), (n) * sizeof(*(from)))
200
201/*
202 *  ======== api_call_dev_ioctl ========
203 *  Purpose:
204 *      Call the (wrapper) function for the corresponding API IOCTL.
205 */
206inline int api_call_dev_ioctl(u32 cmd, union trapped_args *args,
207				      u32 *result, void *pr_ctxt)
208{
209	u32(*ioctl_cmd) (union trapped_args *args, void *pr_ctxt) = NULL;
210	int i;
211
212	if (_IOC_TYPE(cmd) != DB) {
213		pr_err("%s: Incompatible dspbridge ioctl number\n", __func__);
214		goto err;
215	}
216
217	if (DB_GET_IOC_TABLE(cmd) > ARRAY_SIZE(size_cmd)) {
218		pr_err("%s: undefined ioctl module\n", __func__);
219		goto err;
220	}
221
222	/* Check the size of the required cmd table */
223	i = DB_GET_IOC(cmd);
224	if (i > size_cmd[DB_GET_IOC_TABLE(cmd)]) {
225		pr_err("%s: requested ioctl %d out of bounds for table %d\n",
226		       __func__, i, DB_GET_IOC_TABLE(cmd));
227		goto err;
228	}
229
230	switch (DB_GET_MODULE(cmd)) {
231	case DB_MGR:
232		ioctl_cmd = mgr_cmd[i].fxn;
233		break;
234	case DB_PROC:
235		ioctl_cmd = proc_cmd[i].fxn;
236		break;
237	case DB_NODE:
238		ioctl_cmd = node_cmd[i].fxn;
239		break;
240	case DB_STRM:
241		ioctl_cmd = strm_cmd[i].fxn;
242		break;
243	case DB_CMM:
244		ioctl_cmd = cmm_cmd[i].fxn;
245		break;
246	}
247
248	if (!ioctl_cmd) {
249		pr_err("%s: requested ioctl not defined\n", __func__);
250		goto err;
251	} else {
252		*result = (*ioctl_cmd) (args, pr_ctxt);
253	}
254
255	return 0;
256
257err:
258	return -EINVAL;
259}
260
261/*
262 *  ======== api_exit ========
263 */
264void api_exit(void)
265{
266	api_c_refs--;
267
268	if (api_c_refs == 0)
269		mgr_exit();
270}
271
272/*
273 *  ======== api_init ========
274 *  Purpose:
275 *      Module initialization used by Bridge API.
276 */
277bool api_init(void)
278{
279	bool ret = true;
280
281	if (api_c_refs == 0)
282		ret = mgr_init();
283
284	if (ret)
285		api_c_refs++;
286
287	return ret;
288}
289
290/*
291 *  ======== api_init_complete2 ========
292 *  Purpose:
293 *      Perform any required bridge initialization which cannot
294 *      be performed in api_init() or dev_start_device() due
295 *      to the fact that some services are not yet
296 *      completely initialized.
297 *  Parameters:
298 *  Returns:
299 *      0:	Allow this device to load
300 *      -EPERM:      Failure.
301 *  Requires:
302 *      Bridge API initialized.
303 *  Ensures:
304 */
305int api_init_complete2(void)
306{
307	int status = 0;
308	struct cfg_devnode *dev_node;
309	struct dev_object *hdev_obj;
310	struct drv_data *drv_datap;
311	u8 dev_type;
312
313	/*  Walk the list of DevObjects, get each devnode, and attempting to
314	 *  autostart the board. Note that this requires COF loading, which
315	 *  requires KFILE. */
316	for (hdev_obj = dev_get_first(); hdev_obj != NULL;
317	     hdev_obj = dev_get_next(hdev_obj)) {
318		if (dev_get_dev_node(hdev_obj, &dev_node))
319			continue;
320
321		if (dev_get_dev_type(hdev_obj, &dev_type))
322			continue;
323
324		if ((dev_type == DSP_UNIT) || (dev_type == IVA_UNIT)) {
325			drv_datap = dev_get_drvdata(bridge);
326
327			if (drv_datap && drv_datap->base_img)
328				proc_auto_start(dev_node, hdev_obj);
329		}
330	}
331
332	return status;
333}
334
335/* TODO: Remove deprecated and not implemented ioctl wrappers */
336
337/*
338 * ======== mgrwrap_enum_node_info ========
339 */
340u32 mgrwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
341{
342	u8 *pndb_props;
343	u32 num_nodes;
344	int status = 0;
345	u32 size = args->args_mgr_enumnode_info.ndb_props_size;
346
347	if (size < sizeof(struct dsp_ndbprops))
348		return -EINVAL;
349
350	pndb_props = kmalloc(size, GFP_KERNEL);
351	if (pndb_props == NULL)
352		status = -ENOMEM;
353
354	if (!status) {
355		status =
356		    mgr_enum_node_info(args->args_mgr_enumnode_info.node_id,
357				       (struct dsp_ndbprops *)pndb_props, size,
358				       &num_nodes);
359	}
360	CP_TO_USR(args->args_mgr_enumnode_info.ndb_props, pndb_props, status,
361		  size);
362	CP_TO_USR(args->args_mgr_enumnode_info.num_nodes, &num_nodes, status,
363		  1);
364	kfree(pndb_props);
365
366	return status;
367}
368
369/*
370 * ======== mgrwrap_enum_proc_info ========
371 */
372u32 mgrwrap_enum_proc_info(union trapped_args *args, void *pr_ctxt)
373{
374	u8 *processor_info;
375	u8 num_procs;
376	int status = 0;
377	u32 size = args->args_mgr_enumproc_info.processor_info_size;
378
379	if (size < sizeof(struct dsp_processorinfo))
380		return -EINVAL;
381
382	processor_info = kmalloc(size, GFP_KERNEL);
383	if (processor_info == NULL)
384		status = -ENOMEM;
385
386	if (!status) {
387		status =
388		    mgr_enum_processor_info(args->args_mgr_enumproc_info.
389					    processor_id,
390					    (struct dsp_processorinfo *)
391					    processor_info, size, &num_procs);
392	}
393	CP_TO_USR(args->args_mgr_enumproc_info.processor_info, processor_info,
394		  status, size);
395	CP_TO_USR(args->args_mgr_enumproc_info.num_procs, &num_procs,
396		  status, 1);
397	kfree(processor_info);
398
399	return status;
400}
401
402#define WRAP_MAP2CALLER(x) x
403/*
404 * ======== mgrwrap_register_object ========
405 */
406u32 mgrwrap_register_object(union trapped_args *args, void *pr_ctxt)
407{
408	u32 ret;
409	struct dsp_uuid uuid_obj;
410	u32 path_size = 0;
411	char *psz_path_name = NULL;
412	int status = 0;
413
414	CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
415	if (status)
416		goto func_end;
417	/* path_size is increased by 1 to accommodate NULL */
418	path_size = strlen_user((char *)
419				args->args_mgr_registerobject.sz_path_name) +
420	    1;
421	psz_path_name = kmalloc(path_size, GFP_KERNEL);
422	if (!psz_path_name) {
423		status = -ENOMEM;
424		goto func_end;
425	}
426	ret = strncpy_from_user(psz_path_name,
427				(char *)args->args_mgr_registerobject.
428				sz_path_name, path_size);
429	if (!ret) {
430		status = -EFAULT;
431		goto func_end;
432	}
433
434	if (args->args_mgr_registerobject.obj_type >= DSP_DCDMAXOBJTYPE) {
435		status = -EINVAL;
436		goto func_end;
437	}
438
439	status = dcd_register_object(&uuid_obj,
440				     args->args_mgr_registerobject.obj_type,
441				     (char *)psz_path_name);
442func_end:
443	kfree(psz_path_name);
444	return status;
445}
446
447/*
448 * ======== mgrwrap_unregister_object ========
449 */
450u32 mgrwrap_unregister_object(union trapped_args *args, void *pr_ctxt)
451{
452	int status = 0;
453	struct dsp_uuid uuid_obj;
454
455	CP_FM_USR(&uuid_obj, args->args_mgr_registerobject.uuid_obj, status, 1);
456	if (status)
457		goto func_end;
458
459	status = dcd_unregister_object(&uuid_obj,
460				       args->args_mgr_unregisterobject.
461				       obj_type);
462func_end:
463	return status;
464
465}
466
467/*
468 * ======== mgrwrap_wait_for_bridge_events ========
469 */
470u32 mgrwrap_wait_for_bridge_events(union trapped_args *args, void *pr_ctxt)
471{
472	int status = 0;
473	struct dsp_notification *anotifications[MAX_EVENTS];
474	struct dsp_notification notifications[MAX_EVENTS];
475	u32 index, i;
476	u32 count = args->args_mgr_wait.count;
477
478	if (count > MAX_EVENTS)
479		status = -EINVAL;
480
481	/* get the array of pointers to user structures */
482	CP_FM_USR(anotifications, args->args_mgr_wait.anotifications,
483		  status, count);
484	/* get the events */
485	for (i = 0; i < count; i++) {
486		CP_FM_USR(&notifications[i], anotifications[i], status, 1);
487		if (status || !notifications[i].handle) {
488			status = -EINVAL;
489			break;
490		}
491		/* set the array of pointers to kernel structures */
492		anotifications[i] = &notifications[i];
493	}
494	if (!status) {
495		status = mgr_wait_for_bridge_events(anotifications, count,
496							 &index,
497							 args->args_mgr_wait.
498							 timeout);
499	}
500	CP_TO_USR(args->args_mgr_wait.index, &index, status, 1);
501	return status;
502}
503
504/*
505 * ======== MGRWRAP_GetProcessResourceInfo ========
506 */
507u32 __deprecated mgrwrap_get_process_resources_info(union trapped_args * args,
508						    void *pr_ctxt)
509{
510	pr_err("%s: deprecated dspbridge ioctl\n", __func__);
511	return 0;
512}
513
514/*
515 * ======== procwrap_attach ========
516 */
517u32 procwrap_attach(union trapped_args *args, void *pr_ctxt)
518{
519	void *processor;
520	int status = 0;
521	struct dsp_processorattrin proc_attr_in, *attr_in = NULL;
522
523	/* Optional argument */
524	if (args->args_proc_attach.attr_in) {
525		CP_FM_USR(&proc_attr_in, args->args_proc_attach.attr_in, status,
526			  1);
527		if (!status)
528			attr_in = &proc_attr_in;
529		else
530			goto func_end;
531
532	}
533	status = proc_attach(args->args_proc_attach.processor_id, attr_in,
534			     &processor, pr_ctxt);
535	CP_TO_USR(args->args_proc_attach.ph_processor, &processor, status, 1);
536func_end:
537	return status;
538}
539
540/*
541 * ======== procwrap_ctrl ========
542 */
543u32 procwrap_ctrl(union trapped_args *args, void *pr_ctxt)
544{
545	u32 cb_data_size, __user * psize = (u32 __user *)
546	    args->args_proc_ctrl.args;
547	u8 *pargs = NULL;
548	int status = 0;
549	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
550
551	if (psize) {
552		if (get_user(cb_data_size, psize)) {
553			status = -EPERM;
554			goto func_end;
555		}
556		cb_data_size += sizeof(u32);
557		pargs = kmalloc(cb_data_size, GFP_KERNEL);
558		if (pargs == NULL) {
559			status = -ENOMEM;
560			goto func_end;
561		}
562
563		CP_FM_USR(pargs, args->args_proc_ctrl.args, status,
564			  cb_data_size);
565	}
566	if (!status) {
567		status = proc_ctrl(hprocessor,
568				   args->args_proc_ctrl.cmd,
569				   (struct dsp_cbdata *)pargs);
570	}
571
572	/* CP_TO_USR(args->args_proc_ctrl.args, pargs, status, 1); */
573	kfree(pargs);
574func_end:
575	return status;
576}
577
578/*
579 * ======== procwrap_detach ========
580 */
581u32 __deprecated procwrap_detach(union trapped_args * args, void *pr_ctxt)
582{
583	/* proc_detach called at bridge_release only */
584	pr_err("%s: deprecated dspbridge ioctl\n", __func__);
585	return 0;
586}
587
588/*
589 * ======== procwrap_enum_node_info ========
590 */
591u32 procwrap_enum_node_info(union trapped_args *args, void *pr_ctxt)
592{
593	int status;
594	void *node_tab[MAX_NODES];
595	u32 num_nodes;
596	u32 alloc_cnt;
597	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
598
599	if (!args->args_proc_enumnode_info.node_tab_size)
600		return -EINVAL;
601
602	status = proc_enum_nodes(hprocessor,
603				 node_tab,
604				 args->args_proc_enumnode_info.node_tab_size,
605				 &num_nodes, &alloc_cnt);
606	CP_TO_USR(args->args_proc_enumnode_info.node_tab, node_tab, status,
607		  num_nodes);
608	CP_TO_USR(args->args_proc_enumnode_info.num_nodes, &num_nodes,
609		  status, 1);
610	CP_TO_USR(args->args_proc_enumnode_info.allocated, &alloc_cnt,
611		  status, 1);
612	return status;
613}
614
615u32 procwrap_end_dma(union trapped_args *args, void *pr_ctxt)
616{
617	int status;
618
619	if (args->args_proc_dma.dir >= DMA_NONE)
620		return -EINVAL;
621
622	status = proc_end_dma(pr_ctxt,
623				   args->args_proc_dma.mpu_addr,
624				   args->args_proc_dma.size,
625				   args->args_proc_dma.dir);
626	return status;
627}
628
629u32 procwrap_begin_dma(union trapped_args *args, void *pr_ctxt)
630{
631	int status;
632
633	if (args->args_proc_dma.dir >= DMA_NONE)
634		return -EINVAL;
635
636	status = proc_begin_dma(pr_ctxt,
637				   args->args_proc_dma.mpu_addr,
638				   args->args_proc_dma.size,
639				   args->args_proc_dma.dir);
640	return status;
641}
642
643/*
644 * ======== procwrap_flush_memory ========
645 */
646u32 procwrap_flush_memory(union trapped_args *args, void *pr_ctxt)
647{
648	int status;
649
650	if (args->args_proc_flushmemory.flags >
651	    PROC_WRITEBACK_INVALIDATE_MEM)
652		return -EINVAL;
653
654	status = proc_flush_memory(pr_ctxt,
655				   args->args_proc_flushmemory.mpu_addr,
656				   args->args_proc_flushmemory.size,
657				   args->args_proc_flushmemory.flags);
658	return status;
659}
660
661/*
662 * ======== procwrap_invalidate_memory ========
663 */
664u32 procwrap_invalidate_memory(union trapped_args *args, void *pr_ctxt)
665{
666	int status;
667
668	status =
669	    proc_invalidate_memory(pr_ctxt,
670				   args->args_proc_invalidatememory.mpu_addr,
671				   args->args_proc_invalidatememory.size);
672	return status;
673}
674
675/*
676 * ======== procwrap_enum_resources ========
677 */
678u32 procwrap_enum_resources(union trapped_args *args, void *pr_ctxt)
679{
680	int status = 0;
681	struct dsp_resourceinfo resource_info;
682	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
683
684	if (args->args_proc_enumresources.resource_info_size <
685	    sizeof(struct dsp_resourceinfo))
686		return -EINVAL;
687
688	status =
689	    proc_get_resource_info(hprocessor,
690				   args->args_proc_enumresources.resource_type,
691				   &resource_info,
692				   args->args_proc_enumresources.
693				   resource_info_size);
694
695	CP_TO_USR(args->args_proc_enumresources.resource_info, &resource_info,
696		  status, 1);
697
698	return status;
699
700}
701
702/*
703 * ======== procwrap_get_state ========
704 */
705u32 procwrap_get_state(union trapped_args *args, void *pr_ctxt)
706{
707	int status;
708	struct dsp_processorstate proc_state;
709	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
710
711	if (args->args_proc_getstate.state_info_size <
712	    sizeof(struct dsp_processorstate))
713		return -EINVAL;
714
715	status = proc_get_state(hprocessor, &proc_state,
716			   args->args_proc_getstate.state_info_size);
717	CP_TO_USR(args->args_proc_getstate.proc_state_obj, &proc_state, status,
718		  1);
719	return status;
720
721}
722
723/*
724 * ======== procwrap_get_trace ========
725 */
726u32 procwrap_get_trace(union trapped_args *args, void *pr_ctxt)
727{
728	int status;
729	u8 *pbuf;
730	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
731
732	if (args->args_proc_gettrace.max_size > MAX_TRACEBUFLEN)
733		return -EINVAL;
734
735	pbuf = kzalloc(args->args_proc_gettrace.max_size, GFP_KERNEL);
736	if (pbuf != NULL) {
737		status = proc_get_trace(hprocessor, pbuf,
738					args->args_proc_gettrace.max_size);
739	} else {
740		status = -ENOMEM;
741	}
742	CP_TO_USR(args->args_proc_gettrace.buf, pbuf, status,
743		  args->args_proc_gettrace.max_size);
744	kfree(pbuf);
745
746	return status;
747}
748
749/*
750 * ======== procwrap_load ========
751 */
752u32 procwrap_load(union trapped_args *args, void *pr_ctxt)
753{
754	s32 i, len;
755	int status = 0;
756	char *temp;
757	s32 count = args->args_proc_load.argc_index;
758	u8 **argv = NULL, **envp = NULL;
759	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
760
761	if (count <= 0 || count > MAX_LOADARGS) {
762		status = -EINVAL;
763		goto func_cont;
764	}
765
766	argv = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
767	if (!argv) {
768		status = -ENOMEM;
769		goto func_cont;
770	}
771
772	CP_FM_USR(argv, args->args_proc_load.user_args, status, count);
773	if (status) {
774		kfree(argv);
775		argv = NULL;
776		goto func_cont;
777	}
778
779	for (i = 0; i < count; i++) {
780		if (argv[i]) {
781			/* User space pointer to argument */
782			temp = (char *)argv[i];
783			/* len is increased by 1 to accommodate NULL */
784			len = strlen_user((char *)temp) + 1;
785			/* Kernel space pointer to argument */
786			argv[i] = kmalloc(len, GFP_KERNEL);
787			if (argv[i]) {
788				CP_FM_USR(argv[i], temp, status, len);
789				if (status) {
790					kfree(argv[i]);
791					argv[i] = NULL;
792					goto func_cont;
793				}
794			} else {
795				status = -ENOMEM;
796				goto func_cont;
797			}
798		}
799	}
800	/* TODO: validate this */
801	if (args->args_proc_load.user_envp) {
802		/* number of elements in the envp array including NULL */
803		count = 0;
804		do {
805			if (get_user(temp,
806				     args->args_proc_load.user_envp + count)) {
807				status = -EFAULT;
808				goto func_cont;
809			}
810			count++;
811		} while (temp);
812		envp = kmalloc(count * sizeof(u8 *), GFP_KERNEL);
813		if (!envp) {
814			status = -ENOMEM;
815			goto func_cont;
816		}
817
818		CP_FM_USR(envp, args->args_proc_load.user_envp, status, count);
819		if (status) {
820			kfree(envp);
821			envp = NULL;
822			goto func_cont;
823		}
824		for (i = 0; envp[i]; i++) {
825			/* User space pointer to argument */
826			temp = (char *)envp[i];
827			/* len is increased by 1 to accommodate NULL */
828			len = strlen_user((char *)temp) + 1;
829			/* Kernel space pointer to argument */
830			envp[i] = kmalloc(len, GFP_KERNEL);
831			if (envp[i]) {
832				CP_FM_USR(envp[i], temp, status, len);
833				if (status) {
834					kfree(envp[i]);
835					envp[i] = NULL;
836					goto func_cont;
837				}
838			} else {
839				status = -ENOMEM;
840				goto func_cont;
841			}
842		}
843	}
844
845	if (!status) {
846		status = proc_load(hprocessor,
847				   args->args_proc_load.argc_index,
848				   (const char **)argv, (const char **)envp);
849	}
850func_cont:
851	if (envp) {
852		i = 0;
853		while (envp[i])
854			kfree(envp[i++]);
855
856		kfree(envp);
857	}
858
859	if (argv) {
860		count = args->args_proc_load.argc_index;
861		for (i = 0; (i < count) && argv[i]; i++)
862			kfree(argv[i]);
863
864		kfree(argv);
865	}
866
867	return status;
868}
869
870/*
871 * ======== procwrap_map ========
872 */
873u32 procwrap_map(union trapped_args *args, void *pr_ctxt)
874{
875	int status;
876	void *map_addr;
877	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
878
879	if (!args->args_proc_mapmem.size)
880		return -EINVAL;
881
882	status = proc_map(args->args_proc_mapmem.processor,
883			  args->args_proc_mapmem.mpu_addr,
884			  args->args_proc_mapmem.size,
885			  args->args_proc_mapmem.req_addr, &map_addr,
886			  args->args_proc_mapmem.map_attr, pr_ctxt);
887	if (!status) {
888		if (put_user(map_addr, args->args_proc_mapmem.map_addr)) {
889			status = -EINVAL;
890			proc_un_map(hprocessor, map_addr, pr_ctxt);
891		}
892
893	}
894	return status;
895}
896
897/*
898 * ======== procwrap_register_notify ========
899 */
900u32 procwrap_register_notify(union trapped_args *args, void *pr_ctxt)
901{
902	int status;
903	struct dsp_notification notification;
904	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
905
906	/* Initialize the notification data structure */
907	notification.name = NULL;
908	notification.handle = NULL;
909
910	status = proc_register_notify(hprocessor,
911				 args->args_proc_register_notify.event_mask,
912				 args->args_proc_register_notify.notify_type,
913				 &notification);
914	CP_TO_USR(args->args_proc_register_notify.notification, &notification,
915		  status, 1);
916	return status;
917}
918
919/*
920 * ======== procwrap_reserve_memory ========
921 */
922u32 procwrap_reserve_memory(union trapped_args *args, void *pr_ctxt)
923{
924	int status;
925	void *prsv_addr;
926	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
927
928	if ((args->args_proc_rsvmem.size <= 0) ||
929	    (args->args_proc_rsvmem.size & (PG_SIZE4K - 1)) != 0)
930		return -EINVAL;
931
932	status = proc_reserve_memory(hprocessor,
933				     args->args_proc_rsvmem.size, &prsv_addr,
934				     pr_ctxt);
935	if (!status) {
936		if (put_user(prsv_addr, args->args_proc_rsvmem.rsv_addr)) {
937			status = -EINVAL;
938			proc_un_reserve_memory(args->args_proc_rsvmem.
939					       processor, prsv_addr, pr_ctxt);
940		}
941	}
942	return status;
943}
944
945/*
946 * ======== procwrap_start ========
947 */
948u32 procwrap_start(union trapped_args *args, void *pr_ctxt)
949{
950	u32 ret;
951
952	ret = proc_start(((struct process_context *)pr_ctxt)->processor);
953	return ret;
954}
955
956/*
957 * ======== procwrap_un_map ========
958 */
959u32 procwrap_un_map(union trapped_args *args, void *pr_ctxt)
960{
961	int status;
962
963	status = proc_un_map(((struct process_context *)pr_ctxt)->processor,
964			     args->args_proc_unmapmem.map_addr, pr_ctxt);
965	return status;
966}
967
968/*
969 * ======== procwrap_un_reserve_memory ========
970 */
971u32 procwrap_un_reserve_memory(union trapped_args *args, void *pr_ctxt)
972{
973	int status;
974	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
975
976	status = proc_un_reserve_memory(hprocessor,
977					args->args_proc_unrsvmem.rsv_addr,
978					pr_ctxt);
979	return status;
980}
981
982/*
983 * ======== procwrap_stop ========
984 */
985u32 procwrap_stop(union trapped_args *args, void *pr_ctxt)
986{
987	u32 ret;
988
989	ret = proc_stop(((struct process_context *)pr_ctxt)->processor);
990
991	return ret;
992}
993
994/*
995 * ======== find_handle =========
996 */
997inline void find_node_handle(struct node_res_object **noderes,
998				void *pr_ctxt, void *hnode)
999{
1000	rcu_read_lock();
1001	*noderes = idr_find(((struct process_context *)pr_ctxt)->node_id,
1002								(int)hnode - 1);
1003	rcu_read_unlock();
1004	return;
1005}
1006
1007
1008/*
1009 * ======== nodewrap_allocate ========
1010 */
1011u32 nodewrap_allocate(union trapped_args *args, void *pr_ctxt)
1012{
1013	int status = 0;
1014	struct dsp_uuid node_uuid;
1015	u32 cb_data_size = 0;
1016	u32 __user *psize = (u32 __user *) args->args_node_allocate.args;
1017	u8 *pargs = NULL;
1018	struct dsp_nodeattrin proc_attr_in, *attr_in = NULL;
1019	struct node_res_object *node_res;
1020	int nodeid;
1021	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1022
1023	/* Optional argument */
1024	if (psize) {
1025		if (get_user(cb_data_size, psize))
1026			status = -EPERM;
1027
1028		cb_data_size += sizeof(u32);
1029		if (!status) {
1030			pargs = kmalloc(cb_data_size, GFP_KERNEL);
1031			if (pargs == NULL)
1032				status = -ENOMEM;
1033
1034		}
1035		CP_FM_USR(pargs, args->args_node_allocate.args, status,
1036			  cb_data_size);
1037	}
1038	CP_FM_USR(&node_uuid, args->args_node_allocate.node_id_ptr, status, 1);
1039	if (status)
1040		goto func_cont;
1041	/* Optional argument */
1042	if (args->args_node_allocate.attr_in) {
1043		CP_FM_USR(&proc_attr_in, args->args_node_allocate.attr_in,
1044			  status, 1);
1045		if (!status)
1046			attr_in = &proc_attr_in;
1047		else
1048			status = -ENOMEM;
1049
1050	}
1051	if (!status) {
1052		status = node_allocate(hprocessor,
1053				       &node_uuid, (struct dsp_cbdata *)pargs,
1054				       attr_in, &node_res, pr_ctxt);
1055	}
1056	if (!status) {
1057		nodeid = node_res->id + 1;
1058		CP_TO_USR(args->args_node_allocate.node, &nodeid,
1059			status, 1);
1060		if (status) {
1061			status = -EFAULT;
1062			node_delete(node_res, pr_ctxt);
1063		}
1064	}
1065func_cont:
1066	kfree(pargs);
1067
1068	return status;
1069}
1070
1071/*
1072 *  ======== nodewrap_alloc_msg_buf ========
1073 */
1074u32 nodewrap_alloc_msg_buf(union trapped_args *args, void *pr_ctxt)
1075{
1076	int status = 0;
1077	struct dsp_bufferattr *pattr = NULL;
1078	struct dsp_bufferattr attr;
1079	u8 *pbuffer = NULL;
1080	struct node_res_object *node_res;
1081
1082	find_node_handle(&node_res,  pr_ctxt,
1083				args->args_node_allocmsgbuf.node);
1084
1085	if (!node_res)
1086		return -EFAULT;
1087
1088	if (!args->args_node_allocmsgbuf.size)
1089		return -EINVAL;
1090
1091	if (args->args_node_allocmsgbuf.attr) {	/* Optional argument */
1092		CP_FM_USR(&attr, args->args_node_allocmsgbuf.attr, status, 1);
1093		if (!status)
1094			pattr = &attr;
1095
1096	}
1097	/* argument */
1098	CP_FM_USR(&pbuffer, args->args_node_allocmsgbuf.buffer, status, 1);
1099	if (!status) {
1100		status = node_alloc_msg_buf(node_res->node,
1101					    args->args_node_allocmsgbuf.size,
1102					    pattr, &pbuffer);
1103	}
1104	CP_TO_USR(args->args_node_allocmsgbuf.buffer, &pbuffer, status, 1);
1105	return status;
1106}
1107
1108/*
1109 * ======== nodewrap_change_priority ========
1110 */
1111u32 nodewrap_change_priority(union trapped_args *args, void *pr_ctxt)
1112{
1113	u32 ret;
1114	struct node_res_object *node_res;
1115
1116	find_node_handle(&node_res, pr_ctxt,
1117				args->args_node_changepriority.node);
1118
1119	if (!node_res)
1120		return -EFAULT;
1121
1122	ret = node_change_priority(node_res->node,
1123				   args->args_node_changepriority.prio);
1124
1125	return ret;
1126}
1127
1128/*
1129 * ======== nodewrap_connect ========
1130 */
1131u32 nodewrap_connect(union trapped_args *args, void *pr_ctxt)
1132{
1133	int status = 0;
1134	struct dsp_strmattr attrs;
1135	struct dsp_strmattr *pattrs = NULL;
1136	u32 cb_data_size;
1137	u32 __user *psize = (u32 __user *) args->args_node_connect.conn_param;
1138	u8 *pargs = NULL;
1139	struct node_res_object *node_res1, *node_res2;
1140	struct node_object *node1 = NULL, *node2 = NULL;
1141
1142	if ((int)args->args_node_connect.node != DSP_HGPPNODE) {
1143		find_node_handle(&node_res1, pr_ctxt,
1144				args->args_node_connect.node);
1145		if (node_res1)
1146			node1 = node_res1->node;
1147	} else {
1148		node1 = args->args_node_connect.node;
1149	}
1150
1151	if ((int)args->args_node_connect.other_node != DSP_HGPPNODE) {
1152		find_node_handle(&node_res2, pr_ctxt,
1153				args->args_node_connect.other_node);
1154		if (node_res2)
1155			node2 = node_res2->node;
1156	} else {
1157		node2 = args->args_node_connect.other_node;
1158	}
1159
1160	if (!node1 || !node2)
1161		return -EFAULT;
1162
1163	/* Optional argument */
1164	if (psize) {
1165		if (get_user(cb_data_size, psize))
1166			status = -EPERM;
1167
1168		cb_data_size += sizeof(u32);
1169		if (!status) {
1170			pargs = kmalloc(cb_data_size, GFP_KERNEL);
1171			if (pargs == NULL) {
1172				status = -ENOMEM;
1173				goto func_cont;
1174			}
1175
1176		}
1177		CP_FM_USR(pargs, args->args_node_connect.conn_param, status,
1178			  cb_data_size);
1179		if (status)
1180			goto func_cont;
1181	}
1182	if (args->args_node_connect.attrs) {	/* Optional argument */
1183		CP_FM_USR(&attrs, args->args_node_connect.attrs, status, 1);
1184		if (!status)
1185			pattrs = &attrs;
1186
1187	}
1188	if (!status) {
1189		status = node_connect(node1,
1190				      args->args_node_connect.stream_id,
1191				      node2,
1192				      args->args_node_connect.other_stream,
1193				      pattrs, (struct dsp_cbdata *)pargs);
1194	}
1195func_cont:
1196	kfree(pargs);
1197
1198	return status;
1199}
1200
1201/*
1202 * ======== nodewrap_create ========
1203 */
1204u32 nodewrap_create(union trapped_args *args, void *pr_ctxt)
1205{
1206	u32 ret;
1207	struct node_res_object *node_res;
1208
1209	find_node_handle(&node_res, pr_ctxt, args->args_node_create.node);
1210
1211	if (!node_res)
1212		return -EFAULT;
1213
1214	ret = node_create(node_res->node);
1215
1216	return ret;
1217}
1218
1219/*
1220 * ======== nodewrap_delete ========
1221 */
1222u32 nodewrap_delete(union trapped_args *args, void *pr_ctxt)
1223{
1224	u32 ret;
1225	struct node_res_object *node_res;
1226
1227	find_node_handle(&node_res, pr_ctxt, args->args_node_delete.node);
1228
1229	if (!node_res)
1230		return -EFAULT;
1231
1232	ret = node_delete(node_res, pr_ctxt);
1233
1234	return ret;
1235}
1236
1237/*
1238 *  ======== nodewrap_free_msg_buf ========
1239 */
1240u32 nodewrap_free_msg_buf(union trapped_args *args, void *pr_ctxt)
1241{
1242	int status = 0;
1243	struct dsp_bufferattr *pattr = NULL;
1244	struct dsp_bufferattr attr;
1245	struct node_res_object *node_res;
1246
1247	find_node_handle(&node_res, pr_ctxt, args->args_node_freemsgbuf.node);
1248
1249	if (!node_res)
1250		return -EFAULT;
1251
1252	if (args->args_node_freemsgbuf.attr) {	/* Optional argument */
1253		CP_FM_USR(&attr, args->args_node_freemsgbuf.attr, status, 1);
1254		if (!status)
1255			pattr = &attr;
1256
1257	}
1258
1259	if (!args->args_node_freemsgbuf.buffer)
1260		return -EFAULT;
1261
1262	if (!status) {
1263		status = node_free_msg_buf(node_res->node,
1264					   args->args_node_freemsgbuf.buffer,
1265					   pattr);
1266	}
1267
1268	return status;
1269}
1270
1271/*
1272 * ======== nodewrap_get_attr ========
1273 */
1274u32 nodewrap_get_attr(union trapped_args *args, void *pr_ctxt)
1275{
1276	int status = 0;
1277	struct dsp_nodeattr attr;
1278	struct node_res_object *node_res;
1279
1280	find_node_handle(&node_res, pr_ctxt, args->args_node_getattr.node);
1281
1282	if (!node_res)
1283		return -EFAULT;
1284
1285	status = node_get_attr(node_res->node, &attr,
1286			       args->args_node_getattr.attr_size);
1287	CP_TO_USR(args->args_node_getattr.attr, &attr, status, 1);
1288
1289	return status;
1290}
1291
1292/*
1293 * ======== nodewrap_get_message ========
1294 */
1295u32 nodewrap_get_message(union trapped_args *args, void *pr_ctxt)
1296{
1297	int status;
1298	struct dsp_msg msg;
1299	struct node_res_object *node_res;
1300
1301	find_node_handle(&node_res, pr_ctxt, args->args_node_getmessage.node);
1302
1303	if (!node_res)
1304		return -EFAULT;
1305
1306	status = node_get_message(node_res->node, &msg,
1307				  args->args_node_getmessage.timeout);
1308
1309	CP_TO_USR(args->args_node_getmessage.message, &msg, status, 1);
1310
1311	return status;
1312}
1313
1314/*
1315 * ======== nodewrap_pause ========
1316 */
1317u32 nodewrap_pause(union trapped_args *args, void *pr_ctxt)
1318{
1319	u32 ret;
1320	struct node_res_object *node_res;
1321
1322	find_node_handle(&node_res, pr_ctxt, args->args_node_pause.node);
1323
1324	if (!node_res)
1325		return -EFAULT;
1326
1327	ret = node_pause(node_res->node);
1328
1329	return ret;
1330}
1331
1332/*
1333 * ======== nodewrap_put_message ========
1334 */
1335u32 nodewrap_put_message(union trapped_args *args, void *pr_ctxt)
1336{
1337	int status = 0;
1338	struct dsp_msg msg;
1339	struct node_res_object *node_res;
1340
1341	find_node_handle(&node_res, pr_ctxt, args->args_node_putmessage.node);
1342
1343	if (!node_res)
1344		return -EFAULT;
1345
1346	CP_FM_USR(&msg, args->args_node_putmessage.message, status, 1);
1347
1348	if (!status) {
1349		status =
1350		    node_put_message(node_res->node, &msg,
1351				     args->args_node_putmessage.timeout);
1352	}
1353
1354	return status;
1355}
1356
1357/*
1358 * ======== nodewrap_register_notify ========
1359 */
1360u32 nodewrap_register_notify(union trapped_args *args, void *pr_ctxt)
1361{
1362	int status = 0;
1363	struct dsp_notification notification;
1364	struct node_res_object *node_res;
1365
1366	find_node_handle(&node_res, pr_ctxt,
1367			args->args_node_registernotify.node);
1368
1369	if (!node_res)
1370		return -EFAULT;
1371
1372	/* Initialize the notification data structure */
1373	notification.name = NULL;
1374	notification.handle = NULL;
1375
1376	if (!args->args_proc_register_notify.event_mask)
1377		CP_FM_USR(&notification,
1378			  args->args_proc_register_notify.notification,
1379			  status, 1);
1380
1381	status = node_register_notify(node_res->node,
1382				      args->args_node_registernotify.event_mask,
1383				      args->args_node_registernotify.
1384				      notify_type, &notification);
1385	CP_TO_USR(args->args_node_registernotify.notification, &notification,
1386		  status, 1);
1387	return status;
1388}
1389
1390/*
1391 * ======== nodewrap_run ========
1392 */
1393u32 nodewrap_run(union trapped_args *args, void *pr_ctxt)
1394{
1395	u32 ret;
1396	struct node_res_object *node_res;
1397
1398	find_node_handle(&node_res, pr_ctxt, args->args_node_run.node);
1399
1400	if (!node_res)
1401		return -EFAULT;
1402
1403	ret = node_run(node_res->node);
1404
1405	return ret;
1406}
1407
1408/*
1409 * ======== nodewrap_terminate ========
1410 */
1411u32 nodewrap_terminate(union trapped_args *args, void *pr_ctxt)
1412{
1413	int status;
1414	int tempstatus;
1415	struct node_res_object *node_res;
1416
1417	find_node_handle(&node_res, pr_ctxt, args->args_node_terminate.node);
1418
1419	if (!node_res)
1420		return -EFAULT;
1421
1422	status = node_terminate(node_res->node, &tempstatus);
1423
1424	CP_TO_USR(args->args_node_terminate.status, &tempstatus, status, 1);
1425
1426	return status;
1427}
1428
1429/*
1430 * ======== nodewrap_get_uuid_props ========
1431 */
1432u32 nodewrap_get_uuid_props(union trapped_args *args, void *pr_ctxt)
1433{
1434	int status = 0;
1435	struct dsp_uuid node_uuid;
1436	struct dsp_ndbprops *pnode_props = NULL;
1437	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1438
1439	CP_FM_USR(&node_uuid, args->args_node_getuuidprops.node_id_ptr, status,
1440		  1);
1441	if (status)
1442		goto func_cont;
1443	pnode_props = kmalloc(sizeof(struct dsp_ndbprops), GFP_KERNEL);
1444	if (pnode_props != NULL) {
1445		status =
1446		    node_get_uuid_props(hprocessor, &node_uuid, pnode_props);
1447		CP_TO_USR(args->args_node_getuuidprops.node_props, pnode_props,
1448			  status, 1);
1449	} else
1450		status = -ENOMEM;
1451func_cont:
1452	kfree(pnode_props);
1453	return status;
1454}
1455
1456/*
1457 * ======== find_strm_handle =========
1458 */
1459inline void find_strm_handle(struct strm_res_object **strmres,
1460				void *pr_ctxt, void *hstream)
1461{
1462	rcu_read_lock();
1463	*strmres = idr_find(((struct process_context *)pr_ctxt)->stream_id,
1464							(int)hstream - 1);
1465	rcu_read_unlock();
1466	return;
1467}
1468
1469/*
1470 * ======== strmwrap_allocate_buffer ========
1471 */
1472u32 strmwrap_allocate_buffer(union trapped_args *args, void *pr_ctxt)
1473{
1474	int status;
1475	u8 **ap_buffer = NULL;
1476	u32 num_bufs = args->args_strm_allocatebuffer.num_bufs;
1477	struct strm_res_object *strm_res;
1478
1479	find_strm_handle(&strm_res, pr_ctxt,
1480		args->args_strm_allocatebuffer.stream);
1481
1482	if (!strm_res)
1483		return -EFAULT;
1484
1485	if (num_bufs > MAX_BUFS)
1486		return -EINVAL;
1487
1488	ap_buffer = kmalloc((num_bufs * sizeof(u8 *)), GFP_KERNEL);
1489	if (ap_buffer == NULL)
1490		return -ENOMEM;
1491
1492	status = strm_allocate_buffer(strm_res,
1493				      args->args_strm_allocatebuffer.size,
1494				      ap_buffer, num_bufs, pr_ctxt);
1495	if (!status) {
1496		CP_TO_USR(args->args_strm_allocatebuffer.ap_buffer, ap_buffer,
1497			  status, num_bufs);
1498		if (status) {
1499			status = -EFAULT;
1500			strm_free_buffer(strm_res,
1501					 ap_buffer, num_bufs, pr_ctxt);
1502		}
1503	}
1504	kfree(ap_buffer);
1505
1506	return status;
1507}
1508
1509/*
1510 * ======== strmwrap_close ========
1511 */
1512u32 strmwrap_close(union trapped_args *args, void *pr_ctxt)
1513{
1514	struct strm_res_object *strm_res;
1515
1516	find_strm_handle(&strm_res, pr_ctxt, args->args_strm_close.stream);
1517
1518	if (!strm_res)
1519		return -EFAULT;
1520
1521	return strm_close(strm_res, pr_ctxt);
1522}
1523
1524/*
1525 * ======== strmwrap_free_buffer ========
1526 */
1527u32 strmwrap_free_buffer(union trapped_args *args, void *pr_ctxt)
1528{
1529	int status = 0;
1530	u8 **ap_buffer = NULL;
1531	u32 num_bufs = args->args_strm_freebuffer.num_bufs;
1532	struct strm_res_object *strm_res;
1533
1534	find_strm_handle(&strm_res, pr_ctxt,
1535			args->args_strm_freebuffer.stream);
1536
1537	if (!strm_res)
1538		return -EFAULT;
1539
1540	if (num_bufs > MAX_BUFS)
1541		return -EINVAL;
1542
1543	ap_buffer = kmalloc((num_bufs * sizeof(u8 *)), GFP_KERNEL);
1544	if (ap_buffer == NULL)
1545		return -ENOMEM;
1546
1547	CP_FM_USR(ap_buffer, args->args_strm_freebuffer.ap_buffer, status,
1548		  num_bufs);
1549
1550	if (!status)
1551		status = strm_free_buffer(strm_res,
1552					  ap_buffer, num_bufs, pr_ctxt);
1553
1554	CP_TO_USR(args->args_strm_freebuffer.ap_buffer, ap_buffer, status,
1555		  num_bufs);
1556	kfree(ap_buffer);
1557
1558	return status;
1559}
1560
1561/*
1562 * ======== strmwrap_get_event_handle ========
1563 */
1564u32 __deprecated strmwrap_get_event_handle(union trapped_args * args,
1565					   void *pr_ctxt)
1566{
1567	pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1568	return -ENOSYS;
1569}
1570
1571/*
1572 * ======== strmwrap_get_info ========
1573 */
1574u32 strmwrap_get_info(union trapped_args *args, void *pr_ctxt)
1575{
1576	int status = 0;
1577	struct stream_info strm_info;
1578	struct dsp_streaminfo user;
1579	struct dsp_streaminfo *temp;
1580	struct strm_res_object *strm_res;
1581
1582	find_strm_handle(&strm_res, pr_ctxt,
1583			args->args_strm_getinfo.stream);
1584
1585	if (!strm_res)
1586		return -EFAULT;
1587
1588	CP_FM_USR(&strm_info, args->args_strm_getinfo.stream_info, status, 1);
1589	temp = strm_info.user_strm;
1590
1591	strm_info.user_strm = &user;
1592
1593	if (!status) {
1594		status = strm_get_info(strm_res->stream,
1595				       &strm_info,
1596				       args->args_strm_getinfo.
1597				       stream_info_size);
1598	}
1599	CP_TO_USR(temp, strm_info.user_strm, status, 1);
1600	strm_info.user_strm = temp;
1601	CP_TO_USR(args->args_strm_getinfo.stream_info, &strm_info, status, 1);
1602	return status;
1603}
1604
1605/*
1606 * ======== strmwrap_idle ========
1607 */
1608u32 strmwrap_idle(union trapped_args *args, void *pr_ctxt)
1609{
1610	u32 ret;
1611	struct strm_res_object *strm_res;
1612
1613	find_strm_handle(&strm_res, pr_ctxt, args->args_strm_idle.stream);
1614
1615	if (!strm_res)
1616		return -EFAULT;
1617
1618	ret = strm_idle(strm_res->stream, args->args_strm_idle.flush_flag);
1619
1620	return ret;
1621}
1622
1623/*
1624 * ======== strmwrap_issue ========
1625 */
1626u32 strmwrap_issue(union trapped_args *args, void *pr_ctxt)
1627{
1628	int status = 0;
1629	struct strm_res_object *strm_res;
1630
1631	find_strm_handle(&strm_res, pr_ctxt, args->args_strm_issue.stream);
1632
1633	if (!strm_res)
1634		return -EFAULT;
1635
1636	if (!args->args_strm_issue.buffer)
1637		return -EFAULT;
1638
1639	/* No need of doing CP_FM_USR for the user buffer (pbuffer)
1640	   as this is done in Bridge internal function bridge_chnl_add_io_req
1641	   in chnl_sm.c */
1642	status = strm_issue(strm_res->stream,
1643			    args->args_strm_issue.buffer,
1644			    args->args_strm_issue.bytes,
1645			    args->args_strm_issue.buf_size,
1646			    args->args_strm_issue.arg);
1647
1648	return status;
1649}
1650
1651/*
1652 * ======== strmwrap_open ========
1653 */
1654u32 strmwrap_open(union trapped_args *args, void *pr_ctxt)
1655{
1656	int status = 0;
1657	struct strm_attr attr;
1658	struct strm_res_object *strm_res_obj;
1659	struct dsp_streamattrin strm_attr_in;
1660	struct node_res_object *node_res;
1661	int strmid;
1662
1663	find_node_handle(&node_res, pr_ctxt, args->args_strm_open.node);
1664
1665	if (!node_res)
1666		return -EFAULT;
1667
1668	CP_FM_USR(&attr, args->args_strm_open.attr_in, status, 1);
1669
1670	if (attr.stream_attr_in != NULL) {	/* Optional argument */
1671		CP_FM_USR(&strm_attr_in, attr.stream_attr_in, status, 1);
1672		if (!status) {
1673			attr.stream_attr_in = &strm_attr_in;
1674			if (attr.stream_attr_in->strm_mode == STRMMODE_LDMA)
1675				return -ENOSYS;
1676		}
1677
1678	}
1679	status = strm_open(node_res->node,
1680			   args->args_strm_open.direction,
1681			   args->args_strm_open.index, &attr, &strm_res_obj,
1682			   pr_ctxt);
1683	if (!status) {
1684		strmid = strm_res_obj->id + 1;
1685		CP_TO_USR(args->args_strm_open.stream, &strmid, status, 1);
1686	}
1687	return status;
1688}
1689
1690/*
1691 * ======== strmwrap_reclaim ========
1692 */
1693u32 strmwrap_reclaim(union trapped_args *args, void *pr_ctxt)
1694{
1695	int status = 0;
1696	u8 *buf_ptr;
1697	u32 ul_bytes;
1698	u32 dw_arg;
1699	u32 ul_buf_size;
1700	struct strm_res_object *strm_res;
1701
1702	find_strm_handle(&strm_res, pr_ctxt, args->args_strm_reclaim.stream);
1703
1704	if (!strm_res)
1705		return -EFAULT;
1706
1707	status = strm_reclaim(strm_res->stream, &buf_ptr,
1708			      &ul_bytes, &ul_buf_size, &dw_arg);
1709	CP_TO_USR(args->args_strm_reclaim.buf_ptr, &buf_ptr, status, 1);
1710	CP_TO_USR(args->args_strm_reclaim.bytes, &ul_bytes, status, 1);
1711	CP_TO_USR(args->args_strm_reclaim.arg, &dw_arg, status, 1);
1712
1713	if (args->args_strm_reclaim.buf_size_ptr != NULL) {
1714		CP_TO_USR(args->args_strm_reclaim.buf_size_ptr, &ul_buf_size,
1715			  status, 1);
1716	}
1717
1718	return status;
1719}
1720
1721/*
1722 * ======== strmwrap_register_notify ========
1723 */
1724u32 strmwrap_register_notify(union trapped_args *args, void *pr_ctxt)
1725{
1726	int status = 0;
1727	struct dsp_notification notification;
1728	struct strm_res_object *strm_res;
1729
1730	find_strm_handle(&strm_res, pr_ctxt,
1731			args->args_strm_registernotify.stream);
1732
1733	if (!strm_res)
1734		return -EFAULT;
1735
1736	/* Initialize the notification data structure */
1737	notification.name = NULL;
1738	notification.handle = NULL;
1739
1740	status = strm_register_notify(strm_res->stream,
1741				      args->args_strm_registernotify.event_mask,
1742				      args->args_strm_registernotify.
1743				      notify_type, &notification);
1744	CP_TO_USR(args->args_strm_registernotify.notification, &notification,
1745		  status, 1);
1746
1747	return status;
1748}
1749
1750/*
1751 * ======== strmwrap_select ========
1752 */
1753u32 strmwrap_select(union trapped_args *args, void *pr_ctxt)
1754{
1755	u32 mask;
1756	struct strm_object *strm_tab[MAX_STREAMS];
1757	int status = 0;
1758	struct strm_res_object *strm_res;
1759	int *ids[MAX_STREAMS];
1760	int i;
1761
1762	if (args->args_strm_select.strm_num > MAX_STREAMS)
1763		return -EINVAL;
1764
1765	CP_FM_USR(ids, args->args_strm_select.stream_tab, status,
1766		args->args_strm_select.strm_num);
1767
1768	if (status)
1769		return status;
1770
1771	for (i = 0; i < args->args_strm_select.strm_num; i++) {
1772		find_strm_handle(&strm_res, pr_ctxt, ids[i]);
1773
1774		if (!strm_res)
1775			return -EFAULT;
1776
1777		strm_tab[i] = strm_res->stream;
1778	}
1779
1780	if (!status) {
1781		status = strm_select(strm_tab, args->args_strm_select.strm_num,
1782				     &mask, args->args_strm_select.timeout);
1783	}
1784	CP_TO_USR(args->args_strm_select.mask, &mask, status, 1);
1785	return status;
1786}
1787
1788/* CMM */
1789
1790/*
1791 * ======== cmmwrap_calloc_buf ========
1792 */
1793u32 __deprecated cmmwrap_calloc_buf(union trapped_args * args, void *pr_ctxt)
1794{
1795	/* This operation is done in kernel */
1796	pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1797	return -ENOSYS;
1798}
1799
1800/*
1801 * ======== cmmwrap_free_buf ========
1802 */
1803u32 __deprecated cmmwrap_free_buf(union trapped_args * args, void *pr_ctxt)
1804{
1805	/* This operation is done in kernel */
1806	pr_err("%s: deprecated dspbridge ioctl\n", __func__);
1807	return -ENOSYS;
1808}
1809
1810/*
1811 * ======== cmmwrap_get_handle ========
1812 */
1813u32 cmmwrap_get_handle(union trapped_args *args, void *pr_ctxt)
1814{
1815	int status = 0;
1816	struct cmm_object *hcmm_mgr;
1817	void *hprocessor = ((struct process_context *)pr_ctxt)->processor;
1818
1819	status = cmm_get_handle(hprocessor, &hcmm_mgr);
1820
1821	CP_TO_USR(args->args_cmm_gethandle.cmm_mgr, &hcmm_mgr, status, 1);
1822
1823	return status;
1824}
1825
1826/*
1827 * ======== cmmwrap_get_info ========
1828 */
1829u32 cmmwrap_get_info(union trapped_args *args, void *pr_ctxt)
1830{
1831	int status = 0;
1832	struct cmm_info cmm_info_obj;
1833
1834	status = cmm_get_info(args->args_cmm_getinfo.cmm_mgr, &cmm_info_obj);
1835
1836	CP_TO_USR(args->args_cmm_getinfo.cmm_info_obj, &cmm_info_obj, status,
1837		  1);
1838
1839	return status;
1840}
1841