blob: fa46aab50e8fb9450c5a85e425f62ce870d47b2d [file] [log] [blame]
Shalabh Jainb0037c02013-01-18 12:47:40 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Dixon Peterson32e70bb2011-12-16 13:26:45 -08002 *
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"
Shalabh Jain737fca72012-11-14 21:53:43 -080034#include "diagfwd_bridge.h"
Dixon Peterson32e70bb2011-12-16 13:26:45 -080035
Dixon Peterson938f8602012-08-17 20:02:57 -070036#define READ_HSIC_BUF_SIZE 2048
Shalabh Jainb0037c02013-01-18 12:47:40 -080037struct diag_hsic_dev *diag_hsic;
Dixon Peterson938f8602012-08-17 20:02:57 -070038
Dixon Peterson32e70bb2011-12-16 13:26:45 -080039static void diag_read_hsic_work_fn(struct work_struct *work)
40{
Dixon Peterson938f8602012-08-17 20:02:57 -070041 unsigned char *buf_in_hsic = NULL;
42 int num_reads_submitted = 0;
43 int err = 0;
44 int write_ptrs_available;
Shalabh Jainb0037c02013-01-18 12:47:40 -080045 struct diag_hsic_dev *hsic_struct = container_of(work,
46 struct diag_hsic_dev, diag_read_hsic_work);
47 int index = hsic_struct->id;
Ravi Aravamudhanb1faa192013-02-22 10:09:19 -080048 static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
Dixon Peterson938f8602012-08-17 20:02:57 -070049
Shalabh Jainb0037c02013-01-18 12:47:40 -080050 if (!diag_hsic[index].hsic_ch) {
51 pr_err("DIAG in %s: diag_hsic[index].hsic_ch == 0\n", __func__);
Dixon Peterson32e70bb2011-12-16 13:26:45 -080052 return;
53 }
54
Dixon Peterson938f8602012-08-17 20:02:57 -070055 /*
56 * Determine the current number of available buffers for writing after
57 * reading from the HSIC has completed.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080058 */
Dixon Peterson938f8602012-08-17 20:02:57 -070059 if (driver->logging_mode == MEMORY_DEVICE_MODE)
Shalabh Jainb0037c02013-01-18 12:47:40 -080060 write_ptrs_available = diag_hsic[index].poolsize_hsic_write -
61 diag_hsic[index].
62 num_hsic_buf_tbl_entries;
Dixon Peterson938f8602012-08-17 20:02:57 -070063 else
Shalabh Jainb0037c02013-01-18 12:47:40 -080064 write_ptrs_available = diag_hsic[index].poolsize_hsic_write -
65 diag_hsic[index].count_hsic_write_pool;
Dixon Peterson32e70bb2011-12-16 13:26:45 -080066
67 /*
Dixon Peterson938f8602012-08-17 20:02:57 -070068 * Queue up a read on the HSIC for all available buffers in the
69 * pool, exhausting the pool.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080070 */
Dixon Peterson938f8602012-08-17 20:02:57 -070071 do {
72 /*
73 * If no more write buffers are available,
74 * stop queuing reads
75 */
76 if (write_ptrs_available <= 0)
77 break;
78
79 write_ptrs_available--;
80
Dixon Peterson6beff2d2012-09-13 18:51:47 -070081 /*
Shalabh Jain737fca72012-11-14 21:53:43 -080082 * No sense queuing a read if the HSIC bridge was
Dixon Peterson6beff2d2012-09-13 18:51:47 -070083 * closed in another thread
84 */
Shalabh Jainb0037c02013-01-18 12:47:40 -080085 if (!diag_hsic[index].hsic_ch)
Dixon Peterson6beff2d2012-09-13 18:51:47 -070086 break;
87
Dixon Peterson938f8602012-08-17 20:02:57 -070088 buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
Shalabh Jainb0037c02013-01-18 12:47:40 -080089 index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -070090 if (buf_in_hsic) {
91 /*
Shalabh Jain737fca72012-11-14 21:53:43 -080092 * Initiate the read from the HSIC. The HSIC read is
Dixon Peterson938f8602012-08-17 20:02:57 -070093 * asynchronous. Once the read is complete the read
94 * callback function will be called.
95 */
Dixon Peterson938f8602012-08-17 20:02:57 -070096 pr_debug("diag: read from HSIC\n");
97 num_reads_submitted++;
Shalabh Jainb0037c02013-01-18 12:47:40 -080098 err = diag_bridge_read(index, (char *)buf_in_hsic,
Dixon Peterson938f8602012-08-17 20:02:57 -070099 READ_HSIC_BUF_SIZE);
100 if (err) {
101 num_reads_submitted--;
102
103 /* Return the buffer to the pool */
104 diagmem_free(driver, buf_in_hsic,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800105 index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700106
Ravi Aravamudhanb1faa192013-02-22 10:09:19 -0800107 if (__ratelimit(&rl))
108 pr_err("diag: Error initiating HSIC read, err: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700109 err);
110 /*
111 * An error occurred, discontinue queuing
112 * reads
113 */
114 break;
115 }
116 }
117 } while (buf_in_hsic);
118
119 /*
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700120 * If there are read buffers available and for some reason the
121 * read was not queued, and if no unrecoverable error occurred
Dixon Peterson938f8602012-08-17 20:02:57 -0700122 * (-ENODEV is an unrecoverable error), then set up the next read
123 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800124 if ((diag_hsic[index].count_hsic_pool <
125 diag_hsic[index].poolsize_hsic) &&
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700126 (num_reads_submitted == 0) && (err != -ENODEV) &&
Shalabh Jainb0037c02013-01-18 12:47:40 -0800127 (diag_hsic[index].hsic_ch != 0))
128 queue_work(diag_bridge[index].wq,
129 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800130}
131
132static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
133 int buf_size, int actual_size)
134{
Dixon Peterson938f8602012-08-17 20:02:57 -0700135 int err = -2;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800136 int index = (int)ctxt;
Ravi Aravamudhanb1faa192013-02-22 10:09:19 -0800137 static DEFINE_RATELIMIT_STATE(rl, 10*HZ, 1);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800138
Shalabh Jainb0037c02013-01-18 12:47:40 -0800139 if (!diag_hsic[index].hsic_ch) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700140 /*
Shalabh Jain737fca72012-11-14 21:53:43 -0800141 * The HSIC channel is closed. Return the buffer to
Dixon Peterson938f8602012-08-17 20:02:57 -0700142 * the pool. Do not send it on.
143 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800144 diagmem_free(driver, buf, index+POOL_TYPE_HSIC);
145 pr_debug("diag: In %s: hsic_ch == 0, actual_size: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700146 __func__, actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800147 return;
148 }
149
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700150 /*
151 * Note that zero length is valid and still needs to be sent to
152 * the USB only when we are logging data to the USB
153 */
154 if ((actual_size > 0) ||
155 ((actual_size == 0) && (driver->logging_mode == USB_MODE))) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800156 if (!buf) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700157 pr_err("diag: Out of diagmem for HSIC\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800158 } else {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800159 /*
Dixon Peterson938f8602012-08-17 20:02:57 -0700160 * Send data in buf to be written on the
161 * appropriate device, e.g. USB MDM channel
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800162 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800163 diag_bridge[index].write_len = actual_size;
164 err = diag_device_write((void *)buf, index+HSIC_DATA,
165 NULL);
Dixon Peterson938f8602012-08-17 20:02:57 -0700166 /* If an error, return buffer to the pool */
167 if (err) {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800168 diagmem_free(driver, buf, index +
169 POOL_TYPE_HSIC);
Ravi Aravamudhanb1faa192013-02-22 10:09:19 -0800170 if (__ratelimit(&rl))
171 pr_err("diag: In %s, error calling diag_device_write, err: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700172 __func__, err);
173 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800174 }
175 } else {
Dixon Peterson938f8602012-08-17 20:02:57 -0700176 /*
177 * The buffer has an error status associated with it. Do not
178 * pass it on. Note that -ENOENT is sent when the diag bridge
179 * is closed.
180 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800181 diagmem_free(driver, buf, index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700182 pr_debug("diag: In %s: error status: %d\n", __func__,
183 actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800184 }
185
186 /*
Shalabh Jain737fca72012-11-14 21:53:43 -0800187 * If for some reason there was no HSIC data to write to the
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800188 * mdm channel, set up another read
189 */
Dixon Peterson938f8602012-08-17 20:02:57 -0700190 if (err &&
191 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
Shalabh Jainb0037c02013-01-18 12:47:40 -0800192 (diag_bridge[index].usb_connected &&
193 !diag_hsic[index].hsic_suspend))) {
194 queue_work(diag_bridge[index].wq,
195 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson938f8602012-08-17 20:02:57 -0700196 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800197}
198
199static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
200 int buf_size, int actual_size)
201{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800202 int index = (int)ctxt;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800203
Shalabh Jainb0037c02013-01-18 12:47:40 -0800204 /* The write of the data to the HSIC bridge is complete */
205 diag_hsic[index].in_busy_hsic_write = 0;
206
207 if (!diag_hsic[index].hsic_ch) {
208 pr_err("DIAG in %s: hsic_ch == 0, ch = %d\n", __func__, index);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800209 return;
210 }
211
212 if (actual_size < 0)
213 pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
214
Shalabh Jainb0037c02013-01-18 12:47:40 -0800215 if (diag_bridge[index].usb_connected &&
Shalabh Jain737fca72012-11-14 21:53:43 -0800216 (driver->logging_mode == USB_MODE))
Shalabh Jainb0037c02013-01-18 12:47:40 -0800217 queue_work(diag_bridge[index].wq,
218 &diag_bridge[index].diag_read_work);
Jack Phamb60775a2012-02-14 17:57:41 -0800219}
220
221static int diag_hsic_suspend(void *ctxt)
222{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800223 int index = (int)ctxt;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700224 pr_debug("diag: hsic_suspend\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700225
226 /* Don't allow suspend if a write in the HSIC is in progress */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800227 if (diag_hsic[index].in_busy_hsic_write)
Jack Phamb60775a2012-02-14 17:57:41 -0800228 return -EBUSY;
229
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800230 /*
231 * Don't allow suspend if in MEMORY_DEVICE_MODE and if there
232 * has been hsic data requested
233 */
234 if (driver->logging_mode == MEMORY_DEVICE_MODE &&
235 diag_hsic[index].hsic_ch)
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700236 return -EBUSY;
237
Shalabh Jainb0037c02013-01-18 12:47:40 -0800238 diag_hsic[index].hsic_suspend = 1;
Jack Phamb60775a2012-02-14 17:57:41 -0800239
240 return 0;
241}
242
243static void diag_hsic_resume(void *ctxt)
244{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800245 int index = (int)ctxt;
Jack Phamb60775a2012-02-14 17:57:41 -0800246
Shalabh Jainb0037c02013-01-18 12:47:40 -0800247 pr_debug("diag: hsic_resume\n");
248 diag_hsic[index].hsic_suspend = 0;
249
250 if ((diag_hsic[index].count_hsic_pool <
251 diag_hsic[index].poolsize_hsic) &&
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700252 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
Shalabh Jainb0037c02013-01-18 12:47:40 -0800253 (diag_bridge[index].usb_connected)))
254 queue_work(diag_bridge[index].wq,
255 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800256}
257
Shalabh Jainb0037c02013-01-18 12:47:40 -0800258struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH] = {
259 {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800260 .ctxt = NULL,
261 .read_complete_cb = diag_hsic_read_complete_callback,
262 .write_complete_cb = diag_hsic_write_complete_callback,
Jack Phamb60775a2012-02-14 17:57:41 -0800263 .suspend = diag_hsic_suspend,
264 .resume = diag_hsic_resume,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800265 },
266 {
267 .ctxt = NULL,
268 .read_complete_cb = diag_hsic_read_complete_callback,
269 .write_complete_cb = diag_hsic_write_complete_callback,
270 .suspend = diag_hsic_suspend,
271 .resume = diag_hsic_resume,
272 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800273};
274
Shalabh Jainb0037c02013-01-18 12:47:40 -0800275void diag_hsic_close(int ch_id)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800276{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800277 if (diag_hsic[ch_id].hsic_device_enabled) {
278 diag_hsic[ch_id].hsic_ch = 0;
279 if (diag_hsic[ch_id].hsic_device_opened) {
280 diag_hsic[ch_id].hsic_device_opened = 0;
281 diag_bridge_close(ch_id);
282 pr_debug("diag: %s: closed successfully ch %d\n",
283 __func__, ch_id);
Jack Phamfbd22552012-09-07 17:29:08 -0700284 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800285 pr_debug("diag: %s: already closed ch %d\n",
286 __func__, ch_id);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800287 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800288 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800289 pr_debug("diag: %s: HSIC device already removed ch %d\n",
290 __func__, ch_id);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700291 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700292}
293
294/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800295int diagfwd_cancel_hsic(int reopen)
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700296{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800297 int err, i;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700298
Shalabh Jainb0037c02013-01-18 12:47:40 -0800299 /* Cancel it for all active HSIC bridges */
300 for (i = 0; i < MAX_HSIC_CH; i++) {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800301 if (!diag_bridge[i].enabled)
302 continue;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800303 mutex_lock(&diag_bridge[i].bridge_mutex);
304 if (diag_hsic[i].hsic_device_enabled) {
305 if (diag_hsic[i].hsic_device_opened) {
306 diag_hsic[i].hsic_ch = 0;
307 diag_hsic[i].hsic_device_opened = 0;
308 diag_bridge_close(i);
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800309 if (reopen) {
310 hsic_diag_bridge_ops[i].ctxt =
311 (void *)(i);
312 err = diag_bridge_open(i,
313 &hsic_diag_bridge_ops[i]);
314 if (err) {
315 pr_err("diag: HSIC %d channel open error: %d\n",
316 i, err);
317 } else {
318 pr_debug("diag: opened HSIC channel: %d\n",
319 i);
320 diag_hsic[i].
321 hsic_device_opened = 1;
322 diag_hsic[i].hsic_ch = 1;
323 }
324 diag_hsic[i].hsic_data_requested = 1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800325 } else {
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800326 diag_hsic[i].hsic_data_requested = 0;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800327 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700328 }
329 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800330 mutex_unlock(&diag_bridge[i].bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800331 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700332 return 0;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800333}
334
335/*
336 * diagfwd_write_complete_hsic is called after the asynchronous
337 * usb_diag_write() on mdm channel is complete
338 */
Dixon Petersonf90f3582013-01-26 18:14:17 -0800339int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr, int index)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800340{
Dixon Peterson938f8602012-08-17 20:02:57 -0700341 unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
342
343 if (buf) {
344 /* Return buffers to their pools */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800345 diagmem_free(driver, (unsigned char *)buf, index +
346 POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700347 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800348 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700349 POOL_TYPE_HSIC_WRITE);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800350 }
351
Shalabh Jainb0037c02013-01-18 12:47:40 -0800352 if (!diag_hsic[index].hsic_ch) {
353 pr_err("diag: In %s: hsic_ch == 0\n", __func__);
Dixon Peterson938f8602012-08-17 20:02:57 -0700354 return 0;
355 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800356
Shalabh Jain737fca72012-11-14 21:53:43 -0800357 /* Read data from the HSIC */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800358 queue_work(diag_bridge[index].wq,
359 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800360
361 return 0;
362}
363
Shalabh Jain737fca72012-11-14 21:53:43 -0800364void diag_usb_read_complete_hsic_fn(struct work_struct *w)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800365{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800366 struct diag_bridge_dev *bridge_struct = container_of(w,
367 struct diag_bridge_dev, usb_read_complete_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800368
Shalabh Jainb0037c02013-01-18 12:47:40 -0800369 diagfwd_read_complete_bridge(
370 diag_bridge[bridge_struct->id].usb_read_ptr);
371}
Shalabh Jain737fca72012-11-14 21:53:43 -0800372
373void diag_read_usb_hsic_work_fn(struct work_struct *work)
374{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800375 struct diag_bridge_dev *bridge_struct = container_of(work,
376 struct diag_bridge_dev, diag_read_work);
377 int index = bridge_struct->id;
378
379 if (!diag_hsic[index].hsic_ch) {
380 pr_err("diag: in %s: hsic_ch == 0\n", __func__);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700381 return;
382 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800383 /*
384 * If there is no data being read from the usb mdm channel
385 * and there is no mdm channel data currently being written
Shalabh Jain737fca72012-11-14 21:53:43 -0800386 * to the HSIC
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800387 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800388 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
389 !diag_hsic[index].in_busy_hsic_write) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800390 APPEND_DEBUG('x');
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800391 /* Setup the next read from usb mdm channel */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800392 diag_hsic[index].in_busy_hsic_read_on_device = 1;
393 diag_bridge[index].usb_read_ptr->buf =
394 diag_bridge[index].usb_buf_out;
395 diag_bridge[index].usb_read_ptr->length = USB_MAX_OUT_BUF;
396 diag_bridge[index].usb_read_ptr->context = (void *)index;
397 usb_diag_read(diag_bridge[index].ch,
398 diag_bridge[index].usb_read_ptr);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800399 APPEND_DEBUG('y');
400 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800401 /* If for some reason there was no mdm channel read initiated,
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800402 * queue up the reading of data from the mdm channel
403 */
Shalabh Jain737fca72012-11-14 21:53:43 -0800404
Shalabh Jainb0037c02013-01-18 12:47:40 -0800405 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
Dixon Peterson70170f72012-11-05 20:25:11 -0800406 (driver->logging_mode == USB_MODE))
Shalabh Jainb0037c02013-01-18 12:47:40 -0800407 queue_work(diag_bridge[index].wq,
408 &(diag_bridge[index].diag_read_work));
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800409}
410
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700411static int diag_hsic_probe(struct platform_device *pdev)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800412{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700413 int err = 0;
Shalabh Jain737fca72012-11-14 21:53:43 -0800414
Shalabh Jainb0037c02013-01-18 12:47:40 -0800415 /* pdev->Id will indicate which HSIC is working. 0 stands for HSIC
416 * or CP1 1 indicates HS-USB or CP2
417 */
418 pr_debug("diag: in %s, ch = %d\n", __func__, pdev->id);
419 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
420 if (!diag_hsic[pdev->id].hsic_inited) {
421 spin_lock_init(&diag_hsic[pdev->id].hsic_spinlock);
422 diag_hsic[pdev->id].num_hsic_buf_tbl_entries = 0;
423 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL)
424 diag_hsic[pdev->id].hsic_buf_tbl =
425 kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
426 sizeof(struct diag_write_device), GFP_KERNEL);
427 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL) {
428 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Shalabh Jain737fca72012-11-14 21:53:43 -0800429 return -ENOMEM;
430 }
Dixon Petersonf90f3582013-01-26 18:14:17 -0800431 diag_hsic[pdev->id].id = pdev->id;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800432 diag_hsic[pdev->id].count_hsic_pool = 0;
433 diag_hsic[pdev->id].count_hsic_write_pool = 0;
434 diag_hsic[pdev->id].itemsize_hsic = READ_HSIC_BUF_SIZE;
435 diag_hsic[pdev->id].poolsize_hsic = N_MDM_WRITE;
436 diag_hsic[pdev->id].itemsize_hsic_write =
437 sizeof(struct diag_request);
438 diag_hsic[pdev->id].poolsize_hsic_write = N_MDM_WRITE;
439 diagmem_hsic_init(pdev->id);
440 INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work),
Shalabh Jain737fca72012-11-14 21:53:43 -0800441 diag_read_hsic_work_fn);
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800442 diag_hsic[pdev->id].hsic_data_requested =
443 (driver->logging_mode == MEMORY_DEVICE_MODE) ? 0 : 1;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800444 diag_hsic[pdev->id].hsic_inited = 1;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700445 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700446 /*
447 * The probe function was called after the usb was connected
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800448 * on the legacy channel OR ODL is turned on and hsic data is
449 * requested. Communication over usb mdm and HSIC needs to be
450 * turned on.
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700451 */
Dixon Petersonf2d449c2013-02-01 18:02:20 -0800452 if ((diag_bridge[pdev->id].usb_connected &&
453 (driver->logging_mode != MEMORY_DEVICE_MODE)) ||
454 ((driver->logging_mode == MEMORY_DEVICE_MODE) &&
455 diag_hsic[pdev->id].hsic_data_requested)) {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800456 if (diag_hsic[pdev->id].hsic_device_opened) {
Jack Phamfbd22552012-09-07 17:29:08 -0700457 /* should not happen. close it before re-opening */
458 pr_warn("diag: HSIC channel already opened in probe\n");
Shalabh Jainb0037c02013-01-18 12:47:40 -0800459 diag_bridge_close(pdev->id);
Jack Phamfbd22552012-09-07 17:29:08 -0700460 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800461 hsic_diag_bridge_ops[pdev->id].ctxt = (void *)(pdev->id);
462 err = diag_bridge_open(pdev->id,
463 &hsic_diag_bridge_ops[pdev->id]);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700464 if (err) {
465 pr_err("diag: could not open HSIC, err: %d\n", err);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800466 diag_hsic[pdev->id].hsic_device_opened = 0;
467 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700468 return err;
469 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800470
Shalabh Jainb0037c02013-01-18 12:47:40 -0800471 pr_info("diag: opened HSIC bridge, ch = %d\n", pdev->id);
472 diag_hsic[pdev->id].hsic_device_opened = 1;
473 diag_hsic[pdev->id].hsic_ch = 1;
474 diag_hsic[pdev->id].in_busy_hsic_read_on_device = 0;
475 diag_hsic[pdev->id].in_busy_hsic_write = 0;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700476
Shalabh Jainb0037c02013-01-18 12:47:40 -0800477 if (diag_bridge[pdev->id].usb_connected) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700478 /* Poll USB mdm channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800479 queue_work(diag_bridge[pdev->id].wq,
480 &diag_bridge[pdev->id].diag_read_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700481 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700482 /* Poll HSIC channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800483 queue_work(diag_bridge[pdev->id].wq,
484 &diag_hsic[pdev->id].diag_read_hsic_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700485 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800486 /* The HSIC (diag_bridge) platform device driver is enabled */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800487 diag_hsic[pdev->id].hsic_device_enabled = 1;
488 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700489 return err;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800490}
491
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800492static int diag_hsic_remove(struct platform_device *pdev)
493{
Dixon Peterson938f8602012-08-17 20:02:57 -0700494 pr_debug("diag: %s called\n", __func__);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800495 if (diag_hsic[pdev->id].hsic_device_enabled) {
496 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
497 diag_hsic_close(pdev->id);
498 diag_hsic[pdev->id].hsic_device_enabled = 0;
499 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
500 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800501
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800502 return 0;
503}
504
505static int diagfwd_hsic_runtime_suspend(struct device *dev)
506{
507 dev_dbg(dev, "pm_runtime: suspending...\n");
508 return 0;
509}
510
511static int diagfwd_hsic_runtime_resume(struct device *dev)
512{
513 dev_dbg(dev, "pm_runtime: resuming...\n");
514 return 0;
515}
516
517static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
518 .runtime_suspend = diagfwd_hsic_runtime_suspend,
519 .runtime_resume = diagfwd_hsic_runtime_resume,
520};
521
Shalabh Jain737fca72012-11-14 21:53:43 -0800522struct platform_driver msm_hsic_ch_driver = {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800523 .probe = diag_hsic_probe,
524 .remove = diag_hsic_remove,
525 .driver = {
526 .name = "diag_bridge",
527 .owner = THIS_MODULE,
528 .pm = &diagfwd_hsic_dev_pm_ops,
529 },
530};