blob: 616c49881eb3080beaead2a2512aa638bf285614 [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 Petersonf79b66f2012-04-26 13:21:26 -0700230 /* Don't allow suspend if in MEMORY_DEVICE_MODE */
231 if (driver->logging_mode == MEMORY_DEVICE_MODE)
232 return -EBUSY;
233
Shalabh Jainb0037c02013-01-18 12:47:40 -0800234 diag_hsic[index].hsic_suspend = 1;
Jack Phamb60775a2012-02-14 17:57:41 -0800235
236 return 0;
237}
238
239static void diag_hsic_resume(void *ctxt)
240{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800241 int index = (int)ctxt;
Jack Phamb60775a2012-02-14 17:57:41 -0800242
Shalabh Jainb0037c02013-01-18 12:47:40 -0800243 pr_debug("diag: hsic_resume\n");
244 diag_hsic[index].hsic_suspend = 0;
245
246 if ((diag_hsic[index].count_hsic_pool <
247 diag_hsic[index].poolsize_hsic) &&
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700248 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
Shalabh Jainb0037c02013-01-18 12:47:40 -0800249 (diag_bridge[index].usb_connected)))
250 queue_work(diag_bridge[index].wq,
251 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800252}
253
Shalabh Jainb0037c02013-01-18 12:47:40 -0800254struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH] = {
255 {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800256 .ctxt = NULL,
257 .read_complete_cb = diag_hsic_read_complete_callback,
258 .write_complete_cb = diag_hsic_write_complete_callback,
Jack Phamb60775a2012-02-14 17:57:41 -0800259 .suspend = diag_hsic_suspend,
260 .resume = diag_hsic_resume,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800261 },
262 {
263 .ctxt = NULL,
264 .read_complete_cb = diag_hsic_read_complete_callback,
265 .write_complete_cb = diag_hsic_write_complete_callback,
266 .suspend = diag_hsic_suspend,
267 .resume = diag_hsic_resume,
268 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800269};
270
Shalabh Jainb0037c02013-01-18 12:47:40 -0800271void diag_hsic_close(int ch_id)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800272{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800273 if (diag_hsic[ch_id].hsic_device_enabled) {
274 diag_hsic[ch_id].hsic_ch = 0;
275 if (diag_hsic[ch_id].hsic_device_opened) {
276 diag_hsic[ch_id].hsic_device_opened = 0;
277 diag_bridge_close(ch_id);
278 pr_debug("diag: %s: closed successfully ch %d\n",
279 __func__, ch_id);
Jack Phamfbd22552012-09-07 17:29:08 -0700280 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800281 pr_debug("diag: %s: already closed ch %d\n",
282 __func__, ch_id);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800283 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800284 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800285 pr_debug("diag: %s: HSIC device already removed ch %d\n",
286 __func__, ch_id);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700287 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700288}
289
290/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
291int diagfwd_cancel_hsic(void)
292{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800293 int err, i;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700294
Shalabh Jainb0037c02013-01-18 12:47:40 -0800295 /* Cancel it for all active HSIC bridges */
296 for (i = 0; i < MAX_HSIC_CH; i++) {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800297 if (!diag_bridge[i].enabled)
298 continue;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800299 mutex_lock(&diag_bridge[i].bridge_mutex);
300 if (diag_hsic[i].hsic_device_enabled) {
301 if (diag_hsic[i].hsic_device_opened) {
302 diag_hsic[i].hsic_ch = 0;
303 diag_hsic[i].hsic_device_opened = 0;
304 diag_bridge_close(i);
305 hsic_diag_bridge_ops[i].ctxt = (void *)(i);
306 err = diag_bridge_open(i,
307 &hsic_diag_bridge_ops[i]);
308 if (err) {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800309 pr_err("diag: HSIC %d channel open error: %d\n",
310 i, err);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800311 } else {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800312 pr_debug("diag: opened HSIC channel: %d\n",
313 i);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800314 diag_hsic[i].hsic_device_opened = 1;
315 diag_hsic[i].hsic_ch = 1;
316 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700317 }
318 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800319 mutex_unlock(&diag_bridge[i].bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800320 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700321 return 0;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800322}
323
324/*
325 * diagfwd_write_complete_hsic is called after the asynchronous
326 * usb_diag_write() on mdm channel is complete
327 */
Dixon Petersonf90f3582013-01-26 18:14:17 -0800328int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr, int index)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800329{
Dixon Peterson938f8602012-08-17 20:02:57 -0700330 unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
331
332 if (buf) {
333 /* Return buffers to their pools */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800334 diagmem_free(driver, (unsigned char *)buf, index +
335 POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700336 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800337 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700338 POOL_TYPE_HSIC_WRITE);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800339 }
340
Shalabh Jainb0037c02013-01-18 12:47:40 -0800341 if (!diag_hsic[index].hsic_ch) {
342 pr_err("diag: In %s: hsic_ch == 0\n", __func__);
Dixon Peterson938f8602012-08-17 20:02:57 -0700343 return 0;
344 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800345
Shalabh Jain737fca72012-11-14 21:53:43 -0800346 /* Read data from the HSIC */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800347 queue_work(diag_bridge[index].wq,
348 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800349
350 return 0;
351}
352
Shalabh Jain737fca72012-11-14 21:53:43 -0800353void diag_usb_read_complete_hsic_fn(struct work_struct *w)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800354{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800355 struct diag_bridge_dev *bridge_struct = container_of(w,
356 struct diag_bridge_dev, usb_read_complete_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800357
Shalabh Jainb0037c02013-01-18 12:47:40 -0800358 diagfwd_read_complete_bridge(
359 diag_bridge[bridge_struct->id].usb_read_ptr);
360}
Shalabh Jain737fca72012-11-14 21:53:43 -0800361
362void diag_read_usb_hsic_work_fn(struct work_struct *work)
363{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800364 struct diag_bridge_dev *bridge_struct = container_of(work,
365 struct diag_bridge_dev, diag_read_work);
366 int index = bridge_struct->id;
367
368 if (!diag_hsic[index].hsic_ch) {
369 pr_err("diag: in %s: hsic_ch == 0\n", __func__);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700370 return;
371 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800372 /*
373 * If there is no data being read from the usb mdm channel
374 * and there is no mdm channel data currently being written
Shalabh Jain737fca72012-11-14 21:53:43 -0800375 * to the HSIC
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800376 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800377 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
378 !diag_hsic[index].in_busy_hsic_write) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800379 APPEND_DEBUG('x');
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800380 /* Setup the next read from usb mdm channel */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800381 diag_hsic[index].in_busy_hsic_read_on_device = 1;
382 diag_bridge[index].usb_read_ptr->buf =
383 diag_bridge[index].usb_buf_out;
384 diag_bridge[index].usb_read_ptr->length = USB_MAX_OUT_BUF;
385 diag_bridge[index].usb_read_ptr->context = (void *)index;
386 usb_diag_read(diag_bridge[index].ch,
387 diag_bridge[index].usb_read_ptr);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800388 APPEND_DEBUG('y');
389 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800390 /* If for some reason there was no mdm channel read initiated,
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800391 * queue up the reading of data from the mdm channel
392 */
Shalabh Jain737fca72012-11-14 21:53:43 -0800393
Shalabh Jainb0037c02013-01-18 12:47:40 -0800394 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
Dixon Peterson70170f72012-11-05 20:25:11 -0800395 (driver->logging_mode == USB_MODE))
Shalabh Jainb0037c02013-01-18 12:47:40 -0800396 queue_work(diag_bridge[index].wq,
397 &(diag_bridge[index].diag_read_work));
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800398}
399
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700400static int diag_hsic_probe(struct platform_device *pdev)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800401{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700402 int err = 0;
Shalabh Jain737fca72012-11-14 21:53:43 -0800403
Shalabh Jainb0037c02013-01-18 12:47:40 -0800404 /* pdev->Id will indicate which HSIC is working. 0 stands for HSIC
405 * or CP1 1 indicates HS-USB or CP2
406 */
407 pr_debug("diag: in %s, ch = %d\n", __func__, pdev->id);
408 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
409 if (!diag_hsic[pdev->id].hsic_inited) {
410 spin_lock_init(&diag_hsic[pdev->id].hsic_spinlock);
411 diag_hsic[pdev->id].num_hsic_buf_tbl_entries = 0;
412 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL)
413 diag_hsic[pdev->id].hsic_buf_tbl =
414 kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
415 sizeof(struct diag_write_device), GFP_KERNEL);
416 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL) {
417 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Shalabh Jain737fca72012-11-14 21:53:43 -0800418 return -ENOMEM;
419 }
Dixon Petersonf90f3582013-01-26 18:14:17 -0800420 diag_hsic[pdev->id].id = pdev->id;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800421 diag_hsic[pdev->id].count_hsic_pool = 0;
422 diag_hsic[pdev->id].count_hsic_write_pool = 0;
423 diag_hsic[pdev->id].itemsize_hsic = READ_HSIC_BUF_SIZE;
424 diag_hsic[pdev->id].poolsize_hsic = N_MDM_WRITE;
425 diag_hsic[pdev->id].itemsize_hsic_write =
426 sizeof(struct diag_request);
427 diag_hsic[pdev->id].poolsize_hsic_write = N_MDM_WRITE;
428 diagmem_hsic_init(pdev->id);
429 INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work),
Shalabh Jain737fca72012-11-14 21:53:43 -0800430 diag_read_hsic_work_fn);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800431 diag_hsic[pdev->id].hsic_inited = 1;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700432 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700433 /*
434 * The probe function was called after the usb was connected
435 * on the legacy channel OR ODL is turned on. Communication over usb
Shalabh Jain737fca72012-11-14 21:53:43 -0800436 * mdm and HSIC needs to be turned on.
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700437 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800438 if (diag_bridge[pdev->id].usb_connected || (driver->logging_mode ==
Shalabh Jain737fca72012-11-14 21:53:43 -0800439 MEMORY_DEVICE_MODE)) {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800440 if (diag_hsic[pdev->id].hsic_device_opened) {
Jack Phamfbd22552012-09-07 17:29:08 -0700441 /* should not happen. close it before re-opening */
442 pr_warn("diag: HSIC channel already opened in probe\n");
Shalabh Jainb0037c02013-01-18 12:47:40 -0800443 diag_bridge_close(pdev->id);
Jack Phamfbd22552012-09-07 17:29:08 -0700444 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800445 hsic_diag_bridge_ops[pdev->id].ctxt = (void *)(pdev->id);
446 err = diag_bridge_open(pdev->id,
447 &hsic_diag_bridge_ops[pdev->id]);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700448 if (err) {
449 pr_err("diag: could not open HSIC, err: %d\n", err);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800450 diag_hsic[pdev->id].hsic_device_opened = 0;
451 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700452 return err;
453 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800454
Shalabh Jainb0037c02013-01-18 12:47:40 -0800455 pr_info("diag: opened HSIC bridge, ch = %d\n", pdev->id);
456 diag_hsic[pdev->id].hsic_device_opened = 1;
457 diag_hsic[pdev->id].hsic_ch = 1;
458 diag_hsic[pdev->id].in_busy_hsic_read_on_device = 0;
459 diag_hsic[pdev->id].in_busy_hsic_write = 0;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700460
Shalabh Jainb0037c02013-01-18 12:47:40 -0800461 if (diag_bridge[pdev->id].usb_connected) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700462 /* Poll USB mdm channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800463 queue_work(diag_bridge[pdev->id].wq,
464 &diag_bridge[pdev->id].diag_read_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700465 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700466 /* Poll HSIC channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800467 queue_work(diag_bridge[pdev->id].wq,
468 &diag_hsic[pdev->id].diag_read_hsic_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700469 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800470 /* The HSIC (diag_bridge) platform device driver is enabled */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800471 diag_hsic[pdev->id].hsic_device_enabled = 1;
472 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700473 return err;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800474}
475
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800476static int diag_hsic_remove(struct platform_device *pdev)
477{
Dixon Peterson938f8602012-08-17 20:02:57 -0700478 pr_debug("diag: %s called\n", __func__);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800479 if (diag_hsic[pdev->id].hsic_device_enabled) {
480 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
481 diag_hsic_close(pdev->id);
482 diag_hsic[pdev->id].hsic_device_enabled = 0;
483 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
484 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800485
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800486 return 0;
487}
488
489static int diagfwd_hsic_runtime_suspend(struct device *dev)
490{
491 dev_dbg(dev, "pm_runtime: suspending...\n");
492 return 0;
493}
494
495static int diagfwd_hsic_runtime_resume(struct device *dev)
496{
497 dev_dbg(dev, "pm_runtime: resuming...\n");
498 return 0;
499}
500
501static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
502 .runtime_suspend = diagfwd_hsic_runtime_suspend,
503 .runtime_resume = diagfwd_hsic_runtime_resume,
504};
505
Shalabh Jain737fca72012-11-14 21:53:43 -0800506struct platform_driver msm_hsic_ch_driver = {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800507 .probe = diag_hsic_probe,
508 .remove = diag_hsic_remove,
509 .driver = {
510 .name = "diag_bridge",
511 .owner = THIS_MODULE,
512 .pm = &diagfwd_hsic_dev_pm_ops,
513 },
514};