#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 
-#include "es2.h"
 #include "greybus.h"
 #include "greybus_protocols.h"
 
  * Camera Protocol Operations
  */
 
+/* vendor request to control the CSI transmitter */
+#define REQUEST_CSI_TX_CONTROL 0x08
+
+struct ap_csi_config_request {
+       __u8 csi_id;
+       __u8 clock_mode;
+       __u8 num_lanes;
+       __u8 padding;
+       __le32 bus_freq;
+} __packed;
+
 static int gb_camera_configure_streams(struct gb_camera *gcam,
                                       unsigned int nstreams,
                                       unsigned int flags,
 {
        struct gb_camera_configure_streams_request *req;
        struct gb_camera_configure_streams_response *resp;
-       struct es2_ap_csi_config csi_cfg;
+       struct ap_csi_config_request csi_cfg;
        unsigned int i;
        size_t req_size;
        size_t resp_size;
                }
        }
 
+       memset(&csi_cfg, 0, sizeof(csi_cfg));
+
        /* Configure the CSI transmitter. Hardcode the parameters for now. */
        if (nstreams && !(resp->flags & GB_CAMERA_CONFIGURE_STREAMS_ADJUSTED)) {
                csi_cfg.csi_id = 1;
                csi_cfg.clock_mode = 0;
                csi_cfg.num_lanes = 4;
-               csi_cfg.bus_freq = 960000000;
-
-               ret = es2_ap_csi_setup(gcam->connection->hd, true, &csi_cfg);
+               csi_cfg.bus_freq = cpu_to_le32(960000000);
+               ret = gb_hd_output(gcam->connection->hd, &csi_cfg,
+                                  sizeof(csi_cfg), REQUEST_CSI_TX_CONTROL,
+                                  false);
        } else if (nstreams == 0) {
                csi_cfg.csi_id = 1;
-               csi_cfg.clock_mode = 0;
-               csi_cfg.num_lanes = 0;
-               csi_cfg.bus_freq = 0;
-
-               ret = es2_ap_csi_setup(gcam->connection->hd, false, &csi_cfg);
+               ret = gb_hd_output(gcam->connection->hd, &csi_cfg,
+                                  sizeof(csi_cfg), REQUEST_CSI_TX_CONTROL,
+                                  false);
        }
 
        if (ret < 0)
 
 #include <linux/debugfs.h>
 #include <asm/unaligned.h>
 
-#include "es2.h"
 #include "greybus.h"
 #include "kernel_ver.h"
 #include "connection.h"
        __u8 endpoint_out;
 };
 
-struct es2_ap_csi_config_request {
-       __u8 csi_id;
-       __u8 clock_mode;
-       __u8 num_lanes;
-       __u8 padding;
-       __le32 bus_freq;
-} __packed;
-
 static inline struct es2_ap_dev *hd_to_es2(struct gb_host_device *hd)
 {
        return (struct es2_ap_dev *)&hd->hd_priv;
 }
 #endif
 
-int es2_ap_csi_setup(struct gb_host_device *hd, bool start,
-                    struct es2_ap_csi_config *cfg)
+static int output_sync(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
 {
-       struct es2_ap_csi_config_request *cfg_req;
-       struct es2_ap_dev *es2 = hd_to_es2(hd);
        struct usb_device *udev = es2->usb_dev;
+       u8 *data;
        int retval;
 
-       cfg_req = kzalloc(sizeof(*cfg_req), GFP_KERNEL);
-       if (!cfg_req)
+       data = kmalloc(size, GFP_KERNEL);
+       if (!data)
                return -ENOMEM;
-
-       cfg_req->csi_id = cfg->csi_id;
-
-       if (start) {
-               cfg_req->clock_mode = cfg->clock_mode;
-               cfg_req->num_lanes = cfg->num_lanes;
-               cfg_req->bus_freq = cpu_to_le32(cfg->bus_freq);
-       }
+       memcpy(data, req, size);
 
        retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                                REQUEST_CSI_TX_CONTROL,
+                                cmd,
                                 USB_DIR_OUT | USB_TYPE_VENDOR |
-                                USB_RECIP_INTERFACE, 0, 0, cfg_req,
-                                sizeof(*cfg_req), ES2_TIMEOUT);
+                                USB_RECIP_INTERFACE,
+                                0, 0, data, size, ES2_TIMEOUT);
        if (retval < 0)
-               dev_err(&udev->dev, "failed to setup csi: %d\n", retval);
+               dev_err(&udev->dev, "%s: return error %d\n", __func__, retval);
+       else
+               retval = 0;
 
-       kfree(cfg_req);
+       kfree(data);
        return retval;
 }
-EXPORT_SYMBOL_GPL(es2_ap_csi_setup);
+
+static void ap_urb_complete(struct urb *urb)
+{
+       struct usb_ctrlrequest *dr = urb->context;
+
+       kfree(dr);
+       usb_free_urb(urb);
+}
+
+static int output_async(struct es2_ap_dev *es2, void *req, u16 size, u8 cmd)
+{
+       struct usb_device *udev = es2->usb_dev;
+       struct urb *urb;
+       struct usb_ctrlrequest *dr;
+       u8 *buf;
+       int retval;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
+
+       dr = kmalloc(sizeof(*dr) + size, GFP_ATOMIC);
+       if (!dr) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       buf = (u8 *)dr + sizeof(*dr);
+       memcpy(buf, req, size);
+
+       dr->bRequest = cmd;
+       dr->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
+       dr->wValue = 0;
+       dr->wIndex = 0;
+       dr->wLength = cpu_to_le16(size);
+
+       usb_fill_control_urb(urb, udev, usb_sndctrlpipe(udev, 0),
+                            (unsigned char *)dr, buf, size,
+                            ap_urb_complete, dr);
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval) {
+               usb_free_urb(urb);
+               kfree(dr);
+       }
+       return retval;
+}
+
+static int output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
+                    bool async)
+{
+       struct es2_ap_dev *es2 = hd_to_es2(hd);
+
+       if (async)
+               return output_async(es2, req, size, cmd);
+
+       return output_sync(es2, req, size, cmd);
+}
 
 static int es2_cport_in_enable(struct es2_ap_dev *es2,
                                struct es2_cport_in *cport_in)
        .cport_enable           = cport_enable,
        .latency_tag_enable     = latency_tag_enable,
        .latency_tag_disable    = latency_tag_disable,
+       .output                 = output,
 };
 
 /* Common function to report consistent warnings based on URB status */