From 47f6ef12fe6dfc4107597af4a44b045324c53c02 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 8 Sep 2014 20:09:08 -0700 Subject: [PATCH] greybus: es1: finialized USB device structure Set up device properly and start up the SVC interrupt in endpoint for processing data --- drivers/staging/greybus/es1-ap-usb.c | 129 +++++++++++++++++++++------ 1 file changed, 102 insertions(+), 27 deletions(-) diff --git a/drivers/staging/greybus/es1-ap-usb.c b/drivers/staging/greybus/es1-ap-usb.c index 12a5d0cf76ba..da3523488165 100644 --- a/drivers/staging/greybus/es1-ap-usb.c +++ b/drivers/staging/greybus/es1-ap-usb.c @@ -24,11 +24,12 @@ struct es1_ap_dev { 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) @@ -245,8 +246,8 @@ static struct greybus_host_driver es1_driver = { .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; @@ -282,7 +283,7 @@ exit: 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; @@ -304,12 +305,45 @@ void ap_out_callback(struct urb *urb) 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) { @@ -318,7 +352,13 @@ static int ap_probe(struct usb_interface *interface, 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)); @@ -328,34 +368,69 @@ static int ap_probe(struct usb_interface *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) @@ -365,11 +440,11 @@ 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 = { -- 2.39.5