From 045d356114557781f4b703ff569f2e3785e87b2e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 11 May 2016 10:18:04 +0200 Subject: [PATCH] greybus: es2: add support for CDSI1 allocation Use the new CPort-allocation callbacks to allow for rudimentary resource management of the CDSI CPorts. How to manage offloaded resources in a generic fashion is yet to be determined, but this minimal implementation will allow core to manage the camera data connection so that the current camera-driver hacks can be removed. This is specifically required to be able to implement proper connection closing and for power management. Note that the CDSI CPorts can not (currently) be reset through the USB vendor request. Signed-off-by: Johan Hovold Reviewed-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.h | 1 + drivers/staging/greybus/es2.c | 59 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index a8da9ca214be..b152e2340591 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -16,6 +16,7 @@ #define GB_CONNECTION_FLAG_CSD BIT(0) #define GB_CONNECTION_FLAG_NO_FLOWCTRL BIT(1) #define GB_CONNECTION_FLAG_OFFLOADED BIT(2) +#define GB_CONNECTION_FLAG_CDSI1 BIT(3) enum gb_connection_state { GB_CONNECTION_STATE_INVALID = 0, diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index f06a322f851a..998b41ebc53e 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -99,6 +99,8 @@ struct es2_ap_dev { bool cport_out_urb_cancelled[NUM_CPORT_OUT_URB]; spinlock_t cport_out_urb_lock; + bool cdsi1_in_use; + int *cport_to_ep; struct task_struct *apb_log_task; @@ -508,6 +510,8 @@ static int cport_reset(struct gb_host_device *hd, u16 cport_id) switch (cport_id) { case GB_SVC_CPORT_ID: + case ES2_CPORT_CDSI0: + case ES2_CPORT_CDSI1: return 0; } @@ -525,6 +529,59 @@ static int cport_reset(struct gb_host_device *hd, u16 cport_id) return 0; } +static int es2_cport_allocate(struct gb_host_device *hd, int cport_id, + unsigned long flags) +{ + struct es2_ap_dev *es2 = hd_to_es2(hd); + struct ida *id_map = &hd->cport_id_map; + int ida_start, ida_end; + + switch (cport_id) { + case ES2_CPORT_CDSI0: + case ES2_CPORT_CDSI1: + dev_err(&hd->dev, "cport %d not available\n", cport_id); + return -EBUSY; + } + + if (flags & GB_CONNECTION_FLAG_OFFLOADED && + flags & GB_CONNECTION_FLAG_CDSI1) { + if (es2->cdsi1_in_use) { + dev_err(&hd->dev, "CDSI1 already in use\n"); + return -EBUSY; + } + + es2->cdsi1_in_use = true; + + return ES2_CPORT_CDSI1; + } + + if (cport_id < 0) { + ida_start = 0; + ida_end = hd->num_cports; + } else if (cport_id < hd->num_cports) { + ida_start = cport_id; + ida_end = cport_id + 1; + } else { + dev_err(&hd->dev, "cport %d not available\n", cport_id); + return -EINVAL; + } + + return ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL); +} + +static void es2_cport_release(struct gb_host_device *hd, u16 cport_id) +{ + struct es2_ap_dev *es2 = hd_to_es2(hd); + + switch (cport_id) { + case ES2_CPORT_CDSI1: + es2->cdsi1_in_use = false; + return; + } + + ida_simple_remove(&hd->cport_id_map, cport_id); +} + static int cport_enable(struct gb_host_device *hd, u16 cport_id) { int retval; @@ -621,6 +678,8 @@ static struct gb_hd_driver es2_driver = { .hd_priv_size = sizeof(struct es2_ap_dev), .message_send = message_send, .message_cancel = message_cancel, + .cport_allocate = es2_cport_allocate, + .cport_release = es2_cport_release, .cport_enable = cport_enable, .latency_tag_enable = latency_tag_enable, .latency_tag_disable = latency_tag_disable, -- 2.39.2