This adds a helper function for unidirectional asynchronous transfer. This is just for convenience as some drivers do these steps manually, like the loopback driver in gb_loopback_async_operation().
Signed-off-by: Damien Riégel damien.riegel@silabs.com --- drivers/greybus/operation.c | 52 +++++++++++++++++++++++++++++++ include/linux/greybus/operation.h | 4 +++ 2 files changed, 56 insertions(+)
diff --git a/drivers/greybus/operation.c b/drivers/greybus/operation.c index 8459e9bc074..a599b9d36cf 100644 --- a/drivers/greybus/operation.c +++ b/drivers/greybus/operation.c @@ -1174,6 +1174,58 @@ int gb_operation_sync_timeout(struct gb_connection *connection, int type, } EXPORT_SYMBOL_GPL(gb_operation_sync_timeout);
+/** + * gb_operation_unidirectional_async_timeout() - initiate an asynchronous unidirectional operation + * @connection: connection to use + * @callback: function called when operation completes + * @data: user-data, retrieved with gb_operation_get_data() + * @type: type of operation to send + * @request: memory buffer to copy the request from + * @request_size: size of @request + * @timeout: send timeout in milliseconds + * + * Initiate a unidirectional operation by sending a request message. Completion is notified by the + * user-provided callback. User can determine operation status with gb_operation_result(). + * operation must be released with gb_operation_put(). + * + * Note that successful send of a unidirectional operation does not imply that + * the request as actually reached the remote end of the connection. + */ +int gb_operation_unidirectional_async_timeout(struct gb_connection *connection, + gb_operation_callback callback, void *data, + int type, void *request, int request_size, + unsigned int timeout) +{ + struct gb_operation *operation; + int ret; + + if (request_size && !request) + return -EINVAL; + + operation = gb_operation_create_flags(connection, type, + request_size, 0, + GB_OPERATION_FLAG_UNIDIRECTIONAL, + GFP_KERNEL); + if (!operation) + return -ENOMEM; + + gb_operation_set_data(operation, data); + + if (request_size) + memcpy(operation->request->payload, request, request_size); + + ret = gb_operation_request_send(operation, callback, timeout, GFP_KERNEL); + if (ret) { + dev_err(&connection->hd->dev, + "%s: asynchronous operation id 0x%04x of type 0x%02x failed: %d\n", + connection->name, operation->id, type, ret); + gb_operation_put(operation); + } + + return ret; +} +EXPORT_SYMBOL_GPL(gb_operation_unidirectional_async_timeout); + /** * gb_operation_unidirectional_timeout() - initiate a unidirectional operation * @connection: connection to use diff --git a/include/linux/greybus/operation.h b/include/linux/greybus/operation.h index cb8e4ef4522..01dd1d89d89 100644 --- a/include/linux/greybus/operation.h +++ b/include/linux/greybus/operation.h @@ -192,6 +192,10 @@ int gb_operation_sync_timeout(struct gb_connection *connection, int type, void *request, int request_size, void *response, int response_size, unsigned int timeout); +int gb_operation_unidirectional_async_timeout(struct gb_connection *connection, + gb_operation_callback callback, void *data, + int type, void *request, int request_size, + unsigned int timeout); int gb_operation_unidirectional_timeout(struct gb_connection *connection, int type, void *request, int request_size, unsigned int timeout);