struct usb_interface *usb_intf;
struct greybus_host_device *hd;
- __u8 ap_comm_endpoint; /* endpoint to talk to the AP */
- __u8 ap_in_endpoint; /* bulk in for CPort data */
- __u8 ap_out_endpoint; /* bulk out for CPort data */
- u8 *ap_buffer;
-
+ __u8 control_endpoint; /* endpoint to send data to SVC */
+ __u8 svc_endpoint; /* endpoint for SVC data */
+ __u8 cport_in_endpoint; /* bulk in for CPort data */
+ __u8 cport_out_endpoint; /* bulk out for CPort data */
+ u8 *svc_buffer; /* buffer for SVC messages coming in */
+ struct urb *svc_urb; /* urb for SVC messages coming in */
};
static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
.ap_msg = ap_msg,
};
-
-void ap_in_callback(struct urb *urb)
+/* Callback for when we get a SVC message */
+static void svc_callback(struct urb *urb)
{
struct es1_ap_dev *es1 = urb->context;
struct device *dev = &urb->dev->dev;
dev_err(dev, "Can not submit urb for AP data: %d\n", retval);
}
-void ap_out_callback(struct urb *urb)
+void cport_in_callback(struct urb *urb)
{
struct device *dev = &urb->dev->dev;
int status = urb->status;
goto exit;
}
- // FIXME - queue up next AP message to send???
+ // FIXME - handle the CPort in data
exit:
return;
}
+void cport_out_callback(struct urb *urb)
+{
+ struct device *dev = &urb->dev->dev;
+ int status = urb->status;
+
+ switch (status) {
+ case 0:
+ break;
+ case -EOVERFLOW:
+ dev_err(dev, "%s: overflow actual length is %d\n",
+ __func__, urb->actual_length);
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EILSEQ:
+ /* device is gone, stop sending */
+ return;
+ default:
+ dev_err(dev, "%s: unknown status %d\n", __func__, status);
+ goto exit;
+ }
+ // FIXME - handle the CPort out data callback
+exit:
+ return;
+}
+
+/*
+ * The ES1 USB Bridge device contains 4 endpoints
+ * 1 Control - usual USB stuff + AP -> SVC messages
+ * 1 Interrupt IN - SVC -> AP messages
+ * 1 Bulk IN - CPort data in
+ * 1 Bulk OUT - CPorta data out
+ */
static int ap_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *udev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
+ bool int_in_found = false;
+ bool bulk_in_found = false;
+ bool bulk_out_found = false;
+ int retval = -ENOMEM;
int i;
+ int buffer_size = 0;
+ u8 svc_interval = 0;
udev = usb_get_dev(interface_to_usbdev(interface));
es1 = hd_to_es1(hd);
es1->hd = hd;
+ es1->usb_intf = interface;
+ es1->usb_dev = udev;
+ usb_set_intfdata(interface, es1);
/* Control endpoint is the pipe to talk to this AP, so save it off */
endpoint = &udev->ep0.desc;
- es1->ap_comm_endpoint = endpoint->bEndpointAddress;
+ es1->control_endpoint = endpoint->bEndpointAddress;
- // FIXME
- // figure out endpoint for talking to the AP.
+ /* find all 3 of our endpoints */
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- es1->ap_in_endpoint = endpoint->bEndpointAddress;
+ if (usb_endpoint_is_int_in(endpoint)) {
+ es1->svc_endpoint = endpoint->bEndpointAddress;
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ svc_interval = endpoint->bInterval;
+ int_in_found = true;
+ } else if (usb_endpoint_is_bulk_in(endpoint)) {
+ es1->cport_in_endpoint = endpoint->bEndpointAddress;
+ bulk_in_found = true;
+ } else if (usb_endpoint_is_bulk_out(endpoint)) {
+ es1->cport_out_endpoint = endpoint->bEndpointAddress;
+ bulk_out_found = true;
+ } else {
+ dev_err(&udev->dev,
+ "Unknown endpoint type found, address %x\n",
+ endpoint->bEndpointAddress);
}
- if (usb_endpoint_is_bulk_out(endpoint)) {
- es1->ap_out_endpoint = endpoint->bEndpointAddress;
- }
- // FIXME - properly exit once found the AP endpoint
- // FIXME - set up cport endpoints
+ }
+ if ((int_in_found == false) ||
+ (bulk_in_found == false) ||
+ (bulk_out_found == false)) {
+ dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
+ goto error;
}
- // FIXME - allocate buffer
- // FIXME = start up talking, then create the gb "devices" based on what the AP tells us.
+ /* Create our buffer and URB to get SVC messages, and start it up */
+ es1->svc_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!es1->svc_buffer)
+ goto error;
+
+ es1->svc_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!es1->svc_urb)
+ goto error_urb;
+
+ usb_fill_int_urb(es1->svc_urb, udev,
+ usb_rcvintpipe(udev, es1->svc_endpoint),
+ es1->svc_buffer, buffer_size, svc_callback,
+ es1, svc_interval);
+ retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL);
+ if (retval)
+ goto error_submit_urb;
- es1->usb_intf = interface;
- es1->usb_dev = udev;
- usb_set_intfdata(interface, es1);
return 0;
+
+error_submit_urb:
+ usb_free_urb(es1->svc_urb);
+error_urb:
+ kfree(es1->svc_buffer);
+error:
+ greybus_remove_hd(es1->hd);
+ return retval;
}
static void ap_disconnect(struct usb_interface *interface)
es1 = usb_get_intfdata(interface);
/* Tear down everything! */
-
+ usb_kill_urb(es1->svc_urb);
usb_put_dev(es1->usb_dev);
- kfree(es1->ap_buffer);
-
+ kfree(es1->svc_buffer);
greybus_remove_hd(es1->hd);
+ usb_set_intfdata(interface, NULL);
}
static struct usb_driver es1_ap_driver = {