Commit 47f6ef12 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

greybus: es1: finialized USB device structure

Set up device properly and start up the SVC interrupt in endpoint for
processing data
parent 8b995148
Loading
Loading
Loading
Loading
+102 −27
Original line number Diff line number Diff line
@@ -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 @@ void ap_in_callback(struct urb *urb)
		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 = {