]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
greybus: es2.c: add a control request for endpoints mapping
authorAlexandre Bailon <abailon@baylibre.com>
Mon, 15 Jun 2015 16:08:14 +0000 (18:08 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 15 Jun 2015 23:51:44 +0000 (16:51 -0700)
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>
drivers/staging/greybus/es2.c

index a1cf1ac2f0aaf1b73562846c3685580f846dfca5..4e99044c1fbe1e9a54bf6027c0c5864520938539 100644 (file)
@@ -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),