/* Memory sizes for the buffers sent to/from the ES2 controller */
#define ES2_GBUF_MSG_SIZE_MAX 2048
+/* Memory sizes for the ARPC buffers */
+#define ARPC_IN_SIZE_MAX 128
+
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x18d1, 0x1eaf) },
{ },
/* Number of bulk in and bulk out couple */
#define NUM_BULKS 7
+/* Expected number of bulk out endpoints */
+#define NUM_BULKS_OUT NUM_BULKS
+
+/* Expected number of bulk in endpoints (including ARPC endpoint) */
+#define NUM_BULKS_IN (NUM_BULKS + 1)
+
/*
* Number of CPort IN urbs in flight at any point in time.
* Adjust if we are having stalls in the USB buffer due to not enough urbs in
*/
#define NUM_CPORT_OUT_URB (8 * NUM_BULKS)
+/*
+ * Number of ARPC in urbs in flight at any point in time.
+ */
+#define NUM_ARPC_IN_URB 2
+
/*
* @endpoint: bulk in endpoint for CPort data
* @urb: array of urbs for the CPort in messages
* @apb_log_dentry: file system entry for the log file interface
* @apb_log_enable_dentry: file system entry for enabling logging
* @apb_log_fifo: kernel FIFO to carry logged data
+ * @arpc_urb: array of urbs for the ARPC in messages
+ * @arpc_buffer: array of buffers for the @arpc_urb urbs
+ * @arpc_endpoint_in: bulk in endpoint for APBridgeA RPC
*/
struct es2_ap_dev {
struct usb_device *usb_dev;
struct dentry *apb_log_dentry;
struct dentry *apb_log_enable_dentry;
DECLARE_KFIFO(apb_log_fifo, char, APB1_LOG_SIZE);
+
+ __u8 arpc_endpoint_in;
+ struct urb *arpc_urb[NUM_ARPC_IN_URB];
+ u8 *arpc_buffer[NUM_ARPC_IN_URB];
};
/**
}
}
+static int es2_arpc_in_enable(struct es2_ap_dev *es2)
+{
+ struct urb *urb;
+ int ret;
+ int i;
+
+ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
+ urb = es2->arpc_urb[i];
+
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ dev_err(&es2->usb_dev->dev,
+ "failed to submit arpc in-urb: %d\n", ret);
+ goto err_kill_urbs;
+ }
+ }
+
+ return 0;
+
+err_kill_urbs:
+ for (--i; i >= 0; --i) {
+ urb = es2->arpc_urb[i];
+ usb_kill_urb(urb);
+ }
+
+ return ret;
+}
+
+static void es2_arpc_in_disable(struct es2_ap_dev *es2)
+{
+ struct urb *urb;
+ int i;
+
+ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
+ urb = es2->arpc_urb[i];
+ usb_kill_urb(urb);
+ }
+}
+
static struct urb *next_free_urb(struct es2_ap_dev *es2, gfp_t gfp_mask)
{
struct urb *urb = NULL;
es2->cport_out_urb_busy[i] = false; /* just to be anal */
}
+ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
+ struct urb *urb = es2->arpc_urb[i];
+
+ if (!urb)
+ break;
+ usb_free_urb(urb);
+ kfree(es2->arpc_buffer[i]);
+ es2->arpc_buffer[i] = NULL;
+ }
+
for (bulk_in = 0; bulk_in < NUM_BULKS; bulk_in++) {
struct es2_cport_in *cport_in = &es2->cport_in[bulk_in];
free_urb(es2, urb);
}
+static void arpc_in_callback(struct urb *urb)
+{
+ struct device *dev = &urb->dev->dev;
+ int status = check_urb_status(urb);
+ int retval;
+
+ if (status) {
+ if ((status == -EAGAIN) || (status == -EPROTO))
+ goto exit;
+
+ /* The urb is being unlinked */
+ if (status == -ENOENT || status == -ESHUTDOWN)
+ return;
+
+ dev_err(dev, "arpc in-urb error %d (dropped)\n", status);
+ return;
+ }
+
+exit:
+ /* put our urb back in the request pool */
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(dev, "failed to resubmit arpc in-urb: %d\n", retval);
+}
+
#define APB1_LOG_MSG_SIZE 64
static void apb_log_get(struct es2_ap_dev *es2, char *buf)
{
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(endpoint)) {
- es2->cport_in[bulk_in++].endpoint =
- endpoint->bEndpointAddress;
+ if (bulk_in < NUM_BULKS)
+ es2->cport_in[bulk_in].endpoint =
+ endpoint->bEndpointAddress;
+ else
+ es2->arpc_endpoint_in =
+ endpoint->bEndpointAddress;
+ bulk_in++;
} else if (usb_endpoint_is_bulk_out(endpoint)) {
es2->cport_out[bulk_out++].endpoint =
endpoint->bEndpointAddress;
endpoint->bEndpointAddress);
}
}
- if (bulk_in != NUM_BULKS || bulk_out != NUM_BULKS) {
+ if (bulk_in != NUM_BULKS_IN || bulk_out != NUM_BULKS_OUT) {
dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
retval = -ENODEV;
goto error;
}
}
+ /* Allocate buffers for ARPC in messages */
+ for (i = 0; i < NUM_ARPC_IN_URB; ++i) {
+ struct urb *urb;
+ u8 *buffer;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ buffer = kmalloc(ARPC_IN_SIZE_MAX, GFP_KERNEL);
+ if (!buffer) {
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ usb_fill_bulk_urb(urb, udev,
+ usb_rcvbulkpipe(udev,
+ es2->arpc_endpoint_in),
+ buffer, ARPC_IN_SIZE_MAX,
+ arpc_in_callback, es2);
+
+ es2->arpc_urb[i] = urb;
+ es2->arpc_buffer[i] = buffer;
+ }
+
/* Allocate urbs for our CPort OUT messages */
for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
struct urb *urb;
gb_debugfs_get(), es2,
&apb_log_enable_fops);
+ if (es2_arpc_in_enable(es2))
+ goto error;
+
retval = gb_hd_add(hd);
if (retval)
- goto error;
+ goto err_disable_arpc_in;
for (i = 0; i < NUM_BULKS; ++i) {
retval = es2_cport_in_enable(es2, &es2->cport_in[i]);
for (--i; i >= 0; --i)
es2_cport_in_disable(es2, &es2->cport_in[i]);
gb_hd_del(hd);
+err_disable_arpc_in:
+ es2_arpc_in_disable(es2);
error:
es2_destroy(es2);
for (i = 0; i < NUM_BULKS; ++i)
es2_cport_in_disable(es2, &es2->cport_in[i]);
+ es2_arpc_in_disable(es2);
es2_destroy(es2);
}