greybus: es2.c: add a control request for endpoints mapping

ES2 give us more endpoints. Use them to map one cport to two endpoints
(in and out). Because there is more cports than endpoints, we still
need to mux other cports traffic on 2 endpoints.
Firmware currently assumes these endpoints are 2 and 3.

By default, all cports are muxed.
To map one cport to 2 endpoints, use map_cport_to_ep().

Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Alexandre Bailon 2015-06-15 18:08:14 +02:00 коммит произвёл Greg Kroah-Hartman
Родитель 606addd284
Коммит fc1a536e60
1 изменённых файлов: 77 добавлений и 1 удалений

Просмотреть файл

@ -34,6 +34,9 @@ static struct dentry *apb1_log_enable_dentry;
static struct task_struct *apb1_log_task;
static DEFINE_KFIFO(apb1_log_fifo, char, APB1_LOG_SIZE);
/* Number of cport present on USB bridge */
#define CPORT_MAX 44
/* Number of bulk in and bulk out couple */
#define NUM_BULKS 7
@ -55,6 +58,9 @@ static DEFINE_KFIFO(apb1_log_fifo, char, APB1_LOG_SIZE);
/* vendor request APB1 log */
#define REQUEST_LOG 0x02
/* vendor request to map a cport to bulk in and bulk out endpoints */
#define REQUEST_EP_MAPPING 0x03
/*
* @endpoint: bulk in endpoint for CPort data
* @urb: array of urbs for the CPort in messages
@ -106,6 +112,14 @@ struct es1_ap_dev {
struct urb *cport_out_urb[NUM_CPORT_OUT_URB];
bool cport_out_urb_busy[NUM_CPORT_OUT_URB];
spinlock_t cport_out_urb_lock;
int cport_to_ep[CPORT_MAX];
};
struct cport_to_ep {
__le16 cport_id;
__u8 endpoint_in;
__u8 endpoint_out;
};
static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
@ -117,6 +131,13 @@ static void cport_out_callback(struct urb *urb);
static void usb_log_enable(struct es1_ap_dev *es1);
static void usb_log_disable(struct es1_ap_dev *es1);
static int cport_to_ep(struct es1_ap_dev *es1, u16 cport_id)
{
if (cport_id >= CPORT_MAX)
return 0;
return es1->cport_to_ep[cport_id];
}
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
{
@ -139,6 +160,60 @@ static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
return 0;
}
static int ep_in_use(struct es1_ap_dev *es1, int bulk_ep_set)
{
int i;
for (i = 0; i < CPORT_MAX; i++) {
if (es1->cport_to_ep[i] == bulk_ep_set)
return 1;
}
return 0;
}
int map_cport_to_ep(struct es1_ap_dev *es1,
u16 cport_id, int bulk_ep_set)
{
int retval;
struct cport_to_ep *cport_to_ep;
if (bulk_ep_set == 0 || bulk_ep_set >= NUM_BULKS)
return -EINVAL;
if (cport_id >= CPORT_MAX)
return -EINVAL;
if (bulk_ep_set && ep_in_use(es1, bulk_ep_set))
return -EINVAL;
cport_to_ep = kmalloc(sizeof(*cport_to_ep), GFP_KERNEL);
if (!cport_to_ep)
return -ENOMEM;
es1->cport_to_ep[cport_id] = bulk_ep_set;
cport_to_ep->cport_id = cpu_to_le16(cport_id);
cport_to_ep->endpoint_in = es1->cport_in[bulk_ep_set].endpoint;
cport_to_ep->endpoint_out = es1->cport_out[bulk_ep_set].endpoint;
retval = usb_control_msg(es1->usb_dev,
usb_sndctrlpipe(es1->usb_dev,
es1->control_endpoint),
REQUEST_EP_MAPPING,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x00, 0x00,
(char *)cport_to_ep,
sizeof(*cport_to_ep),
ES1_TIMEOUT);
if (retval == sizeof(*cport_to_ep))
retval = 0;
kfree(cport_to_ep);
return retval;
}
int unmap_cport(struct es1_ap_dev *es1, u16 cport_id)
{
return map_cport_to_ep(es1, cport_id, 0);
}
static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
{
struct urb *urb = NULL;
@ -204,7 +279,7 @@ static void *message_send(struct greybus_host_device *hd, u16 cport_id,
size_t buffer_size;
int retval;
struct urb *urb;
int bulk_ep_set = 0;
int bulk_ep_set;
buffer = message->buffer;
buffer_size = sizeof(*message->header) + message->payload_size;
@ -230,6 +305,7 @@ static void *message_send(struct greybus_host_device *hd, u16 cport_id,
*/
put_unaligned_le16(cport_id, message->header->pad);
bulk_ep_set = cport_to_ep(es1, cport_id);
usb_fill_bulk_urb(urb, udev,
usb_sndbulkpipe(udev,
es1->cport_out[bulk_ep_set].endpoint),