blob: 7aef01fd38743c17ea0f2bec8e74fc216303e7a6 [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>
Jack Phamcca03322012-06-14 19:00:31 -070019#include <linux/ratelimit.h>
Dixon Peterson32e70bb2011-12-16 13:26:45 -080020#include <linux/workqueue.h>
21#include <linux/pm_runtime.h>
22#include <linux/platform_device.h>
Shalabh Jainf7228dc2012-05-23 17:32:05 -070023#include <linux/smux.h>
Dixon Peterson32e70bb2011-12-16 13:26:45 -080024#include <asm/current.h>
25#ifdef CONFIG_DIAG_OVER_USB
26#include <mach/usbdiag.h>
27#endif
28#include "diagchar_hdlc.h"
29#include "diagmem.h"
30#include "diagchar.h"
31#include "diagfwd.h"
32#include "diagfwd_hsic.h"
Shalabh Jainf7228dc2012-05-23 17:32:05 -070033#include "diagfwd_smux.h"
Dixon Peterson32e70bb2011-12-16 13:26:45 -080034
Dixon Peterson938f8602012-08-17 20:02:57 -070035#define READ_HSIC_BUF_SIZE 2048
36
Dixon Peterson32e70bb2011-12-16 13:26:45 -080037static void diag_read_hsic_work_fn(struct work_struct *work)
38{
Dixon Peterson938f8602012-08-17 20:02:57 -070039 unsigned char *buf_in_hsic = NULL;
40 int num_reads_submitted = 0;
41 int err = 0;
42 int write_ptrs_available;
43
Dixon Peterson32e70bb2011-12-16 13:26:45 -080044 if (!driver->hsic_ch) {
45 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
46 return;
47 }
48
Dixon Peterson938f8602012-08-17 20:02:57 -070049 /*
50 * Determine the current number of available buffers for writing after
51 * reading from the HSIC has completed.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080052 */
Dixon Peterson938f8602012-08-17 20:02:57 -070053 if (driver->logging_mode == MEMORY_DEVICE_MODE)
54 write_ptrs_available = driver->poolsize_hsic_write -
55 driver->num_hsic_buf_tbl_entries;
56 else
57 write_ptrs_available = driver->poolsize_hsic_write -
58 driver->count_hsic_write_pool;
Dixon Peterson32e70bb2011-12-16 13:26:45 -080059
60 /*
Dixon Peterson938f8602012-08-17 20:02:57 -070061 * Queue up a read on the HSIC for all available buffers in the
62 * pool, exhausting the pool.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080063 */
Dixon Peterson938f8602012-08-17 20:02:57 -070064 do {
65 /*
66 * If no more write buffers are available,
67 * stop queuing reads
68 */
69 if (write_ptrs_available <= 0)
70 break;
71
72 write_ptrs_available--;
73
Dixon Peterson6beff2d2012-09-13 18:51:47 -070074 /*
75 * No sense queuing a read if the hsic bridge was
76 * closed in another thread
77 */
78 if (!driver->hsic_ch)
79 break;
80
Dixon Peterson938f8602012-08-17 20:02:57 -070081 buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
82 POOL_TYPE_HSIC);
83 if (buf_in_hsic) {
84 /*
85 * Initiate the read from the hsic. The hsic read is
86 * asynchronous. Once the read is complete the read
87 * callback function will be called.
88 */
Dixon Peterson938f8602012-08-17 20:02:57 -070089 pr_debug("diag: read from HSIC\n");
90 num_reads_submitted++;
91 err = diag_bridge_read((char *)buf_in_hsic,
92 READ_HSIC_BUF_SIZE);
93 if (err) {
94 num_reads_submitted--;
95
96 /* Return the buffer to the pool */
97 diagmem_free(driver, buf_in_hsic,
98 POOL_TYPE_HSIC);
99
100 pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
101 err);
102 /*
103 * An error occurred, discontinue queuing
104 * reads
105 */
106 break;
107 }
108 }
109 } while (buf_in_hsic);
110
111 /*
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700112 * If there are read buffers available and for some reason the
113 * read was not queued, and if no unrecoverable error occurred
Dixon Peterson938f8602012-08-17 20:02:57 -0700114 * (-ENODEV is an unrecoverable error), then set up the next read
115 */
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700116 if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700117 (num_reads_submitted == 0) && (err != -ENODEV) &&
118 (driver->hsic_ch != 0))
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700119 queue_work(driver->diag_bridge_wq,
120 &driver->diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800121}
122
123static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
124 int buf_size, int actual_size)
125{
Dixon Peterson938f8602012-08-17 20:02:57 -0700126 int err = -2;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800127
128 if (!driver->hsic_ch) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700129 /*
130 * The hsic channel is closed. Return the buffer to
131 * the pool. Do not send it on.
132 */
133 diagmem_free(driver, buf, POOL_TYPE_HSIC);
134 pr_debug("diag: In %s: driver->hsic_ch == 0, actual_size: %d\n",
135 __func__, actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800136 return;
137 }
138
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700139 /*
140 * Note that zero length is valid and still needs to be sent to
141 * the USB only when we are logging data to the USB
142 */
143 if ((actual_size > 0) ||
144 ((actual_size == 0) && (driver->logging_mode == USB_MODE))) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800145 if (!buf) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700146 pr_err("diag: Out of diagmem for HSIC\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800147 } else {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800148 /*
Dixon Peterson938f8602012-08-17 20:02:57 -0700149 * Send data in buf to be written on the
150 * appropriate device, e.g. USB MDM channel
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800151 */
Dixon Peterson938f8602012-08-17 20:02:57 -0700152 driver->write_len_mdm = actual_size;
153 err = diag_device_write((void *)buf, HSIC_DATA, NULL);
154 /* If an error, return buffer to the pool */
155 if (err) {
156 diagmem_free(driver, buf, POOL_TYPE_HSIC);
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700157 pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700158 __func__, err);
159 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800160 }
161 } else {
Dixon Peterson938f8602012-08-17 20:02:57 -0700162 /*
163 * The buffer has an error status associated with it. Do not
164 * pass it on. Note that -ENOENT is sent when the diag bridge
165 * is closed.
166 */
167 diagmem_free(driver, buf, POOL_TYPE_HSIC);
168 pr_debug("diag: In %s: error status: %d\n", __func__,
169 actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800170 }
171
172 /*
173 * If for some reason there was no hsic data to write to the
174 * mdm channel, set up another read
175 */
Dixon Peterson938f8602012-08-17 20:02:57 -0700176 if (err &&
177 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
178 (driver->usb_mdm_connected && !driver->hsic_suspend))) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700179 queue_work(driver->diag_bridge_wq,
180 &driver->diag_read_hsic_work);
Dixon Peterson938f8602012-08-17 20:02:57 -0700181 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800182}
183
184static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
185 int buf_size, int actual_size)
186{
187 /* The write of the data to the HSIC bridge is complete */
188 driver->in_busy_hsic_write = 0;
189
190 if (!driver->hsic_ch) {
191 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
192 return;
193 }
194
195 if (actual_size < 0)
196 pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
197
Dixon Peterson70170f72012-11-05 20:25:11 -0800198 if (driver->usb_mdm_connected && (driver->logging_mode == USB_MODE))
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700199 queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
Jack Phamb60775a2012-02-14 17:57:41 -0800200}
201
202static int diag_hsic_suspend(void *ctxt)
203{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700204 pr_debug("diag: hsic_suspend\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700205
206 /* Don't allow suspend if a write in the HSIC is in progress */
Jack Phamb60775a2012-02-14 17:57:41 -0800207 if (driver->in_busy_hsic_write)
208 return -EBUSY;
209
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700210 /* Don't allow suspend if in MEMORY_DEVICE_MODE */
211 if (driver->logging_mode == MEMORY_DEVICE_MODE)
212 return -EBUSY;
213
Jack Phamb60775a2012-02-14 17:57:41 -0800214 driver->hsic_suspend = 1;
215
216 return 0;
217}
218
219static void diag_hsic_resume(void *ctxt)
220{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700221 pr_debug("diag: hsic_resume\n");
Jack Phamb60775a2012-02-14 17:57:41 -0800222 driver->hsic_suspend = 0;
223
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700224 if ((driver->count_hsic_pool < driver->poolsize_hsic) &&
225 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
226 (driver->usb_mdm_connected)))
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700227 queue_work(driver->diag_bridge_wq,
228 &driver->diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800229}
230
231static struct diag_bridge_ops hsic_diag_bridge_ops = {
232 .ctxt = NULL,
233 .read_complete_cb = diag_hsic_read_complete_callback,
234 .write_complete_cb = diag_hsic_write_complete_callback,
Jack Phamb60775a2012-02-14 17:57:41 -0800235 .suspend = diag_hsic_suspend,
236 .resume = diag_hsic_resume,
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800237};
238
Jack Phamfbd22552012-09-07 17:29:08 -0700239static void diag_hsic_close(void)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800240{
241 if (driver->hsic_device_enabled) {
242 driver->hsic_ch = 0;
243 if (driver->hsic_device_opened) {
244 driver->hsic_device_opened = 0;
245 diag_bridge_close();
Jack Phamfbd22552012-09-07 17:29:08 -0700246 pr_debug("diag: %s: closed successfully\n", __func__);
247 } else {
248 pr_debug("diag: %s: already closed\n", __func__);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800249 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800250 } else {
Jack Phamfbd22552012-09-07 17:29:08 -0700251 pr_debug("diag: %s: HSIC device already removed\n", __func__);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700252 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700253}
254
255/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
256int diagfwd_cancel_hsic(void)
257{
258 int err;
259
Jack Phamfbd22552012-09-07 17:29:08 -0700260 mutex_lock(&driver->bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700261 if (driver->hsic_device_enabled) {
262 if (driver->hsic_device_opened) {
263 driver->hsic_ch = 0;
264 driver->hsic_device_opened = 0;
265 diag_bridge_close();
266 err = diag_bridge_open(&hsic_diag_bridge_ops);
267 if (err) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700268 pr_err("diag: HSIC channel open error: %d\n",
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700269 err);
270 } else {
Dixon Peterson938f8602012-08-17 20:02:57 -0700271 pr_debug("diag: opened HSIC channel\n");
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700272 driver->hsic_device_opened = 1;
273 driver->hsic_ch = 1;
274 }
275 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800276 }
277
Jack Phamfbd22552012-09-07 17:29:08 -0700278 mutex_unlock(&driver->bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800279 return 0;
280}
281
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700282/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
283int diagfwd_connect_bridge(int process_cable)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800284{
285 int err;
286
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700287 pr_debug("diag: in %s\n", __func__);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800288
Jack Phamfbd22552012-09-07 17:29:08 -0700289 mutex_lock(&driver->bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700290 /* If the usb cable is being connected */
291 if (process_cable) {
292 err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
293 N_MDM_READ);
294 if (err)
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700295 pr_err("diag: unable to alloc USB req on mdm"
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700296 " ch err:%d\n", err);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800297
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700298 driver->usb_mdm_connected = 1;
299 }
300
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700301 if (driver->hsic_device_enabled) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700302 driver->in_busy_hsic_read_on_device = 0;
303 driver->in_busy_hsic_write = 0;
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700304 } else if (driver->diag_smux_enabled) {
305 driver->in_busy_smux = 0;
306 diagfwd_connect_smux();
Jack Phamfbd22552012-09-07 17:29:08 -0700307 mutex_unlock(&driver->bridge_mutex);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700308 return 0;
309 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800310
311 /* If the hsic (diag_bridge) platform device is not open */
312 if (driver->hsic_device_enabled) {
313 if (!driver->hsic_device_opened) {
314 err = diag_bridge_open(&hsic_diag_bridge_ops);
315 if (err) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700316 pr_err("diag: HSIC channel open error: %d\n",
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800317 err);
318 } else {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700319 pr_debug("diag: opened HSIC channel\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800320 driver->hsic_device_opened = 1;
321 }
322 } else {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700323 pr_debug("diag: HSIC channel already open\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800324 }
325
326 /*
327 * Turn on communication over usb mdm and hsic, if the hsic
328 * device driver is enabled and opened
329 */
Jack Phamfbd22552012-09-07 17:29:08 -0700330 if (driver->hsic_device_opened) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800331 driver->hsic_ch = 1;
332
Jack Phamfbd22552012-09-07 17:29:08 -0700333 /* Poll USB mdm channel to check for data */
334 if (driver->logging_mode == USB_MODE)
335 queue_work(driver->diag_bridge_wq,
336 &driver->diag_read_mdm_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800337
Jack Phamfbd22552012-09-07 17:29:08 -0700338 /* Poll HSIC channel to check for data */
339 queue_work(driver->diag_bridge_wq,
340 &driver->diag_read_hsic_work);
341 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800342 } else {
343 /* The hsic device driver has not yet been enabled */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700344 pr_info("diag: HSIC channel not yet enabled\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800345 }
346
Jack Phamfbd22552012-09-07 17:29:08 -0700347 mutex_unlock(&driver->bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800348 return 0;
349}
350
351/*
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700352 * diagfwd_disconnect_bridge is called when the USB mdm channel
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800353 * is disconnected
354 */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700355int diagfwd_disconnect_bridge(int process_cable)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800356{
Dixon Peterson938f8602012-08-17 20:02:57 -0700357 pr_debug("diag: In %s, process_cable: %d\n", __func__, process_cable);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800358
Jack Phamfbd22552012-09-07 17:29:08 -0700359 mutex_lock(&driver->bridge_mutex);
360
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700361 /* If the usb cable is being disconnected */
362 if (process_cable) {
363 driver->usb_mdm_connected = 0;
364 usb_diag_free_req(driver->mdm_ch);
365 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800366
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700367 if (driver->hsic_device_enabled &&
368 driver->logging_mode != MEMORY_DEVICE_MODE) {
369 driver->in_busy_hsic_read_on_device = 1;
370 driver->in_busy_hsic_write = 1;
371 /* Turn off communication over usb mdm and hsic */
Jack Phamfbd22552012-09-07 17:29:08 -0700372 diag_hsic_close();
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700373 } else if (driver->diag_smux_enabled &&
374 driver->logging_mode == USB_MODE) {
375 driver->in_busy_smux = 1;
376 driver->lcid = LCID_INVALID;
377 driver->smux_connected = 0;
378 /* Turn off communication over usb mdm and smux */
379 msm_smux_close(LCID_VALID);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700380 }
Jack Phamfbd22552012-09-07 17:29:08 -0700381
382 mutex_unlock(&driver->bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700383 return 0;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800384}
385
386/*
387 * diagfwd_write_complete_hsic is called after the asynchronous
388 * usb_diag_write() on mdm channel is complete
389 */
Dixon Peterson938f8602012-08-17 20:02:57 -0700390int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800391{
Dixon Peterson938f8602012-08-17 20:02:57 -0700392 unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
393
394 if (buf) {
395 /* Return buffers to their pools */
396 diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HSIC);
397 diagmem_free(driver, (unsigned char *)diag_write_ptr,
398 POOL_TYPE_HSIC_WRITE);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800399 }
400
Dixon Peterson938f8602012-08-17 20:02:57 -0700401 if (!driver->hsic_ch) {
402 pr_err("diag: In %s: driver->hsic_ch == 0\n", __func__);
403 return 0;
404 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800405
406 /* Read data from the hsic */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700407 queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800408
409 return 0;
410}
411
412/* Called after the asychronous usb_diag_read() on mdm channel is complete */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700413static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800414{
415 /* The read of the usb driver on the mdm (not hsic) has completed */
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700416 driver->in_busy_hsic_read_on_device = 0;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800417 driver->read_len_mdm = diag_read_ptr->actual;
418
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700419 if (driver->diag_smux_enabled) {
420 diagfwd_read_complete_smux();
421 return 0;
422 }
423 /* If SMUX not enabled, check for HSIC */
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800424 if (!driver->hsic_ch) {
425 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
426 return 0;
427 }
428
429 /*
430 * The read of the usb driver on the mdm channel has completed.
431 * If there is no write on the hsic in progress, check if the
432 * read has data to pass on to the hsic. If so, pass the usb
433 * mdm data on to the hsic.
434 */
435 if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
436 (driver->read_len_mdm > 0)) {
437
438 /*
439 * Initiate the hsic write. The hsic write is
440 * asynchronous. When complete the write
441 * complete callback function will be called
442 */
443 int err;
444 driver->in_busy_hsic_write = 1;
445 err = diag_bridge_write(driver->usb_buf_mdm_out,
446 driver->read_len_mdm);
447 if (err) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700448 pr_err_ratelimited("diag: mdm data on hsic write err: %d\n",
Jack Phamcca03322012-06-14 19:00:31 -0700449 err);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800450 /*
451 * If the error is recoverable, then clear
452 * the write flag, so we will resubmit a
453 * write on the next frame. Otherwise, don't
454 * resubmit a write on the next frame.
455 */
Jack Phamcca03322012-06-14 19:00:31 -0700456 if ((-ENODEV) != err)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800457 driver->in_busy_hsic_write = 0;
458 }
459 }
460
461 /*
462 * If there is no write of the usb mdm data on the
463 * hsic channel
464 */
Dixon Peterson70170f72012-11-05 20:25:11 -0800465 if (!driver->in_busy_hsic_write && (driver->logging_mode == USB_MODE))
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700466 queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800467
468 return 0;
469}
470
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700471static void diagfwd_bridge_notifier(void *priv, unsigned event,
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800472 struct diag_request *d_req)
473{
474 switch (event) {
475 case USB_DIAG_CONNECT:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700476 diagfwd_connect_bridge(1);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800477 break;
478 case USB_DIAG_DISCONNECT:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700479 queue_work(driver->diag_bridge_wq,
480 &driver->diag_disconnect_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800481 break;
482 case USB_DIAG_READ_DONE:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700483 queue_work(driver->diag_bridge_wq,
Jack Phamb60775a2012-02-14 17:57:41 -0800484 &driver->diag_usb_read_complete_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800485 break;
486 case USB_DIAG_WRITE_DONE:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700487 if (driver->hsic_device_enabled)
Dixon Peterson938f8602012-08-17 20:02:57 -0700488 diagfwd_write_complete_hsic(d_req);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700489 else if (driver->diag_smux_enabled)
490 diagfwd_write_complete_smux();
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800491 break;
492 default:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700493 pr_err("diag: in %s: Unknown event from USB diag:%u\n",
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800494 __func__, event);
495 break;
496 }
497}
498
Jack Phamb60775a2012-02-14 17:57:41 -0800499static void diag_usb_read_complete_fn(struct work_struct *w)
500{
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700501 diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
Jack Phamb60775a2012-02-14 17:57:41 -0800502}
503
504static void diag_disconnect_work_fn(struct work_struct *w)
505{
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700506 diagfwd_disconnect_bridge(1);
Jack Phamb60775a2012-02-14 17:57:41 -0800507}
508
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800509static void diag_read_mdm_work_fn(struct work_struct *work)
510{
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700511 int ret;
512 if (driver->diag_smux_enabled) {
513 if (driver->lcid && driver->usb_buf_mdm_out &&
Ashay Jaiswal2d8daae2012-07-17 17:29:33 +0530514 (driver->read_len_mdm > 0) &&
515 driver->smux_connected) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700516 ret = msm_smux_write(driver->lcid, NULL,
517 driver->usb_buf_mdm_out, driver->read_len_mdm);
518 if (ret)
519 pr_err("diag: writing to SMUX ch, r = %d,"
520 "lcid = %d\n", ret, driver->lcid);
521 }
522 driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
523 driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
524 usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
525 return;
526 }
527
528 /* if SMUX not enabled, check for HSIC */
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800529 if (!driver->hsic_ch) {
530 pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
531 return;
532 }
533
534 /*
535 * If there is no data being read from the usb mdm channel
536 * and there is no mdm channel data currently being written
537 * to the hsic
538 */
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700539 if (!driver->in_busy_hsic_read_on_device &&
540 !driver->in_busy_hsic_write) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800541 APPEND_DEBUG('x');
542
543 /* Setup the next read from usb mdm channel */
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700544 driver->in_busy_hsic_read_on_device = 1;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800545 driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
546 driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
547 usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
548 APPEND_DEBUG('y');
549 }
550
551 /*
552 * If for some reason there was no mdm channel read initiated,
553 * queue up the reading of data from the mdm channel
554 */
Dixon Peterson70170f72012-11-05 20:25:11 -0800555 if (!driver->in_busy_hsic_read_on_device &&
556 (driver->logging_mode == USB_MODE))
557 queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800558}
559
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700560static int diag_hsic_probe(struct platform_device *pdev)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800561{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700562 int err = 0;
563 pr_debug("diag: in %s\n", __func__);
Jack Phamfbd22552012-09-07 17:29:08 -0700564 if (!driver->hsic_inited) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700565 diagmem_hsic_init(driver);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700566 INIT_WORK(&(driver->diag_read_hsic_work),
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700567 diag_read_hsic_work_fn);
Jack Phamfbd22552012-09-07 17:29:08 -0700568 driver->hsic_inited = 1;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700569 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800570
Jack Phamfbd22552012-09-07 17:29:08 -0700571 mutex_lock(&driver->bridge_mutex);
572
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700573 /*
574 * The probe function was called after the usb was connected
575 * on the legacy channel OR ODL is turned on. Communication over usb
576 * mdm and hsic needs to be turned on.
577 */
578 if (driver->usb_mdm_connected || (driver->logging_mode ==
579 MEMORY_DEVICE_MODE)) {
Jack Phamfbd22552012-09-07 17:29:08 -0700580 if (driver->hsic_device_opened) {
581 /* should not happen. close it before re-opening */
582 pr_warn("diag: HSIC channel already opened in probe\n");
583 diag_bridge_close();
584 }
585
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700586 err = diag_bridge_open(&hsic_diag_bridge_ops);
587 if (err) {
588 pr_err("diag: could not open HSIC, err: %d\n", err);
589 driver->hsic_device_opened = 0;
Jack Phamfbd22552012-09-07 17:29:08 -0700590 mutex_unlock(&driver->bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700591 return err;
592 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800593
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700594 pr_info("diag: opened HSIC channel\n");
595 driver->hsic_device_opened = 1;
596 driver->hsic_ch = 1;
Dixon Peterson938f8602012-08-17 20:02:57 -0700597
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700598 driver->in_busy_hsic_read_on_device = 0;
599 driver->in_busy_hsic_write = 0;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700600
601 if (driver->usb_mdm_connected) {
602 /* Poll USB mdm channel to check for data */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700603 queue_work(driver->diag_bridge_wq,
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700604 &driver->diag_read_mdm_work);
605 }
606
607 /* Poll HSIC channel to check for data */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700608 queue_work(driver->diag_bridge_wq,
609 &driver->diag_read_hsic_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700610 }
611
Jack Phamfbd22552012-09-07 17:29:08 -0700612 /* The hsic (diag_bridge) platform device driver is enabled */
613 driver->hsic_device_enabled = 1;
614 mutex_unlock(&driver->bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700615 return err;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800616}
617
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800618static int diag_hsic_remove(struct platform_device *pdev)
619{
Dixon Peterson938f8602012-08-17 20:02:57 -0700620 pr_debug("diag: %s called\n", __func__);
Jack Phamfbd22552012-09-07 17:29:08 -0700621 mutex_lock(&driver->bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800622 diag_hsic_close();
Jack Phamfbd22552012-09-07 17:29:08 -0700623 driver->hsic_device_enabled = 0;
624 mutex_unlock(&driver->bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800625 return 0;
626}
627
628static int diagfwd_hsic_runtime_suspend(struct device *dev)
629{
630 dev_dbg(dev, "pm_runtime: suspending...\n");
631 return 0;
632}
633
634static int diagfwd_hsic_runtime_resume(struct device *dev)
635{
636 dev_dbg(dev, "pm_runtime: resuming...\n");
637 return 0;
638}
639
640static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
641 .runtime_suspend = diagfwd_hsic_runtime_suspend,
642 .runtime_resume = diagfwd_hsic_runtime_resume,
643};
644
645static struct platform_driver msm_hsic_ch_driver = {
646 .probe = diag_hsic_probe,
647 .remove = diag_hsic_remove,
648 .driver = {
649 .name = "diag_bridge",
650 .owner = THIS_MODULE,
651 .pm = &diagfwd_hsic_dev_pm_ops,
652 },
653};
654
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700655void diagfwd_bridge_init(void)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800656{
657 int ret;
658
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700659 pr_debug("diag: in %s\n", __func__);
660 driver->diag_bridge_wq = create_singlethread_workqueue(
661 "diag_bridge_wq");
662 driver->read_len_mdm = 0;
Dixon Peterson938f8602012-08-17 20:02:57 -0700663 driver->write_len_mdm = 0;
664 driver->num_hsic_buf_tbl_entries = 0;
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700665 spin_lock_init(&driver->hsic_spinlock);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700666 if (driver->usb_buf_mdm_out == NULL)
667 driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
668 GFP_KERNEL);
669 if (driver->usb_buf_mdm_out == NULL)
670 goto err;
Dixon Peterson938f8602012-08-17 20:02:57 -0700671 /* Only used by smux move to smux probe function */
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700672 if (driver->write_ptr_mdm == NULL)
673 driver->write_ptr_mdm = kzalloc(
674 sizeof(struct diag_request), GFP_KERNEL);
675 if (driver->write_ptr_mdm == NULL)
676 goto err;
677 if (driver->usb_read_mdm_ptr == NULL)
678 driver->usb_read_mdm_ptr = kzalloc(
679 sizeof(struct diag_request), GFP_KERNEL);
680 if (driver->usb_read_mdm_ptr == NULL)
681 goto err;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800682
Dixon Peterson938f8602012-08-17 20:02:57 -0700683 if (driver->hsic_buf_tbl == NULL)
684 driver->hsic_buf_tbl = kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
685 sizeof(struct diag_write_device), GFP_KERNEL);
686 if (driver->hsic_buf_tbl == NULL)
687 goto err;
688
689 driver->count_hsic_pool = 0;
690 driver->count_hsic_write_pool = 0;
691
692 driver->itemsize_hsic = READ_HSIC_BUF_SIZE;
693 driver->poolsize_hsic = N_MDM_WRITE;
694 driver->itemsize_hsic_write = sizeof(struct diag_request);
695 driver->poolsize_hsic_write = N_MDM_WRITE;
696
Jack Phamfbd22552012-09-07 17:29:08 -0700697 mutex_init(&driver->bridge_mutex);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700698#ifdef CONFIG_DIAG_OVER_USB
699 INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
700#endif
Jack Phamb60775a2012-02-14 17:57:41 -0800701 INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
702 INIT_WORK(&(driver->diag_usb_read_complete_work),
703 diag_usb_read_complete_fn);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800704#ifdef CONFIG_DIAG_OVER_USB
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700705 driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
706 diagfwd_bridge_notifier);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800707 if (IS_ERR(driver->mdm_ch)) {
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700708 pr_err("diag: Unable to open USB diag MDM channel\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800709 goto err;
710 }
711#endif
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700712 /* register HSIC device */
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800713 ret = platform_driver_register(&msm_hsic_ch_driver);
714 if (ret)
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700715 pr_err("diag: could not register HSIC device, ret: %d\n", ret);
716 /* register SMUX device */
717 ret = platform_driver_register(&msm_diagfwd_smux_driver);
718 if (ret)
719 pr_err("diag: could not register SMUX device, ret: %d\n", ret);
Dixon Peterson938f8602012-08-17 20:02:57 -0700720
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800721 return;
722err:
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700723 pr_err("diag: Could not initialize for bridge forwarding\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800724 kfree(driver->usb_buf_mdm_out);
Dixon Peterson938f8602012-08-17 20:02:57 -0700725 kfree(driver->hsic_buf_tbl);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800726 kfree(driver->write_ptr_mdm);
727 kfree(driver->usb_read_mdm_ptr);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700728 if (driver->diag_bridge_wq)
729 destroy_workqueue(driver->diag_bridge_wq);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800730
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700731 return;
732}
733
734void diagfwd_bridge_exit(void)
735{
736 pr_debug("diag: in %s\n", __func__);
737
738 if (driver->hsic_device_enabled) {
739 diag_hsic_close();
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700740 driver->hsic_device_enabled = 0;
741 }
Jack Phamfbd22552012-09-07 17:29:08 -0700742 driver->hsic_inited = 0;
743 diagmem_exit(driver, POOL_TYPE_ALL);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700744 if (driver->diag_smux_enabled) {
745 driver->lcid = LCID_INVALID;
746 kfree(driver->buf_in_smux);
747 driver->diag_smux_enabled = 0;
748 }
749 platform_driver_unregister(&msm_hsic_ch_driver);
750 platform_driver_unregister(&msm_diagfwd_smux_driver);
751 /* destroy USB MDM specific variables */
752#ifdef CONFIG_DIAG_OVER_USB
753 if (driver->usb_mdm_connected)
754 usb_diag_free_req(driver->mdm_ch);
755 usb_diag_close(driver->mdm_ch);
756#endif
757 kfree(driver->usb_buf_mdm_out);
Dixon Peterson938f8602012-08-17 20:02:57 -0700758 kfree(driver->hsic_buf_tbl);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700759 kfree(driver->write_ptr_mdm);
760 kfree(driver->usb_read_mdm_ptr);
761 destroy_workqueue(driver->diag_bridge_wq);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800762}