blob: a92f8934928a078bad1f343cff64d92e2190b260 [file] [log] [blame]
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -07001/*
2 * Greybus "AP" USB driver
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * Released under the GPLv2 only.
7 */
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/slab.h>
11#include <linux/errno.h>
Matt Porterf0f70912014-09-30 16:01:40 -040012#include <linux/sizes.h>
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -070013#include <linux/usb.h>
Alex Elder1cfc6672014-09-30 19:25:21 -050014
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -070015#include "greybus.h"
Greg Kroah-Hartman43cc32a2014-09-07 13:51:12 -070016#include "svc_msg.h"
Alex Elder1cfc6672014-09-30 19:25:21 -050017#include "kernel_ver.h"
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -070018
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -070019/* Memory sizes for the buffers sent to/from the ES1 controller */
Matt Porterf0f70912014-09-30 16:01:40 -040020#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -070021#define ES1_GBUF_MSG_SIZE PAGE_SIZE
22
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -070023static const struct usb_device_id id_table[] = {
Greg Kroah-Hartman7f9e05e2014-09-13 17:28:33 -070024 /* Made up numbers for the SVC USB Bridge in ES1 */
25 { USB_DEVICE(0xffff, 0x0001) },
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -070026 { },
27};
28MODULE_DEVICE_TABLE(usb, id_table);
29
Greg Kroah-Hartman11299732014-09-12 21:17:37 -070030/*
31 * Number of CPort IN urbs in flight at any point in time.
32 * Adjust if we are having stalls in the USB buffer due to not enough urbs in
33 * flight.
34 */
35#define NUM_CPORT_IN_URB 4
36
37/* Number of CPort OUT urbs in flight at any point in time.
38 * Adjust if we get messages saying we are out of urbs in the system log.
39 */
40#define NUM_CPORT_OUT_URB 8
41
Greg Kroah-Hartman7f9e05e2014-09-13 17:28:33 -070042/**
43 * es1_ap_dev - ES1 USB Bridge to AP structure
44 * @usb_dev: pointer to the USB device we are.
45 * @usb_intf: pointer to the USB interface we are bound to.
46 * @hd: pointer to our greybus_host_device structure
47 * @control_endpoint: endpoint to send data to SVC
48 * @svc_endpoint: endpoint for SVC data in
49 * @cport_in_endpoint: bulk in endpoint for CPort data
50 * @cport-out_endpoint: bulk out endpoint for CPort data
51 * @svc_buffer: buffer for SVC messages coming in on @svc_endpoint
52 * @svc_urb: urb for SVC messages coming in on @svc_endpoint
53 * @cport_in_urb: array of urbs for the CPort in messages
54 * @cport_in_buffer: array of buffers for the @cport_in_urb urbs
55 * @cport_out_urb: array of urbs for the CPort out messages
56 * @cport_out_urb_busy: array of flags to see if the @cport_out_urb is busy or
57 * not.
58 * @cport_out_urb_lock: locks the @cport_out_urb_busy "list"
59 */
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -070060struct es1_ap_dev {
61 struct usb_device *usb_dev;
62 struct usb_interface *usb_intf;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070063 struct greybus_host_device *hd;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -070064
Greg Kroah-Hartman7f9e05e2014-09-13 17:28:33 -070065 __u8 control_endpoint;
66 __u8 svc_endpoint;
67 __u8 cport_in_endpoint;
68 __u8 cport_out_endpoint;
69
70 u8 *svc_buffer;
71 struct urb *svc_urb;
72
73 struct urb *cport_in_urb[NUM_CPORT_IN_URB];
74 u8 *cport_in_buffer[NUM_CPORT_IN_URB];
75 struct urb *cport_out_urb[NUM_CPORT_OUT_URB];
76 bool cport_out_urb_busy[NUM_CPORT_OUT_URB];
77 spinlock_t cport_out_urb_lock;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -070078};
79
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070080static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
81{
Alex Elder69f93ab2014-09-22 18:53:02 -050082 return (struct es1_ap_dev *)&hd->hd_priv;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070083}
84
Greg Kroah-Hartman11299732014-09-12 21:17:37 -070085static void cport_out_callback(struct urb *urb);
86
Greg Kroah-Hartmanf1eec302014-08-30 17:18:14 -070087/*
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070088 * Allocate the actual buffer for this gbuf and device and cport
89 *
90 * We are responsible for setting the following fields in a struct gbuf:
91 * void *hcpriv;
92 * void *transfer_buffer;
93 * u32 transfer_buffer_length;
Greg Kroah-Hartmanf1eec302014-08-30 17:18:14 -070094 */
Alex Elder9a6f6312014-10-06 06:53:11 -050095static int alloc_gbuf_data(struct gbuf *gbuf, unsigned int size,
96 gfp_t gfp_mask)
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070097{
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -070098 u8 *buffer;
99
Alex Elderf7935e32014-11-17 18:08:34 -0600100 if (gbuf->transfer_buffer)
101 return -EALREADY;
102
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -0700103 if (size > ES1_GBUF_MSG_SIZE) {
Greg Kroah-Hartmanf036e052014-09-19 19:13:33 -0700104 pr_err("guf was asked to be bigger than %ld!\n",
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -0700105 ES1_GBUF_MSG_SIZE);
106 }
107
Alex Elder5259ef12014-11-18 13:26:39 -0600108 /*
109 * For ES1 we need to insert a byte at the front of the data
Alex Elder06a4a062014-11-18 13:26:40 -0600110 * to indicate the destination CPort id. We only need one
111 * extra byte, but we allocate four extra bytes to allow the
112 * buffer returned to be aligned on a four-byte boundary.
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700113 *
Alex Elder5259ef12014-11-18 13:26:39 -0600114 * This is only needed for outbound data, but we handle
115 * buffers for inbound data the same way for consistency.
Alex Elder9a6f6312014-10-06 06:53:11 -0500116 *
Alex Elder5259ef12014-11-18 13:26:39 -0600117 * XXX Do we need to indicate the destination device id too?
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700118 */
Alex Elder06a4a062014-11-18 13:26:40 -0600119 buffer = kzalloc(GB_BUFFER_ALIGN + size, gfp_mask);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700120 if (!buffer)
121 return -ENOMEM;
Alex Elder06a4a062014-11-18 13:26:40 -0600122 buffer += GB_BUFFER_ALIGN;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700123
Alex Elder9a6f6312014-10-06 06:53:11 -0500124 gbuf->transfer_buffer = buffer;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700125 gbuf->transfer_buffer_length = size;
126
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700127 return 0;
128}
129
130/* Free the memory we allocated with a gbuf */
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700131static void free_gbuf_data(struct gbuf *gbuf)
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700132{
Alex Elder9a6f6312014-10-06 06:53:11 -0500133 u8 *transfer_buffer = gbuf->transfer_buffer;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700134
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700135 /* Can be called with a NULL transfer_buffer on some error paths */
Alex Elder9a6f6312014-10-06 06:53:11 -0500136 if (!transfer_buffer)
137 return;
138
Alex Elder06a4a062014-11-18 13:26:40 -0600139 /* Account for the space set aside for the prepended cport id */
140 transfer_buffer -= GB_BUFFER_ALIGN;
Alex Elder9a6f6312014-10-06 06:53:11 -0500141 kfree(transfer_buffer);
Alex Elderf7935e32014-11-17 18:08:34 -0600142 gbuf->transfer_buffer = NULL;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700143}
144
Greg Kroah-Hartman8c53e072014-09-12 20:47:11 -0700145#define ES1_TIMEOUT 500 /* 500 ms for the SVC to do something */
Alex Elder0db32a62014-09-24 05:16:14 -0500146static int submit_svc(struct svc_msg *svc_msg, struct greybus_host_device *hd)
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700147{
148 struct es1_ap_dev *es1 = hd_to_es1(hd);
Greg Kroah-Hartman8c53e072014-09-12 20:47:11 -0700149 int retval;
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700150
Greg Kroah-Hartman8c53e072014-09-12 20:47:11 -0700151 /* SVC messages go down our control pipe */
152 retval = usb_control_msg(es1->usb_dev,
153 usb_sndctrlpipe(es1->usb_dev,
154 es1->control_endpoint),
155 0x01, /* vendor request AP message */
Matt Porter648cb6c2014-09-22 15:51:48 -0400156 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
Greg Kroah-Hartman8c53e072014-09-12 20:47:11 -0700157 0x00, 0x00,
158 (char *)svc_msg,
159 sizeof(*svc_msg),
160 ES1_TIMEOUT);
161 if (retval != sizeof(*svc_msg))
162 return retval;
163
164 return 0;
Greg Kroah-Hartman68f1fc42014-09-07 13:12:11 -0700165}
166
Greg Kroah-Hartman0dad95d2014-09-13 09:54:35 -0700167static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700168{
Greg Kroah-Hartman0dad95d2014-09-13 09:54:35 -0700169 struct urb *urb = NULL;
170 unsigned long flags;
171 int i;
172
173 spin_lock_irqsave(&es1->cport_out_urb_lock, flags);
174
175 /* Look in our pool of allocated urbs first, as that's the "fastest" */
176 for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
177 if (es1->cport_out_urb_busy[i] == false) {
178 es1->cport_out_urb_busy[i] = true;
179 urb = es1->cport_out_urb[i];
180 break;
181 }
182 }
183 spin_unlock_irqrestore(&es1->cport_out_urb_lock, flags);
184 if (urb)
185 return urb;
186
187 /*
188 * Crap, pool is empty, complain to the syslog and go allocate one
189 * dynamically as we have to succeed.
190 */
191 dev_err(&es1->usb_dev->dev,
192 "No free CPort OUT urbs, having to dynamically allocate one!\n");
193 urb = usb_alloc_urb(0, gfp_mask);
194 if (!urb)
195 return NULL;
196
197 return urb;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700198}
199
Alex Elder61418b92014-10-16 06:35:29 -0500200static int submit_gbuf(struct gbuf *gbuf, gfp_t gfp_mask)
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700201{
Alex Elderba993462014-11-17 08:08:43 -0600202 struct greybus_host_device *hd = gbuf->hd;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700203 struct es1_ap_dev *es1 = hd_to_es1(hd);
204 struct usb_device *udev = es1->usb_dev;
Alex Elder0f4c8082014-11-18 13:26:41 -0600205 u16 dest_cport_id = gbuf->dest_cport_id;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700206 int retval;
207 u8 *transfer_buffer;
208 u8 *buffer;
209 struct urb *urb;
210
211 transfer_buffer = gbuf->transfer_buffer;
Alex Elderf7935e32014-11-17 18:08:34 -0600212 if (!transfer_buffer)
213 return -EINVAL;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700214 buffer = &transfer_buffer[-1]; /* yes, we mean -1 */
215
Alex Elder0f4c8082014-11-18 13:26:41 -0600216 /* Do one last check of the target CPort id before filling it in */
217 if (dest_cport_id == CPORT_ID_BAD) {
218 pr_err("request to send inbound data buffer\n");
Alex Elder5259ef12014-11-18 13:26:39 -0600219 return -EINVAL;
220 }
Alex Elder0f4c8082014-11-18 13:26:41 -0600221 if (dest_cport_id > (u16)U8_MAX) {
222 pr_err("dest_cport_id (%hd) is out of range for ES1\n",
223 dest_cport_id);
224 return -EINVAL;
225 }
226 *buffer = dest_cport_id;
Alex Elder5259ef12014-11-18 13:26:39 -0600227
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700228 /* Find a free urb */
Greg Kroah-Hartman0dad95d2014-09-13 09:54:35 -0700229 urb = next_free_urb(es1, gfp_mask);
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700230 if (!urb)
231 return -ENOMEM;
232
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800233 gbuf->hcd_data = urb;
234
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700235 usb_fill_bulk_urb(urb, udev,
236 usb_sndbulkpipe(udev, es1->cport_out_endpoint),
237 buffer, gbuf->transfer_buffer_length + 1,
238 cport_out_callback, gbuf);
239 retval = usb_submit_urb(urb, gfp_mask);
240 return retval;
241}
242
Greg Kroah-Hartman4afbba02014-10-27 14:01:06 +0800243static void kill_gbuf(struct gbuf *gbuf)
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800244{
245 struct urb *urb = gbuf->hcd_data;
246
247 if (!urb)
Greg Kroah-Hartman4afbba02014-10-27 14:01:06 +0800248 return;
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800249
250 usb_kill_urb(urb);
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800251}
252
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700253static struct greybus_host_driver es1_driver = {
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700254 .hd_priv_size = sizeof(struct es1_ap_dev),
255 .alloc_gbuf_data = alloc_gbuf_data,
256 .free_gbuf_data = free_gbuf_data,
Alex Elder0db32a62014-09-24 05:16:14 -0500257 .submit_svc = submit_svc,
Greg Kroah-Hartman3e7736e2014-09-21 17:34:28 -0700258 .submit_gbuf = submit_gbuf,
Greg Kroah-Hartman4afbba02014-10-27 14:01:06 +0800259 .kill_gbuf = kill_gbuf,
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700260};
261
Alex Elder877b1ee2014-09-24 05:16:13 -0500262/* Common function to report consistent warnings based on URB status */
263static int check_urb_status(struct urb *urb)
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700264{
265 struct device *dev = &urb->dev->dev;
266 int status = urb->status;
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700267
268 switch (status) {
269 case 0:
Alex Elder877b1ee2014-09-24 05:16:13 -0500270 return 0;
271
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700272 case -EOVERFLOW:
273 dev_err(dev, "%s: overflow actual length is %d\n",
274 __func__, urb->actual_length);
275 case -ECONNRESET:
276 case -ENOENT:
277 case -ESHUTDOWN:
278 case -EILSEQ:
Matt Porter8fd39e32014-10-13 03:00:53 -0400279 case -EPROTO:
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700280 /* device is gone, stop sending */
Alex Elder877b1ee2014-09-24 05:16:13 -0500281 return status;
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700282 }
Alex Elder877b1ee2014-09-24 05:16:13 -0500283 dev_err(dev, "%s: unknown status %d\n", __func__, status);
284
285 return -EAGAIN;
286}
287
Alex Elder68925372014-10-20 10:27:59 -0500288static void ap_disconnect(struct usb_interface *interface)
289{
290 struct es1_ap_dev *es1;
291 int i;
292
293 es1 = usb_get_intfdata(interface);
294 if (!es1)
295 return;
296
297 /* Tear down everything! */
298 for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500299 struct urb *urb = es1->cport_out_urb[i];
300
301 if (!urb)
302 break;
303 usb_kill_urb(urb);
304 usb_free_urb(urb);
305 es1->cport_out_urb[i] = NULL;
306 es1->cport_out_urb_busy[i] = false; /* just to be anal */
Alex Elder68925372014-10-20 10:27:59 -0500307 }
308
309 for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500310 struct urb *urb = es1->cport_in_urb[i];
311
312 if (!urb)
313 break;
314 usb_kill_urb(urb);
315 usb_free_urb(urb);
Alex Elder68925372014-10-20 10:27:59 -0500316 kfree(es1->cport_in_buffer[i]);
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500317 es1->cport_in_buffer[i] = NULL;
Alex Elder68925372014-10-20 10:27:59 -0500318 }
319
320 usb_kill_urb(es1->svc_urb);
321 usb_free_urb(es1->svc_urb);
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500322 es1->svc_urb = NULL;
Alex Elder68925372014-10-20 10:27:59 -0500323 kfree(es1->svc_buffer);
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500324 es1->svc_buffer = NULL;
325
Alex Elder68925372014-10-20 10:27:59 -0500326 usb_set_intfdata(interface, NULL);
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500327 greybus_remove_hd(es1->hd);
328
329 usb_put_dev(es1->usb_dev);
Alex Elder68925372014-10-20 10:27:59 -0500330}
331
Alex Elder877b1ee2014-09-24 05:16:13 -0500332/* Callback for when we get a SVC message */
333static void svc_in_callback(struct urb *urb)
334{
335 struct es1_ap_dev *es1 = urb->context;
336 struct device *dev = &urb->dev->dev;
337 int status = check_urb_status(urb);
338 int retval;
339
Alex Elderbedfdf32014-10-17 05:18:22 -0500340 if (status) {
Alex Elderc4a432d2014-10-24 05:02:02 -0500341 if (status == -EAGAIN)
342 goto exit;
343 dev_err(dev, "urb svc in error %d (dropped)\n", status);
344 return;
Alex Elderbedfdf32014-10-17 05:18:22 -0500345 }
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700346
347 /* We have a message, create a new message structure, add it to the
348 * list, and wake up our thread that will process the messages.
349 */
Alex Elder51c75fd2014-09-26 20:55:35 -0500350 greybus_svc_in(es1->hd, urb->transfer_buffer, urb->actual_length);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700351
352exit:
353 /* resubmit the urb to get more messages */
354 retval = usb_submit_urb(urb, GFP_ATOMIC);
355 if (retval)
356 dev_err(dev, "Can not submit urb for AP data: %d\n", retval);
357}
358
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700359static void cport_in_callback(struct urb *urb)
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700360{
361 struct device *dev = &urb->dev->dev;
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700362 struct es1_ap_dev *es1 = urb->context;
Alex Elder877b1ee2014-09-24 05:16:13 -0500363 int status = check_urb_status(urb);
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700364 int retval;
365 u8 cport;
366 u8 *data;
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700367
Alex Elderbedfdf32014-10-17 05:18:22 -0500368 if (status) {
Alex Elderc4a432d2014-10-24 05:02:02 -0500369 if (status == -EAGAIN)
370 goto exit;
371 dev_err(dev, "urb cport in error %d (dropped)\n", status);
372 return;
Alex Elderbedfdf32014-10-17 05:18:22 -0500373 }
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700374
Alex Elder170229d2014-10-16 06:35:27 -0500375 /* The size has to be at least one, for the cport id */
376 if (!urb->actual_length) {
377 dev_err(dev, "%s: no cport id in input buffer?\n", __func__);
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700378 goto exit;
379 }
380
381 /*
382 * The CPort number is the first byte of the data stream, the rest of
383 * the stream is "real" data
384 */
385 data = urb->transfer_buffer;
386 cport = data[0];
387 data = &data[1];
388
389 /* Pass this data to the greybus core */
Alex Elder0db32a62014-09-24 05:16:14 -0500390 greybus_cport_in(es1->hd, cport, data, urb->actual_length - 1);
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700391
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700392exit:
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700393 /* put our urb back in the request pool */
394 retval = usb_submit_urb(urb, GFP_ATOMIC);
395 if (retval)
396 dev_err(dev, "%s: error %d in submitting urb.\n",
397 __func__, retval);
Greg Kroah-Hartmande536e32014-08-31 16:17:04 -0700398}
399
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700400static void cport_out_callback(struct urb *urb)
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700401{
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700402 struct gbuf *gbuf = urb->context;
Alex Elderba993462014-11-17 08:08:43 -0600403 struct es1_ap_dev *es1 = hd_to_es1(gbuf->hd);
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700404 unsigned long flags;
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700405 int i;
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700406
Alex Elderbedfdf32014-10-17 05:18:22 -0500407 /* Record whether the transfer was successful */
408 gbuf->status = check_urb_status(urb);
Greg Kroah-Hartmand8144882014-10-27 13:31:01 +0800409 gbuf->hcd_data = NULL;
Alex Elderbedfdf32014-10-17 05:18:22 -0500410
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700411 /*
Greg Kroah-Hartman7f9e05e2014-09-13 17:28:33 -0700412 * See if this was an urb in our pool, if so mark it "free", otherwise
413 * we need to free it ourselves.
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700414 */
415 spin_lock_irqsave(&es1->cport_out_urb_lock, flags);
416 for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
417 if (urb == es1->cport_out_urb[i]) {
418 es1->cport_out_urb_busy[i] = false;
419 urb = NULL;
420 break;
421 }
422 }
423 spin_unlock_irqrestore(&es1->cport_out_urb_lock, flags);
Greg Kroah-Hartman9c8d3af2014-09-13 11:09:35 -0700424
Greg Kroah-Hartman7f9e05e2014-09-13 17:28:33 -0700425 /* If urb is not NULL, then we need to free this urb */
426 usb_free_urb(urb);
Greg Kroah-Hartmanf9ab34c2014-10-28 18:20:24 +0800427
428 /*
429 * Yes, you are right, we aren't telling anyone that the urb finished.
430 * "That's crazy! How does this all even work?" you might be saying.
431 * The "magic" is the idea that greybus works on the "operation" level,
432 * not the "send a buffer" level. All operations are "round-trip" with
433 * a response from the device that the operation finished, or it will
434 * time out. Because of that, we don't care that this urb finished, or
435 * failed, or did anything else, as higher levels of the protocol stack
436 * will handle completions and timeouts and the rest.
437 *
438 * This protocol is "needed" due to some hardware restrictions on the
439 * current generation of Unipro controllers. Think about it for a
440 * minute, this is a USB driver, talking to a Unipro bridge, impediance
441 * mismatch is huge, yet the Unipro controller are even more
442 * underpowered than this little USB controller. We rely on the round
443 * trip to keep stalls in the Unipro controllers from happening so that
444 * we can keep data flowing properly, no matter how slow it might be.
445 *
446 * Once again, a wonderful bus protocol cut down in its prime by a naive
447 * controller chip. We dream of the day we have a "real" HCD for
448 * Unipro. Until then, we suck it up and make the hardware work, as
449 * that's the job of the firmware and kernel.
450 * </rant>
451 */
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700452}
453
454/*
455 * The ES1 USB Bridge device contains 4 endpoints
456 * 1 Control - usual USB stuff + AP -> SVC messages
457 * 1 Interrupt IN - SVC -> AP messages
458 * 1 Bulk IN - CPort data in
Alex Elder69f93ab2014-09-22 18:53:02 -0500459 * 1 Bulk OUT - CPort data out
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700460 */
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700461static int ap_probe(struct usb_interface *interface,
462 const struct usb_device_id *id)
463{
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700464 struct es1_ap_dev *es1;
465 struct greybus_host_device *hd;
466 struct usb_device *udev;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700467 struct usb_host_interface *iface_desc;
468 struct usb_endpoint_descriptor *endpoint;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700469 bool int_in_found = false;
470 bool bulk_in_found = false;
471 bool bulk_out_found = false;
472 int retval = -ENOMEM;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700473 int i;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700474 u8 svc_interval = 0;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700475
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700476 udev = usb_get_dev(interface_to_usbdev(interface));
477
478 hd = greybus_create_hd(&es1_driver, &udev->dev);
Alex Elder599dc6a2014-10-20 10:27:55 -0500479 if (!hd) {
480 usb_put_dev(udev);
Greg Kroah-Hartmanf1eec302014-08-30 17:18:14 -0700481 return -ENOMEM;
Alex Elder599dc6a2014-10-20 10:27:55 -0500482 }
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700483
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700484 es1 = hd_to_es1(hd);
485 es1->hd = hd;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700486 es1->usb_intf = interface;
487 es1->usb_dev = udev;
Greg Kroah-Hartman0dad95d2014-09-13 09:54:35 -0700488 spin_lock_init(&es1->cport_out_urb_lock);
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700489 usb_set_intfdata(interface, es1);
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700490
491 /* Control endpoint is the pipe to talk to this AP, so save it off */
492 endpoint = &udev->ep0.desc;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700493 es1->control_endpoint = endpoint->bEndpointAddress;
Greg Kroah-Hartmana39879f2014-09-06 16:57:36 -0700494
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700495 /* find all 3 of our endpoints */
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700496 iface_desc = interface->cur_altsetting;
497 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
498 endpoint = &iface_desc->endpoint[i].desc;
499
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700500 if (usb_endpoint_is_int_in(endpoint)) {
501 es1->svc_endpoint = endpoint->bEndpointAddress;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700502 svc_interval = endpoint->bInterval;
503 int_in_found = true;
504 } else if (usb_endpoint_is_bulk_in(endpoint)) {
505 es1->cport_in_endpoint = endpoint->bEndpointAddress;
506 bulk_in_found = true;
507 } else if (usb_endpoint_is_bulk_out(endpoint)) {
508 es1->cport_out_endpoint = endpoint->bEndpointAddress;
509 bulk_out_found = true;
510 } else {
511 dev_err(&udev->dev,
512 "Unknown endpoint type found, address %x\n",
513 endpoint->bEndpointAddress);
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700514 }
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700515 }
516 if ((int_in_found == false) ||
517 (bulk_in_found == false) ||
518 (bulk_out_found == false)) {
519 dev_err(&udev->dev, "Not enough endpoints found in device, aborting!\n");
520 goto error;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700521 }
522
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700523 /* Create our buffer and URB to get SVC messages, and start it up */
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -0700524 es1->svc_buffer = kmalloc(ES1_SVC_MSG_SIZE, GFP_KERNEL);
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700525 if (!es1->svc_buffer)
526 goto error;
Greg Kroah-Hartman6f83ab72014-08-30 17:30:04 -0700527
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700528 es1->svc_urb = usb_alloc_urb(0, GFP_KERNEL);
529 if (!es1->svc_urb)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500530 goto error;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700531
532 usb_fill_int_urb(es1->svc_urb, udev,
533 usb_rcvintpipe(udev, es1->svc_endpoint),
Alex Elder877b1ee2014-09-24 05:16:13 -0500534 es1->svc_buffer, ES1_SVC_MSG_SIZE, svc_in_callback,
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700535 es1, svc_interval);
536 retval = usb_submit_urb(es1->svc_urb, GFP_KERNEL);
537 if (retval)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500538 goto error;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700539
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700540 /* Allocate buffers for our cport in messages and start them up */
541 for (i = 0; i < NUM_CPORT_IN_URB; ++i) {
542 struct urb *urb;
543 u8 *buffer;
544
545 urb = usb_alloc_urb(0, GFP_KERNEL);
546 if (!urb)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500547 goto error;
Greg Kroah-Hartman29f000f2014-09-19 18:37:44 -0700548 buffer = kmalloc(ES1_GBUF_MSG_SIZE, GFP_KERNEL);
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700549 if (!buffer)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500550 goto error;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700551
552 usb_fill_bulk_urb(urb, udev,
553 usb_rcvbulkpipe(udev, es1->cport_in_endpoint),
Alex Elder3e9cb4a2014-11-12 15:17:50 -0600554 buffer, ES1_GBUF_MSG_SIZE, cport_in_callback,
555 es1);
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700556 es1->cport_in_urb[i] = urb;
557 es1->cport_in_buffer[i] = buffer;
558 retval = usb_submit_urb(urb, GFP_KERNEL);
559 if (retval)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500560 goto error;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700561 }
562
563 /* Allocate urbs for our CPort OUT messages */
564 for (i = 0; i < NUM_CPORT_OUT_URB; ++i) {
565 struct urb *urb;
566
567 urb = usb_alloc_urb(0, GFP_KERNEL);
568 if (!urb)
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500569 goto error;
Greg Kroah-Hartman11299732014-09-12 21:17:37 -0700570
571 es1->cport_out_urb[i] = urb;
572 es1->cport_out_urb_busy[i] = false; /* just to be anal */
573 }
574
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700575 return 0;
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700576error:
Alex Elder1ec1d6d2014-10-20 10:28:00 -0500577 ap_disconnect(interface);
578
Greg Kroah-Hartman47f6ef12014-09-08 20:09:08 -0700579 return retval;
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700580}
581
Greg Kroah-Hartmanba4468d42014-08-30 17:06:54 -0700582static struct usb_driver es1_ap_driver = {
583 .name = "es1_ap_driver",
584 .probe = ap_probe,
585 .disconnect = ap_disconnect,
586 .id_table = id_table,
587};
588
589module_usb_driver(es1_ap_driver);
590
591MODULE_LICENSE("GPL");
592MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");