/**
* struct gb_camera - A Greybus Camera Device
- * @connection: the greybus connection for camera control
+ * @connection: the greybus connection for camera management
+ * @data_connection: the greybus connection for camera data
+ * @mutex: protects the connection field
* @debugfs: debugfs entries for camera protocol operations testing
* @module: Greybus camera module registered to HOST processor.
*/
struct gb_bundle *bundle;
struct gb_connection *connection;
struct gb_connection *data_connection;
+ struct mutex mutex;
struct {
struct dentry *root;
static int gb_camera_capabilities(struct gb_camera *gcam,
u8 *capabilities, size_t *size)
{
- struct gb_operation *op;
+ struct gb_operation *op = NULL;
int ret;
+ mutex_lock(&gcam->mutex);
+
+ if (!gcam->connection) {
+ ret = -EINVAL;
+ goto done;
+ }
+
op = gb_operation_create_flags(gcam->connection,
GB_CAMERA_TYPE_CAPABILITIES, 0, *size,
GB_OPERATION_FLAG_SHORT_RESPONSE,
GFP_KERNEL);
- if (!op)
- return -ENOMEM;
+ if (!op) {
+ ret = -ENOMEM;
+ goto done;
+ }
ret = gb_operation_request_send_sync(op);
if (ret) {
*size = op->response->payload_size;
done:
- gb_operation_put(op);
+ mutex_unlock(&gcam->mutex);
+ if (op)
+ gb_operation_put(op);
return ret;
}
req = kmalloc(req_size, GFP_KERNEL);
resp = kmalloc(resp_size, GFP_KERNEL);
if (!req || !resp) {
- ret = -ENOMEM;
- goto done;
+ kfree(req);
+ kfree(resp);
+ return -ENOMEM;
}
req->num_streams = nstreams;
cfg->padding = 0;
}
+ mutex_lock(&gcam->mutex);
+
+ if (!gcam->connection) {
+ ret = -EINVAL;
+ goto done;
+ }
+
ret = gb_operation_sync(gcam->connection,
GB_CAMERA_TYPE_CONFIGURE_STREAMS,
req, req_size, resp, resp_size);
ret = 0;
done:
+ mutex_unlock(&gcam->mutex);
kfree(req);
kfree(resp);
return ret;
req->num_frames = cpu_to_le16(num_frames);
memcpy(req->settings, settings, settings_size);
+ mutex_lock(&gcam->mutex);
+
+ if (!gcam->connection) {
+ ret = -EINVAL;
+ goto done;
+ }
+
ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_CAPTURE,
- req, req_size, NULL, 0);
+ req, req_size, NULL, 0);
+done:
+ mutex_unlock(&gcam->mutex);
kfree(req);
struct gb_camera_flush_response resp;
int ret;
+ mutex_lock(&gcam->mutex);
+
+ if (!gcam->connection) {
+ ret = -EINVAL;
+ goto done;
+ }
+
ret = gb_operation_sync(gcam->connection, GB_CAMERA_TYPE_FLUSH, NULL, 0,
&resp, sizeof(resp));
+
if (ret < 0)
- return ret;
+ goto done;
if (request_id)
*request_id = le32_to_cpu(resp.request_id);
- return 0;
+done:
+ mutex_unlock(&gcam->mutex);
+
+ return ret;
}
static int gb_camera_request_handler(struct gb_operation *op)
.flush = gb_camera_op_flush,
};
-static int gb_camera_register_intf_ops(struct gb_camera *gcam)
-{
- gcam->module.priv = gcam;
- gcam->module.ops = &gb_cam_ops;
- return gb_camera_register(&gcam->module);
-}
-
-static int gb_camera_unregister_intf_ops(struct gb_camera *gcam)
-{
- return gb_camera_unregister(&gcam->module);
-}
-
/* -----------------------------------------------------------------------------
* DebugFS
*/
if (gcam->data_connection) {
gb_connection_disable(gcam->data_connection);
gb_connection_destroy(gcam->data_connection);
+ gcam->data_connection = NULL;
}
+ mutex_lock(&gcam->mutex);
if (gcam->connection) {
gb_connection_disable(gcam->connection);
gb_connection_destroy(gcam->connection);
+ gcam->connection = NULL;
}
+ mutex_unlock(&gcam->mutex);
+}
- kfree(gcam);
+static void gb_camera_release_module(struct kref *ref)
+{
+ struct gb_camera_module *cam_mod =
+ container_of(ref, struct gb_camera_module, refcount);
+ kfree(cam_mod->priv);
}
static int gb_camera_probe(struct gb_bundle *bundle,
if (ret)
goto error;
+ mutex_init(&gcam->mutex);
+
/*
* Create the data connection between the camera module data CPort and
* APB CDSI1. The CDSI1 CPort ID is hardcoded by the ES2 bridge.
if (ret < 0)
goto error;
- ret = gb_camera_register_intf_ops(gcam);
+ gcam->module.priv = gcam;
+ gcam->module.ops = &gb_cam_ops;
+ gcam->module.interface_id = gcam->connection->intf->interface_id;
+ gcam->module.release = gb_camera_release_module;
+ ret = gb_camera_register(&gcam->module);
if (ret < 0)
goto error;
error:
gb_camera_cleanup(gcam);
+ kfree(gcam);
return ret;
}
{
struct gb_camera *gcam = greybus_get_drvdata(bundle);
- gb_camera_unregister_intf_ops(gcam);
gb_camera_cleanup(gcam);
+ gb_camera_unregister(&gcam->module);
}
static const struct greybus_bundle_id gb_camera_id_table[] = {