@@ -250,3 +250,221 @@ int fastrpc2(const struct fastrpc_function_def_interp2 *def,
250250
251251 return ret ;
252252}
253+
254+ /*
255+ * This populates relevant arguments with information necessary to receive
256+ * output from the remote processor.
257+ *
258+ * First, it allocates a new first output buffer to contain the returned 32-bit
259+ * integers. This output buffer must be freed after use.
260+ *
261+ * With a peek at the output arguments, it populates the fastrpc_invoke_args
262+ * struct to give information about the provided buffers to the kernel, and
263+ * adds an entry to the first input buffer to tell the remote processor the
264+ * size of the function-level output buffer.
265+ */
266+ static void prepare_outbufs3 (const struct hrpc_method_def_interp3 * def ,
267+ struct fastrpc_invoke_args * args ,
268+ size_t delim ,
269+ uint32_t * n_prim_in , uint8_t * n_outbufs ,
270+ uint32_t * prim ,
271+ va_list peek )
272+ {
273+ uint32_t n_prim_out = 0 ;
274+ size_t i ;
275+
276+ if (def -> has_prim_out )
277+ * n_outbufs = 1 ;
278+ else
279+ * n_outbufs = 0 ;
280+
281+ for (i = delim ; i < def -> n_args ; i ++ ) {
282+ if (def -> args [i ]) {
283+ prim [* n_prim_in ] = va_arg (peek , uint32_t );
284+
285+ args [* n_outbufs ].length = prim [* n_prim_in ] * def -> args [i ];
286+ args [* n_outbufs ].ptr = (__u64 ) va_arg (peek , void * );
287+ args [* n_outbufs ].fd = -1 ;
288+
289+ (* n_prim_in )++ ;
290+ (* n_outbufs )++ ;
291+ } else {
292+ va_arg (peek , uint32_t * );
293+ n_prim_out ++ ;
294+ }
295+ }
296+
297+ if (def -> has_prim_out ) {
298+ args [0 ].length = sizeof (uint32_t ) * n_prim_out ;
299+ args [0 ].ptr = (__u64 ) & prim [* n_prim_in ];
300+ args [0 ].fd = -1 ;
301+ }
302+ }
303+
304+ static void return_prim_out (const struct hrpc_method_def_interp3 * def ,
305+ size_t delim ,
306+ const uint32_t * prim_out ,
307+ va_list list )
308+ {
309+ uint32_t * ptr ;
310+ size_t i , j = 0 ;
311+
312+ for (i = delim ; i < def -> n_args ; i ++ ) {
313+ if (def -> args [i ]) {
314+ va_arg (list , uint32_t );
315+ va_arg (list , void * );
316+ } else {
317+ ptr = va_arg (list , uint32_t * );
318+ * ptr = prim_out [j ];
319+ j ++ ;
320+ }
321+ }
322+ }
323+
324+ /*
325+ * This is the main function to invoke a FastRPC procedure call. The first
326+ * parameter specifies how to populate the ioctl-level buffers. The second and
327+ * third parameters specify where to send the invocation to. The fourth is the
328+ * list of arguments that the procedure call should interact with.
329+ *
330+ * A good example for this would be the adsp_listener_next2 call:
331+ *
332+ * static inline void adsp_listener_next2(int fd, uint32_t handle,
333+ * uint32_t prev_ctx,
334+ * uint32_t prev_result,
335+ * uint32_t nested_outbufs_len,
336+ * void *nested_outbufs,
337+ * uint32_t *ctx,
338+ * uint32_t *nested_handle,
339+ * uint32_t *nested_sc,
340+ * uint32_t *nested_inbufs_len,
341+ * uint32_t nested_inbufs_size,
342+ * void *nested_inbufs)
343+ * {
344+ * uint32_t args[] = { 0, 0, 1, HEXAGONRPC_DELIMITER, 0, 0, 0, 1 };
345+ * struct hrpc_method_def_interp3 def = {
346+ * .mid = 4,
347+ * .has_out_prim = true,
348+ * .n_args = 8,
349+ * .args = args,
350+ * };
351+ * return vhexagonrpc2(def, fd, handle,
352+ * prev_ctx,
353+ * prev_result,
354+ * nested_outbufs_len,
355+ * nested_outbufs,
356+ * ctx,
357+ * nested_handle,
358+ * nested_sc,
359+ * nested_inbufs_len,
360+ * nested_inbufs_size,
361+ * nested_inbufs);
362+ * }
363+ */
364+ int vhexagonrpc2 (const struct hrpc_method_def_interp3 * def ,
365+ int fd , uint32_t handle , va_list list )
366+ {
367+ va_list peek ;
368+ struct fastrpc_invoke invoke ;
369+ struct fastrpc_invoke_args * args ;
370+ uint32_t * prim ;
371+ uint32_t n_prim_in = 0 ;
372+ uint32_t msg_id ;
373+ uint8_t n_inbufs = 1 , n_outbufs ;
374+ size_t i ;
375+ int ret = -1 ;
376+
377+ /*
378+ * If there are only input buffers specified in the method definition,
379+ * we need an extra primary input argument for their sizes.
380+ */
381+ args = malloc (sizeof (struct fastrpc_invoke_args ) * (def -> n_args + 1 ));
382+ if (args == NULL )
383+ return -1 ;
384+
385+ /*
386+ * The input and output buffers need a size in the primary input buffer
387+ * so all arguments except the optional delimiter contribute to the
388+ * primary buffers.
389+ */
390+ prim = malloc (sizeof (uint32_t ) * (def -> n_args + 1 ));
391+ if (prim == NULL )
392+ goto err_free_args ;
393+
394+ /*
395+ * The apps_std interface demonstrates that there is support
396+ * for more than 32 methods for a single interface. Support
397+ * extended method IDs that go beyond 5 bits and the ID
398+ * reserved for this purpose.
399+ */
400+ if (def -> msg_id >= 31 ) {
401+ prim [n_prim_in ] = def -> msg_id ;
402+ n_prim_in ++ ;
403+ msg_id = 31 ;
404+ } else {
405+ msg_id = def -> msg_id ;
406+ }
407+
408+ for (i = 0 ; i < def -> n_args ; i ++ ) {
409+ if (def -> args [i ] == HEXAGONRPC_DELIMITER ) {
410+ i ++ ;
411+ break ;
412+ }
413+
414+ prim [n_prim_in ] = va_arg (list , uint32_t );
415+
416+ if (def -> args [i ]) {
417+ args [n_inbufs ].length = prim [n_prim_in ] * def -> args [i ];
418+ args [n_inbufs ].ptr = (__u64 ) va_arg (list , const void * );
419+ args [n_inbufs ].fd = -1 ;
420+ n_inbufs ++ ;
421+ }
422+
423+ n_prim_in ++ ;
424+ }
425+
426+ va_copy (peek , list );
427+ prepare_outbufs3 (def , & args [n_inbufs ], i , & n_prim_in , & n_outbufs , prim , peek );
428+ va_end (peek );
429+
430+ args [0 ].length = sizeof (uint32_t ) * n_prim_in ;
431+ args [0 ].ptr = (__u64 ) prim ;
432+ args [0 ].fd = -1 ;
433+
434+ // Pass the primary input buffer if not empty, otherwise skip it.
435+ if (n_prim_in != 0 ) {
436+ invoke .args = (__u64 ) args ;
437+ } else {
438+ invoke .args = (__u64 ) & args [1 ];
439+ n_inbufs -- ;
440+ }
441+
442+ invoke .handle = handle ;
443+ invoke .sc = REMOTE_SCALARS_MAKE (msg_id , n_inbufs , n_outbufs );
444+
445+ ret = ioctl (fd , FASTRPC_IOCTL_INVOKE , (__u64 ) & invoke );
446+ if (ret == -1 )
447+ goto err_free_prim ;
448+
449+ return_prim_out (def , i , & prim [n_prim_in ], list );
450+
451+ err_free_prim :
452+ free (prim );
453+ err_free_args :
454+ free (args );
455+
456+ return ret ;
457+ }
458+
459+ int hexagonrpc2 (const struct hrpc_method_def_interp3 * def ,
460+ int fd , uint32_t handle , ...)
461+ {
462+ va_list list ;
463+ int ret ;
464+
465+ va_start (list , handle );
466+ ret = vhexagonrpc2 (def , fd , handle , list );
467+ va_end (list );
468+
469+ return ret ;
470+ }
0 commit comments