blob: ac5722f3b8b20ab89d48ea726310340abae5e1d7 [file] [log] [blame]
Dixon Peterson32e70bb2011-12-16 13:26:45 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/slab.h>
14#include <linux/init.h>
15#include <linux/uaccess.h>
16#include <linux/diagchar.h>
17#include <linux/sched.h>
18#include <linux/err.h>
19#include <linux/workqueue.h>
20#include <linux/pm_runtime.h>
21#include <linux/platform_device.h>
22#include <asm/current.h>
23#ifdef CONFIG_DIAG_OVER_USB
24#include <mach/usbdiag.h>
25#endif
26#include "diagchar_hdlc.h"
27#include "diagmem.h"
28#include "diagchar.h"
29#include "diagfwd.h"
30#include "diagfwd_hsic.h"
31
32static void diag_read_hsic_work_fn(struct work_struct *work)
33{
34 if (!driver->hsic_ch) {
35 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
36 return;
37 }
38
39 /*
40 * If there is no hsic data being read from the hsic and there
41 * is no hsic data being written to the usb mdm channel
42 */
43 if (!driver->in_busy_hsic_read && !driver->in_busy_hsic_write_on_mdm) {
44 /*
45 * Initiate the read from the hsic. The hsic read is
46 * asynchronous. Once the read is complete the read
47 * callback function will be called.
48 */
49 int err;
50 driver->in_busy_hsic_read = 1;
51 APPEND_DEBUG('i');
52 err = diag_bridge_read((char *)driver->buf_in_hsic,
53 IN_BUF_SIZE);
54 if (err) {
55 pr_err("DIAG: Error initiating HSIC read, err: %d\n",
56 err);
57 /*
58 * If the error is recoverable, then clear
59 * the read flag, so we will resubmit a
60 * read on the next frame. Otherwise, don't
61 * resubmit a read on the next frame.
62 */
63 if ((-ESHUTDOWN) != err)
64 driver->in_busy_hsic_read = 0;
65 }
66 }
67
68 /*
69 * If for some reason there was no hsic data, set up
70 * the next read
71 */
72 if (!driver->in_busy_hsic_read)
73 queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
74}
75
76static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
77 int buf_size, int actual_size)
78{
79 /* The read of the data from the HSIC bridge is complete */
80 driver->in_busy_hsic_read = 0;
81
82 if (!driver->hsic_ch) {
83 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
84 return;
85 }
86
87 APPEND_DEBUG('j');
88 if (actual_size > 0) {
89 if (!buf) {
90 pr_err("Out of diagmem for HSIC\n");
91 } else {
92 driver->write_ptr_mdm->length = actual_size;
93 /*
94 * Set flag to denote hsic data is currently
95 * being written to the usb mdm channel.
96 * driver->buf_in_hsic was given to
97 * diag_bridge_read(), so buf here should be
98 * driver->buf_in_hsic
99 */
100 driver->in_busy_hsic_write_on_mdm = 1;
101 diag_device_write((void *)buf, HSIC_DATA,
102 driver->write_ptr_mdm);
103 }
104 } else {
105 pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
106 }
107
108 /*
109 * If for some reason there was no hsic data to write to the
110 * mdm channel, set up another read
111 */
112 if (!driver->in_busy_hsic_write_on_mdm)
113 queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
114}
115
116static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
117 int buf_size, int actual_size)
118{
119 /* The write of the data to the HSIC bridge is complete */
120 driver->in_busy_hsic_write = 0;
121
122 if (!driver->hsic_ch) {
123 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
124 return;
125 }
126
127 if (actual_size < 0)
128 pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
129
130 queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
131}
132
133static struct diag_bridge_ops hsic_diag_bridge_ops = {
134 .ctxt = NULL,
135 .read_complete_cb = diag_hsic_read_complete_callback,
136 .write_complete_cb = diag_hsic_write_complete_callback,
137};
138
139static int diag_hsic_close(void)
140{
141 if (driver->hsic_device_enabled) {
142 driver->hsic_ch = 0;
143 if (driver->hsic_device_opened) {
144 driver->hsic_device_opened = 0;
145 diag_bridge_close();
146 }
147 pr_debug("DIAG in %s: closed successfully\n", __func__);
148 } else {
149 pr_debug("DIAG in %s: already closed\n", __func__);
150 }
151
152 return 0;
153}
154
155/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
156static int diagfwd_connect_hsic(void)
157{
158 int err;
159
160 pr_debug("DIAG in %s\n", __func__);
161
162 err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE, N_MDM_READ);
163 if (err)
164 pr_err("DIAG: unable to alloc USB req on mdm ch err:%d\n", err);
165
166 driver->usb_mdm_connected = 1;
167 driver->in_busy_hsic_write_on_mdm = 0;
168 driver->in_busy_hsic_read_on_mdm = 0;
169 driver->in_busy_hsic_write = 0;
170 driver->in_busy_hsic_read = 0;
171
172 /* If the hsic (diag_bridge) platform device is not open */
173 if (driver->hsic_device_enabled) {
174 if (!driver->hsic_device_opened) {
175 err = diag_bridge_open(&hsic_diag_bridge_ops);
176 if (err) {
177 pr_err("DIAG: HSIC channel open error: %d\n",
178 err);
179 } else {
180 pr_info("DIAG: opened HSIC channel\n");
181 driver->hsic_device_opened = 1;
182 }
183 } else {
184 pr_info("DIAG: HSIC channel already open\n");
185 }
186
187 /*
188 * Turn on communication over usb mdm and hsic, if the hsic
189 * device driver is enabled and opened
190 */
191 if (driver->hsic_device_opened)
192 driver->hsic_ch = 1;
193
194 /* Poll USB mdm channel to check for data */
195 queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
196
197 /* Poll HSIC channel to check for data */
198 queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
199 } else {
200 /* The hsic device driver has not yet been enabled */
201 pr_info("DIAG: HSIC channel not yet enabled\n");
202 }
203
204 return 0;
205}
206
207/*
208 * diagfwd_disconnect_hsic is called when the USB mdm channel
209 * is disconnected
210 */
211static int diagfwd_disconnect_hsic(void)
212{
213 pr_debug("DIAG in %s\n", __func__);
214
215 driver->usb_mdm_connected = 0;
216 usb_diag_free_req(driver->mdm_ch);
217 driver->in_busy_hsic_write_on_mdm = 1;
218 driver->in_busy_hsic_read_on_mdm = 1;
219 driver->in_busy_hsic_write = 1;
220 driver->in_busy_hsic_read = 1;
221
222 /* Turn off communication over usb mdm and hsic */
223 driver->hsic_ch = 0;
224
225 return 0;
226}
227
228/*
229 * diagfwd_write_complete_hsic is called after the asynchronous
230 * usb_diag_write() on mdm channel is complete
231 */
232static int diagfwd_write_complete_hsic(void)
233{
234 /*
235 * Clear flag to denote that the write of the hsic data on the
236 * usb mdm channel is complete
237 */
238 driver->in_busy_hsic_write_on_mdm = 0;
239
240 if (!driver->hsic_ch) {
241 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
242 return 0;
243 }
244
245 APPEND_DEBUG('q');
246
247 /* Read data from the hsic */
248 queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
249
250 return 0;
251}
252
253/* Called after the asychronous usb_diag_read() on mdm channel is complete */
254static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
255{
256 /* The read of the usb driver on the mdm (not hsic) has completed */
257 driver->in_busy_hsic_read_on_mdm = 0;
258 driver->read_len_mdm = diag_read_ptr->actual;
259
260 if (!driver->hsic_ch) {
261 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
262 return 0;
263 }
264
265 /*
266 * The read of the usb driver on the mdm channel has completed.
267 * If there is no write on the hsic in progress, check if the
268 * read has data to pass on to the hsic. If so, pass the usb
269 * mdm data on to the hsic.
270 */
271 if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
272 (driver->read_len_mdm > 0)) {
273
274 /*
275 * Initiate the hsic write. The hsic write is
276 * asynchronous. When complete the write
277 * complete callback function will be called
278 */
279 int err;
280 driver->in_busy_hsic_write = 1;
281 err = diag_bridge_write(driver->usb_buf_mdm_out,
282 driver->read_len_mdm);
283 if (err) {
284 pr_err("DIAG: mdm data on hsic write err: %d\n", err);
285 /*
286 * If the error is recoverable, then clear
287 * the write flag, so we will resubmit a
288 * write on the next frame. Otherwise, don't
289 * resubmit a write on the next frame.
290 */
291 if ((-ESHUTDOWN) != err)
292 driver->in_busy_hsic_write = 0;
293 }
294 }
295
296 /*
297 * If there is no write of the usb mdm data on the
298 * hsic channel
299 */
300 if (!driver->in_busy_hsic_write)
301 queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
302
303 return 0;
304}
305
306static void diagfwd_hsic_notifier(void *priv, unsigned event,
307 struct diag_request *d_req)
308{
309 switch (event) {
310 case USB_DIAG_CONNECT:
311 diagfwd_connect_hsic();
312 break;
313 case USB_DIAG_DISCONNECT:
314 diagfwd_disconnect_hsic();
315 break;
316 case USB_DIAG_READ_DONE:
317 diagfwd_read_complete_hsic(d_req);
318 break;
319 case USB_DIAG_WRITE_DONE:
320 diagfwd_write_complete_hsic();
321 break;
322 default:
323 pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
324 __func__, event);
325 break;
326 }
327}
328
329static void diag_read_mdm_work_fn(struct work_struct *work)
330{
331 if (!driver->hsic_ch) {
332 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
333 return;
334 }
335
336 /*
337 * If there is no data being read from the usb mdm channel
338 * and there is no mdm channel data currently being written
339 * to the hsic
340 */
341 if (!driver->in_busy_hsic_read_on_mdm && !driver->in_busy_hsic_write) {
342 APPEND_DEBUG('x');
343
344 /* Setup the next read from usb mdm channel */
345 driver->in_busy_hsic_read_on_mdm = 1;
346 driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
347 driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
348 usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
349 APPEND_DEBUG('y');
350 }
351
352 /*
353 * If for some reason there was no mdm channel read initiated,
354 * queue up the reading of data from the mdm channel
355 */
356 if (!driver->in_busy_hsic_read_on_mdm)
357 queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
358}
359
360int diag_hsic_enable(void)
361{
362 pr_debug("DIAG in %s\n", __func__);
363
364 driver->read_len_mdm = 0;
365 if (driver->buf_in_hsic == NULL)
366 driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
367 if (driver->buf_in_hsic == NULL)
368 goto err;
369 if (driver->usb_buf_mdm_out == NULL)
370 driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF, GFP_KERNEL);
371 if (driver->usb_buf_mdm_out == NULL)
372 goto err;
373 if (driver->write_ptr_mdm == NULL)
374 driver->write_ptr_mdm = kzalloc(
375 sizeof(struct diag_request), GFP_KERNEL);
376 if (driver->write_ptr_mdm == NULL)
377 goto err;
378 if (driver->usb_read_mdm_ptr == NULL)
379 driver->usb_read_mdm_ptr = kzalloc(
380 sizeof(struct diag_request), GFP_KERNEL);
381 if (driver->usb_read_mdm_ptr == NULL)
382 goto err;
383 driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
384#ifdef CONFIG_DIAG_OVER_USB
385 INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
386#endif
387 INIT_WORK(&(driver->diag_read_hsic_work), diag_read_hsic_work_fn);
388
389 driver->hsic_device_enabled = 1;
390
391 return 0;
392err:
393 pr_err("DIAG could not initialize buf for HSIC\n");
394 kfree(driver->buf_in_hsic);
395 kfree(driver->usb_buf_mdm_out);
396 kfree(driver->write_ptr_mdm);
397 kfree(driver->usb_read_mdm_ptr);
398 if (driver->diag_hsic_wq)
399 destroy_workqueue(driver->diag_hsic_wq);
400
401 return -ENOMEM;
402}
403
404static int diag_hsic_probe(struct platform_device *pdev)
405{
406 int err;
407
408 if (!driver->hsic_device_enabled) {
409 err = diag_hsic_enable();
410 if (err) {
411 pr_err("DIAG could not enable HSIC, err: %d\n", err);
412 return err;
413 }
414 }
415
416 /* The hsic (diag_bridge) platform device driver is enabled */
417 err = diag_bridge_open(&hsic_diag_bridge_ops);
418 if (err) {
419 pr_err("DIAG could not open HSIC channel, err: %d\n", err);
420 driver->hsic_device_opened = 0;
421 return err;
422 }
423
424 pr_info("DIAG opened HSIC channel\n");
425 driver->hsic_device_opened = 1;
426
427 /*
428 * The probe function was called after the usb was connected
429 * on the legacy channel. Communication over usb mdm and hsic
430 * needs to be turned on.
431 */
432 if (driver->usb_connected) {
433 driver->hsic_ch = 1;
434 driver->in_busy_hsic_write_on_mdm = 0;
435 driver->in_busy_hsic_read_on_mdm = 0;
436 driver->in_busy_hsic_write = 0;
437 driver->in_busy_hsic_read = 0;
438
439 /* Poll USB mdm channel to check for data */
440 queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
441
442 /* Poll HSIC channel to check for data */
443 queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
444 }
445
446 return err;
447}
448
449static int diag_hsic_remove(struct platform_device *pdev)
450{
451 pr_info("DIAG: %s called\n", __func__);
452 diag_hsic_close();
453 return 0;
454}
455
456static int diagfwd_hsic_runtime_suspend(struct device *dev)
457{
458 dev_dbg(dev, "pm_runtime: suspending...\n");
459 return 0;
460}
461
462static int diagfwd_hsic_runtime_resume(struct device *dev)
463{
464 dev_dbg(dev, "pm_runtime: resuming...\n");
465 return 0;
466}
467
468static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
469 .runtime_suspend = diagfwd_hsic_runtime_suspend,
470 .runtime_resume = diagfwd_hsic_runtime_resume,
471};
472
473static struct platform_driver msm_hsic_ch_driver = {
474 .probe = diag_hsic_probe,
475 .remove = diag_hsic_remove,
476 .driver = {
477 .name = "diag_bridge",
478 .owner = THIS_MODULE,
479 .pm = &diagfwd_hsic_dev_pm_ops,
480 },
481};
482
483
484void __init diagfwd_hsic_init(void)
485{
486 int ret;
487
488 pr_debug("DIAG in %s\n", __func__);
489
490#ifdef CONFIG_DIAG_OVER_USB
491 driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
492 if (IS_ERR(driver->mdm_ch)) {
493 pr_err("DIAG Unable to open USB diag MDM channel\n");
494 goto err;
495 }
496#endif
497 ret = platform_driver_register(&msm_hsic_ch_driver);
498 if (ret)
499 pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
500 else
501 driver->hsic_initialized = 1;
502
503 return;
504err:
505 pr_err("DIAG could not initialize for HSIC execution\n");
506}
507
508void __exit diagfwd_hsic_exit(void)
509{
510 pr_debug("DIAG in %s\n", __func__);
511
512 if (driver->hsic_initialized)
513 diag_hsic_close();
514
515#ifdef CONFIG_DIAG_OVER_USB
516 if (driver->usb_mdm_connected)
517 usb_diag_free_req(driver->mdm_ch);
518#endif
519 platform_driver_unregister(&msm_hsic_ch_driver);
520#ifdef CONFIG_DIAG_OVER_USB
521 usb_diag_close(driver->mdm_ch);
522#endif
523 kfree(driver->buf_in_hsic);
524 kfree(driver->usb_buf_mdm_out);
525 kfree(driver->write_ptr_mdm);
526 kfree(driver->usb_read_mdm_ptr);
527 destroy_workqueue(driver->diag_hsic_wq);
528
529 driver->hsic_device_enabled = 0;
530}