#include <linux/kfifo.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
+#include <asm/unaligned.h>
#include "greybus.h"
#include "svc_msg.h"
*/
static void hd_buffer_constraints(struct greybus_host_device *hd)
{
- /*
- * Only one byte is required, but this produces a result
- * that's better aligned for the user.
- */
- hd->buffer_headroom = sizeof(u32); /* For cport id */
- hd->buffer_size_max = ES1_GBUF_MSG_SIZE_MAX - hd->buffer_headroom;
- BUILD_BUG_ON(hd->buffer_headroom > GB_BUFFER_HEADROOM_MAX);
+ hd->buffer_headroom = 0;
+ hd->buffer_size_max = ES1_GBUF_MSG_SIZE_MAX;
}
#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
{
struct es1_ap_dev *es1 = hd_to_es1(hd);
struct usb_device *udev = es1->usb_dev;
- u8 *transfer_buffer;
+ void *buffer;
size_t buffer_size;
- int transfer_buffer_size;
int retval;
struct urb *urb;
- buffer_size = hd->buffer_headroom + sizeof(*message->header) +
- message->payload_size;
- transfer_buffer = message->buffer + hd->buffer_headroom - 1;
- transfer_buffer_size = buffer_size - (hd->buffer_headroom - 1);
+ buffer = message->buffer;
+ buffer_size = sizeof(*message->header) + message->payload_size;
/*
* The data actually transferred will include an indication
pr_err("request to send inbound data buffer\n");
return ERR_PTR(-EINVAL);
}
- if (cport_id > U8_MAX) {
- pr_err("cport_id (%hd) is out of range for ES1\n", cport_id);
- return ERR_PTR(-EINVAL);
- }
- /* OK, the destination is fine; record it in the transfer buffer */
- *transfer_buffer = cport_id;
/* Find a free urb */
urb = next_free_urb(es1, gfp_mask);
if (!urb)
return ERR_PTR(-ENOMEM);
+ /*
+ * We (ab)use the operation-message header pad bytes to transfer the
+ * cport id in order to minimise overhead.
+ */
+ put_unaligned_le16(cport_id, message->header->pad);
+
usb_fill_bulk_urb(urb, udev,
usb_sndbulkpipe(udev, es1->cport_out_endpoint),
- transfer_buffer, transfer_buffer_size,
+ buffer, buffer_size,
cport_out_callback, message);
retval = usb_submit_urb(urb, gfp_mask);
if (retval) {
pr_err("error %d submitting URB\n", retval);
free_urb(es1, urb);
+ put_unaligned_le16(0, message->header->pad);
return ERR_PTR(retval);
}
{
struct greybus_host_device *hd = urb->context;
struct device *dev = &urb->dev->dev;
+ struct gb_operation_msg_hdr *header;
int status = check_urb_status(urb);
int retval;
u16 cport_id;
- u8 *data;
if (status) {
if ((status == -EAGAIN) || (status == -EPROTO))
return;
}
- /* The size has to be at least one, for the cport id */
- if (!urb->actual_length) {
- dev_err(dev, "%s: no cport id in input buffer?\n", __func__);
+ if (urb->actual_length < sizeof(*header)) {
+ dev_err(dev, "%s: short message received\n", __func__);
goto exit;
}
- /*
- * Our CPort number is the first byte of the data stream,
- * the rest of the stream is "real" data
- */
- data = urb->transfer_buffer;
- cport_id = data[0];
- data = &data[1];
-
- /* Pass this data to the greybus core */
- greybus_data_rcvd(hd, cport_id, data, urb->actual_length - 1);
+ header = urb->transfer_buffer;
+ cport_id = get_unaligned_le16(header->pad);
+ put_unaligned_le16(0, header->pad);
+ greybus_data_rcvd(hd, cport_id, urb->transfer_buffer,
+ urb->actual_length);
exit:
/* put our urb back in the request pool */
retval = usb_submit_urb(urb, GFP_ATOMIC);
struct es1_ap_dev *es1 = hd_to_es1(hd);
int status = check_urb_status(urb);
+ /* Clear the pad bytes used for the cport id */
+ put_unaligned_le16(0, message->header->pad);
+
/*
* Tell the submitter that the message send (attempt) is
* complete, and report the status.