blob: aa55578fb5f410891fa4f439fbc366f7483589d6 [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;
Dixon Peterson938f8602012-08-17 20:02:57 -070048
Shalabh Jainb0037c02013-01-18 12:47:40 -080049 if (!diag_hsic[index].hsic_ch) {
50 pr_err("DIAG in %s: diag_hsic[index].hsic_ch == 0\n", __func__);
Dixon Peterson32e70bb2011-12-16 13:26:45 -080051 return;
52 }
53
Dixon Peterson938f8602012-08-17 20:02:57 -070054 /*
55 * Determine the current number of available buffers for writing after
56 * reading from the HSIC has completed.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080057 */
Dixon Peterson938f8602012-08-17 20:02:57 -070058 if (driver->logging_mode == MEMORY_DEVICE_MODE)
Shalabh Jainb0037c02013-01-18 12:47:40 -080059 write_ptrs_available = diag_hsic[index].poolsize_hsic_write -
60 diag_hsic[index].
61 num_hsic_buf_tbl_entries;
Dixon Peterson938f8602012-08-17 20:02:57 -070062 else
Shalabh Jainb0037c02013-01-18 12:47:40 -080063 write_ptrs_available = diag_hsic[index].poolsize_hsic_write -
64 diag_hsic[index].count_hsic_write_pool;
Dixon Peterson32e70bb2011-12-16 13:26:45 -080065
66 /*
Dixon Peterson938f8602012-08-17 20:02:57 -070067 * Queue up a read on the HSIC for all available buffers in the
68 * pool, exhausting the pool.
Dixon Peterson32e70bb2011-12-16 13:26:45 -080069 */
Dixon Peterson938f8602012-08-17 20:02:57 -070070 do {
71 /*
72 * If no more write buffers are available,
73 * stop queuing reads
74 */
75 if (write_ptrs_available <= 0)
76 break;
77
78 write_ptrs_available--;
79
Dixon Peterson6beff2d2012-09-13 18:51:47 -070080 /*
Shalabh Jain737fca72012-11-14 21:53:43 -080081 * No sense queuing a read if the HSIC bridge was
Dixon Peterson6beff2d2012-09-13 18:51:47 -070082 * closed in another thread
83 */
Shalabh Jainb0037c02013-01-18 12:47:40 -080084 if (!diag_hsic[index].hsic_ch)
Dixon Peterson6beff2d2012-09-13 18:51:47 -070085 break;
86
Dixon Peterson938f8602012-08-17 20:02:57 -070087 buf_in_hsic = diagmem_alloc(driver, READ_HSIC_BUF_SIZE,
Shalabh Jainb0037c02013-01-18 12:47:40 -080088 index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -070089 if (buf_in_hsic) {
90 /*
Shalabh Jain737fca72012-11-14 21:53:43 -080091 * Initiate the read from the HSIC. The HSIC read is
Dixon Peterson938f8602012-08-17 20:02:57 -070092 * asynchronous. Once the read is complete the read
93 * callback function will be called.
94 */
Dixon Peterson938f8602012-08-17 20:02:57 -070095 pr_debug("diag: read from HSIC\n");
96 num_reads_submitted++;
Shalabh Jainb0037c02013-01-18 12:47:40 -080097 err = diag_bridge_read(index, (char *)buf_in_hsic,
Dixon Peterson938f8602012-08-17 20:02:57 -070098 READ_HSIC_BUF_SIZE);
99 if (err) {
100 num_reads_submitted--;
101
102 /* Return the buffer to the pool */
103 diagmem_free(driver, buf_in_hsic,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800104 index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700105
106 pr_err_ratelimited("diag: Error initiating HSIC read, err: %d\n",
107 err);
108 /*
109 * An error occurred, discontinue queuing
110 * reads
111 */
112 break;
113 }
114 }
115 } while (buf_in_hsic);
116
117 /*
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700118 * If there are read buffers available and for some reason the
119 * read was not queued, and if no unrecoverable error occurred
Dixon Peterson938f8602012-08-17 20:02:57 -0700120 * (-ENODEV is an unrecoverable error), then set up the next read
121 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800122 if ((diag_hsic[index].count_hsic_pool <
123 diag_hsic[index].poolsize_hsic) &&
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700124 (num_reads_submitted == 0) && (err != -ENODEV) &&
Shalabh Jainb0037c02013-01-18 12:47:40 -0800125 (diag_hsic[index].hsic_ch != 0))
126 queue_work(diag_bridge[index].wq,
127 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800128}
129
130static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
131 int buf_size, int actual_size)
132{
Dixon Peterson938f8602012-08-17 20:02:57 -0700133 int err = -2;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800134 int index = (int)ctxt;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800135
Shalabh Jainb0037c02013-01-18 12:47:40 -0800136 if (!diag_hsic[index].hsic_ch) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700137 /*
Shalabh Jain737fca72012-11-14 21:53:43 -0800138 * The HSIC channel is closed. Return the buffer to
Dixon Peterson938f8602012-08-17 20:02:57 -0700139 * the pool. Do not send it on.
140 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800141 diagmem_free(driver, buf, index+POOL_TYPE_HSIC);
142 pr_debug("diag: In %s: hsic_ch == 0, actual_size: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700143 __func__, actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800144 return;
145 }
146
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700147 /*
148 * Note that zero length is valid and still needs to be sent to
149 * the USB only when we are logging data to the USB
150 */
151 if ((actual_size > 0) ||
152 ((actual_size == 0) && (driver->logging_mode == USB_MODE))) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800153 if (!buf) {
Dixon Peterson938f8602012-08-17 20:02:57 -0700154 pr_err("diag: Out of diagmem for HSIC\n");
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800155 } else {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800156 /*
Dixon Peterson938f8602012-08-17 20:02:57 -0700157 * Send data in buf to be written on the
158 * appropriate device, e.g. USB MDM channel
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800159 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800160 diag_bridge[index].write_len = actual_size;
161 err = diag_device_write((void *)buf, index+HSIC_DATA,
162 NULL);
Dixon Peterson938f8602012-08-17 20:02:57 -0700163 /* If an error, return buffer to the pool */
164 if (err) {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800165 diagmem_free(driver, buf, index +
166 POOL_TYPE_HSIC);
Dixon Peterson6beff2d2012-09-13 18:51:47 -0700167 pr_err_ratelimited("diag: In %s, error calling diag_device_write, err: %d\n",
Dixon Peterson938f8602012-08-17 20:02:57 -0700168 __func__, err);
169 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800170 }
171 } else {
Dixon Peterson938f8602012-08-17 20:02:57 -0700172 /*
173 * The buffer has an error status associated with it. Do not
174 * pass it on. Note that -ENOENT is sent when the diag bridge
175 * is closed.
176 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800177 diagmem_free(driver, buf, index+POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700178 pr_debug("diag: In %s: error status: %d\n", __func__,
179 actual_size);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800180 }
181
182 /*
Shalabh Jain737fca72012-11-14 21:53:43 -0800183 * If for some reason there was no HSIC data to write to the
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800184 * mdm channel, set up another read
185 */
Dixon Peterson938f8602012-08-17 20:02:57 -0700186 if (err &&
187 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
Shalabh Jainb0037c02013-01-18 12:47:40 -0800188 (diag_bridge[index].usb_connected &&
189 !diag_hsic[index].hsic_suspend))) {
190 queue_work(diag_bridge[index].wq,
191 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson938f8602012-08-17 20:02:57 -0700192 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800193}
194
195static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
196 int buf_size, int actual_size)
197{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800198 int index = (int)ctxt;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800199
Shalabh Jainb0037c02013-01-18 12:47:40 -0800200 /* The write of the data to the HSIC bridge is complete */
201 diag_hsic[index].in_busy_hsic_write = 0;
202
203 if (!diag_hsic[index].hsic_ch) {
204 pr_err("DIAG in %s: hsic_ch == 0, ch = %d\n", __func__, index);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800205 return;
206 }
207
208 if (actual_size < 0)
209 pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
210
Shalabh Jainb0037c02013-01-18 12:47:40 -0800211 if (diag_bridge[index].usb_connected &&
Shalabh Jain737fca72012-11-14 21:53:43 -0800212 (driver->logging_mode == USB_MODE))
Shalabh Jainb0037c02013-01-18 12:47:40 -0800213 queue_work(diag_bridge[index].wq,
214 &diag_bridge[index].diag_read_work);
Jack Phamb60775a2012-02-14 17:57:41 -0800215}
216
217static int diag_hsic_suspend(void *ctxt)
218{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800219 int index = (int)ctxt;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700220 pr_debug("diag: hsic_suspend\n");
Dixon Peterson938f8602012-08-17 20:02:57 -0700221
222 /* Don't allow suspend if a write in the HSIC is in progress */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800223 if (diag_hsic[index].in_busy_hsic_write)
Jack Phamb60775a2012-02-14 17:57:41 -0800224 return -EBUSY;
225
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700226 /* Don't allow suspend if in MEMORY_DEVICE_MODE */
227 if (driver->logging_mode == MEMORY_DEVICE_MODE)
228 return -EBUSY;
229
Shalabh Jainb0037c02013-01-18 12:47:40 -0800230 diag_hsic[index].hsic_suspend = 1;
Jack Phamb60775a2012-02-14 17:57:41 -0800231
232 return 0;
233}
234
235static void diag_hsic_resume(void *ctxt)
236{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800237 int index = (int)ctxt;
Jack Phamb60775a2012-02-14 17:57:41 -0800238
Shalabh Jainb0037c02013-01-18 12:47:40 -0800239 pr_debug("diag: hsic_resume\n");
240 diag_hsic[index].hsic_suspend = 0;
241
242 if ((diag_hsic[index].count_hsic_pool <
243 diag_hsic[index].poolsize_hsic) &&
Dixon Peterson5db2e3c2012-09-06 19:13:14 -0700244 ((driver->logging_mode == MEMORY_DEVICE_MODE) ||
Shalabh Jainb0037c02013-01-18 12:47:40 -0800245 (diag_bridge[index].usb_connected)))
246 queue_work(diag_bridge[index].wq,
247 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800248}
249
Shalabh Jainb0037c02013-01-18 12:47:40 -0800250struct diag_bridge_ops hsic_diag_bridge_ops[MAX_HSIC_CH] = {
251 {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800252 .ctxt = NULL,
253 .read_complete_cb = diag_hsic_read_complete_callback,
254 .write_complete_cb = diag_hsic_write_complete_callback,
Jack Phamb60775a2012-02-14 17:57:41 -0800255 .suspend = diag_hsic_suspend,
256 .resume = diag_hsic_resume,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800257 },
258 {
259 .ctxt = NULL,
260 .read_complete_cb = diag_hsic_read_complete_callback,
261 .write_complete_cb = diag_hsic_write_complete_callback,
262 .suspend = diag_hsic_suspend,
263 .resume = diag_hsic_resume,
264 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800265};
266
Shalabh Jainb0037c02013-01-18 12:47:40 -0800267void diag_hsic_close(int ch_id)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800268{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800269 if (diag_hsic[ch_id].hsic_device_enabled) {
270 diag_hsic[ch_id].hsic_ch = 0;
271 if (diag_hsic[ch_id].hsic_device_opened) {
272 diag_hsic[ch_id].hsic_device_opened = 0;
273 diag_bridge_close(ch_id);
274 pr_debug("diag: %s: closed successfully ch %d\n",
275 __func__, ch_id);
Jack Phamfbd22552012-09-07 17:29:08 -0700276 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800277 pr_debug("diag: %s: already closed ch %d\n",
278 __func__, ch_id);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800279 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800280 } else {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800281 pr_debug("diag: %s: HSIC device already removed ch %d\n",
282 __func__, ch_id);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700283 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700284}
285
286/* diagfwd_cancel_hsic is called to cancel outstanding read/writes */
287int diagfwd_cancel_hsic(void)
288{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800289 int err, i;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700290
Shalabh Jainb0037c02013-01-18 12:47:40 -0800291 /* Cancel it for all active HSIC bridges */
292 for (i = 0; i < MAX_HSIC_CH; i++) {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800293 if (!diag_bridge[i].enabled)
294 continue;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800295 mutex_lock(&diag_bridge[i].bridge_mutex);
296 if (diag_hsic[i].hsic_device_enabled) {
297 if (diag_hsic[i].hsic_device_opened) {
298 diag_hsic[i].hsic_ch = 0;
299 diag_hsic[i].hsic_device_opened = 0;
300 diag_bridge_close(i);
301 hsic_diag_bridge_ops[i].ctxt = (void *)(i);
302 err = diag_bridge_open(i,
303 &hsic_diag_bridge_ops[i]);
304 if (err) {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800305 pr_err("diag: HSIC %d channel open error: %d\n",
306 i, err);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800307 } else {
Dixon Petersonf90f3582013-01-26 18:14:17 -0800308 pr_debug("diag: opened HSIC channel: %d\n",
309 i);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800310 diag_hsic[i].hsic_device_opened = 1;
311 diag_hsic[i].hsic_ch = 1;
312 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700313 }
314 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800315 mutex_unlock(&diag_bridge[i].bridge_mutex);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800316 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700317 return 0;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800318}
319
320/*
321 * diagfwd_write_complete_hsic is called after the asynchronous
322 * usb_diag_write() on mdm channel is complete
323 */
Dixon Petersonf90f3582013-01-26 18:14:17 -0800324int diagfwd_write_complete_hsic(struct diag_request *diag_write_ptr, int index)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800325{
Dixon Peterson938f8602012-08-17 20:02:57 -0700326 unsigned char *buf = (diag_write_ptr) ? diag_write_ptr->buf : NULL;
327
328 if (buf) {
329 /* Return buffers to their pools */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800330 diagmem_free(driver, (unsigned char *)buf, index +
331 POOL_TYPE_HSIC);
Dixon Peterson938f8602012-08-17 20:02:57 -0700332 diagmem_free(driver, (unsigned char *)diag_write_ptr,
Shalabh Jainb0037c02013-01-18 12:47:40 -0800333 index +
Dixon Peterson938f8602012-08-17 20:02:57 -0700334 POOL_TYPE_HSIC_WRITE);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800335 }
336
Shalabh Jainb0037c02013-01-18 12:47:40 -0800337 if (!diag_hsic[index].hsic_ch) {
338 pr_err("diag: In %s: hsic_ch == 0\n", __func__);
Dixon Peterson938f8602012-08-17 20:02:57 -0700339 return 0;
340 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800341
Shalabh Jain737fca72012-11-14 21:53:43 -0800342 /* Read data from the HSIC */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800343 queue_work(diag_bridge[index].wq,
344 &diag_hsic[index].diag_read_hsic_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800345
346 return 0;
347}
348
Shalabh Jain737fca72012-11-14 21:53:43 -0800349void diag_usb_read_complete_hsic_fn(struct work_struct *w)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800350{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800351 struct diag_bridge_dev *bridge_struct = container_of(w,
352 struct diag_bridge_dev, usb_read_complete_work);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800353
Shalabh Jainb0037c02013-01-18 12:47:40 -0800354 diagfwd_read_complete_bridge(
355 diag_bridge[bridge_struct->id].usb_read_ptr);
356}
Shalabh Jain737fca72012-11-14 21:53:43 -0800357
358void diag_read_usb_hsic_work_fn(struct work_struct *work)
359{
Shalabh Jainb0037c02013-01-18 12:47:40 -0800360 struct diag_bridge_dev *bridge_struct = container_of(work,
361 struct diag_bridge_dev, diag_read_work);
362 int index = bridge_struct->id;
363
364 if (!diag_hsic[index].hsic_ch) {
365 pr_err("diag: in %s: hsic_ch == 0\n", __func__);
Shalabh Jainf7228dc2012-05-23 17:32:05 -0700366 return;
367 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800368 /*
369 * If there is no data being read from the usb mdm channel
370 * and there is no mdm channel data currently being written
Shalabh Jain737fca72012-11-14 21:53:43 -0800371 * to the HSIC
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800372 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800373 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
374 !diag_hsic[index].in_busy_hsic_write) {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800375 APPEND_DEBUG('x');
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800376 /* Setup the next read from usb mdm channel */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800377 diag_hsic[index].in_busy_hsic_read_on_device = 1;
378 diag_bridge[index].usb_read_ptr->buf =
379 diag_bridge[index].usb_buf_out;
380 diag_bridge[index].usb_read_ptr->length = USB_MAX_OUT_BUF;
381 diag_bridge[index].usb_read_ptr->context = (void *)index;
382 usb_diag_read(diag_bridge[index].ch,
383 diag_bridge[index].usb_read_ptr);
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800384 APPEND_DEBUG('y');
385 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800386 /* If for some reason there was no mdm channel read initiated,
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800387 * queue up the reading of data from the mdm channel
388 */
Shalabh Jain737fca72012-11-14 21:53:43 -0800389
Shalabh Jainb0037c02013-01-18 12:47:40 -0800390 if (!diag_hsic[index].in_busy_hsic_read_on_device &&
Dixon Peterson70170f72012-11-05 20:25:11 -0800391 (driver->logging_mode == USB_MODE))
Shalabh Jainb0037c02013-01-18 12:47:40 -0800392 queue_work(diag_bridge[index].wq,
393 &(diag_bridge[index].diag_read_work));
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800394}
395
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700396static int diag_hsic_probe(struct platform_device *pdev)
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800397{
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700398 int err = 0;
Shalabh Jain737fca72012-11-14 21:53:43 -0800399
Shalabh Jainb0037c02013-01-18 12:47:40 -0800400 /* pdev->Id will indicate which HSIC is working. 0 stands for HSIC
401 * or CP1 1 indicates HS-USB or CP2
402 */
403 pr_debug("diag: in %s, ch = %d\n", __func__, pdev->id);
404 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
405 if (!diag_hsic[pdev->id].hsic_inited) {
406 spin_lock_init(&diag_hsic[pdev->id].hsic_spinlock);
407 diag_hsic[pdev->id].num_hsic_buf_tbl_entries = 0;
408 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL)
409 diag_hsic[pdev->id].hsic_buf_tbl =
410 kzalloc(NUM_HSIC_BUF_TBL_ENTRIES *
411 sizeof(struct diag_write_device), GFP_KERNEL);
412 if (diag_hsic[pdev->id].hsic_buf_tbl == NULL) {
413 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Shalabh Jain737fca72012-11-14 21:53:43 -0800414 return -ENOMEM;
415 }
Dixon Petersonf90f3582013-01-26 18:14:17 -0800416 diag_hsic[pdev->id].id = pdev->id;
Shalabh Jainb0037c02013-01-18 12:47:40 -0800417 diag_hsic[pdev->id].count_hsic_pool = 0;
418 diag_hsic[pdev->id].count_hsic_write_pool = 0;
419 diag_hsic[pdev->id].itemsize_hsic = READ_HSIC_BUF_SIZE;
420 diag_hsic[pdev->id].poolsize_hsic = N_MDM_WRITE;
421 diag_hsic[pdev->id].itemsize_hsic_write =
422 sizeof(struct diag_request);
423 diag_hsic[pdev->id].poolsize_hsic_write = N_MDM_WRITE;
424 diagmem_hsic_init(pdev->id);
425 INIT_WORK(&(diag_hsic[pdev->id].diag_read_hsic_work),
Shalabh Jain737fca72012-11-14 21:53:43 -0800426 diag_read_hsic_work_fn);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800427 diag_hsic[pdev->id].hsic_inited = 1;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700428 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700429 /*
430 * The probe function was called after the usb was connected
431 * on the legacy channel OR ODL is turned on. Communication over usb
Shalabh Jain737fca72012-11-14 21:53:43 -0800432 * mdm and HSIC needs to be turned on.
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700433 */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800434 if (diag_bridge[pdev->id].usb_connected || (driver->logging_mode ==
Shalabh Jain737fca72012-11-14 21:53:43 -0800435 MEMORY_DEVICE_MODE)) {
Shalabh Jainb0037c02013-01-18 12:47:40 -0800436 if (diag_hsic[pdev->id].hsic_device_opened) {
Jack Phamfbd22552012-09-07 17:29:08 -0700437 /* should not happen. close it before re-opening */
438 pr_warn("diag: HSIC channel already opened in probe\n");
Shalabh Jainb0037c02013-01-18 12:47:40 -0800439 diag_bridge_close(pdev->id);
Jack Phamfbd22552012-09-07 17:29:08 -0700440 }
Shalabh Jainb0037c02013-01-18 12:47:40 -0800441 hsic_diag_bridge_ops[pdev->id].ctxt = (void *)(pdev->id);
442 err = diag_bridge_open(pdev->id,
443 &hsic_diag_bridge_ops[pdev->id]);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700444 if (err) {
445 pr_err("diag: could not open HSIC, err: %d\n", err);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800446 diag_hsic[pdev->id].hsic_device_opened = 0;
447 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700448 return err;
449 }
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800450
Shalabh Jainb0037c02013-01-18 12:47:40 -0800451 pr_info("diag: opened HSIC bridge, ch = %d\n", pdev->id);
452 diag_hsic[pdev->id].hsic_device_opened = 1;
453 diag_hsic[pdev->id].hsic_ch = 1;
454 diag_hsic[pdev->id].in_busy_hsic_read_on_device = 0;
455 diag_hsic[pdev->id].in_busy_hsic_write = 0;
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700456
Shalabh Jainb0037c02013-01-18 12:47:40 -0800457 if (diag_bridge[pdev->id].usb_connected) {
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700458 /* Poll USB mdm channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800459 queue_work(diag_bridge[pdev->id].wq,
460 &diag_bridge[pdev->id].diag_read_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700461 }
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700462 /* Poll HSIC channel to check for data */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800463 queue_work(diag_bridge[pdev->id].wq,
464 &diag_hsic[pdev->id].diag_read_hsic_work);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700465 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800466 /* The HSIC (diag_bridge) platform device driver is enabled */
Shalabh Jainb0037c02013-01-18 12:47:40 -0800467 diag_hsic[pdev->id].hsic_device_enabled = 1;
468 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
Dixon Petersonf79b66f2012-04-26 13:21:26 -0700469 return err;
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800470}
471
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800472static int diag_hsic_remove(struct platform_device *pdev)
473{
Dixon Peterson938f8602012-08-17 20:02:57 -0700474 pr_debug("diag: %s called\n", __func__);
Shalabh Jainb0037c02013-01-18 12:47:40 -0800475 if (diag_hsic[pdev->id].hsic_device_enabled) {
476 mutex_lock(&diag_bridge[pdev->id].bridge_mutex);
477 diag_hsic_close(pdev->id);
478 diag_hsic[pdev->id].hsic_device_enabled = 0;
479 mutex_unlock(&diag_bridge[pdev->id].bridge_mutex);
480 }
Shalabh Jain737fca72012-11-14 21:53:43 -0800481
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800482 return 0;
483}
484
485static int diagfwd_hsic_runtime_suspend(struct device *dev)
486{
487 dev_dbg(dev, "pm_runtime: suspending...\n");
488 return 0;
489}
490
491static int diagfwd_hsic_runtime_resume(struct device *dev)
492{
493 dev_dbg(dev, "pm_runtime: resuming...\n");
494 return 0;
495}
496
497static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
498 .runtime_suspend = diagfwd_hsic_runtime_suspend,
499 .runtime_resume = diagfwd_hsic_runtime_resume,
500};
501
Shalabh Jain737fca72012-11-14 21:53:43 -0800502struct platform_driver msm_hsic_ch_driver = {
Dixon Peterson32e70bb2011-12-16 13:26:45 -0800503 .probe = diag_hsic_probe,
504 .remove = diag_hsic_remove,
505 .driver = {
506 .name = "diag_bridge",
507 .owner = THIS_MODULE,
508 .pm = &diagfwd_hsic_dev_pm_ops,
509 },
510};