blob: e76a9a8b19d8091e9c49665e2dc418664abe14be [file] [log] [blame]
Vamsi Krishna5b944712012-06-29 18:36:23 -07001/*
Pavankumar Kondeti7fcc7792012-12-28 17:15:41 +05302 * Copyright (c) 2012-2013, Linux Foundation. All rights reserved.
Vamsi Krishna5b944712012-06-29 18:36:23 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14/* add additional information to our printk's */
15#define pr_fmt(fmt) "%s: " fmt "\n", __func__
16
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/module.h>
22#include <linux/kref.h>
23#include <linux/platform_device.h>
24#include <linux/ratelimit.h>
25#include <linux/uaccess.h>
26#include <linux/usb.h>
27#include <linux/debugfs.h>
28#include <linux/seq_file.h>
29#include <linux/miscdevice.h>
30#include <linux/list.h>
31#include <linux/wait.h>
32
33#define DRIVER_DESC "USB host ks bridge driver"
34#define DRIVER_VERSION "1.0"
35
36struct data_pkt {
37 int n_read;
38 char *buf;
39 size_t len;
40 struct list_head list;
41 void *ctxt;
42};
43
44#define FILE_OPENED BIT(0)
45#define USB_DEV_CONNECTED BIT(1)
46#define NO_RX_REQS 10
47#define NO_BRIDGE_INSTANCES 2
48#define BOOT_BRIDGE_INDEX 0
49#define EFS_BRIDGE_INDEX 1
50#define MAX_DATA_PKT_SIZE 16384
Hemant Kumarb3779d12012-09-16 20:28:56 -070051#define PENDING_URB_TIMEOUT 10
Vamsi Krishna5b944712012-06-29 18:36:23 -070052
53struct ks_bridge {
54 char *name;
55 spinlock_t lock;
56 struct workqueue_struct *wq;
57 struct work_struct to_mdm_work;
58 struct work_struct start_rx_work;
59 struct list_head to_mdm_list;
60 struct list_head to_ks_list;
61 wait_queue_head_t ks_wait_q;
Hemant Kumarb3779d12012-09-16 20:28:56 -070062 wait_queue_head_t pending_urb_wait;
Hemant Kumarda86bd22012-08-24 19:42:31 -070063 struct miscdevice *fs_dev;
Hemant Kumarb3779d12012-09-16 20:28:56 -070064 atomic_t tx_pending_cnt;
65 atomic_t rx_pending_cnt;
Vamsi Krishna5b944712012-06-29 18:36:23 -070066
67 /* usb specific */
68 struct usb_device *udev;
69 struct usb_interface *ifc;
70 __u8 in_epAddr;
71 __u8 out_epAddr;
72 unsigned int in_pipe;
73 unsigned int out_pipe;
74 struct usb_anchor submitted;
75
76 unsigned long flags;
Vamsi Krishna5b944712012-06-29 18:36:23 -070077
78#define DBG_MSG_LEN 40
79#define DBG_MAX_MSG 500
80 unsigned int dbg_idx;
81 rwlock_t dbg_lock;
82 char (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
83};
84struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
85
86/* by default debugging is enabled */
87static unsigned int enable_dbg = 1;
88module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
89
90static void
91dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
92{
93 unsigned long flags;
94 unsigned long long t;
95 unsigned long nanosec;
96
97 if (!enable_dbg)
98 return;
99
100 write_lock_irqsave(&ksb->dbg_lock, flags);
101 t = cpu_clock(smp_processor_id());
102 nanosec = do_div(t, 1000000000)/1000;
103 scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
104 (unsigned long)t, nanosec, event, d1, d2);
105
106 ksb->dbg_idx++;
107 ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
108 write_unlock_irqrestore(&ksb->dbg_lock, flags);
109}
110
111static
112struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
113{
114 struct data_pkt *pkt;
115
116 pkt = kzalloc(sizeof(struct data_pkt), flags);
117 if (!pkt) {
118 pr_err("failed to allocate data packet\n");
119 return ERR_PTR(-ENOMEM);
120 }
121
122 pkt->buf = kmalloc(count, flags);
123 if (!pkt->buf) {
124 pr_err("failed to allocate data buffer\n");
125 kfree(pkt);
126 return ERR_PTR(-ENOMEM);
127 }
128
129 pkt->len = count;
130 INIT_LIST_HEAD(&pkt->list);
131 pkt->ctxt = ctxt;
132
133 return pkt;
134}
135
136static void ksb_free_data_pkt(struct data_pkt *pkt)
137{
138 kfree(pkt->buf);
139 kfree(pkt);
140}
141
142
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530143static void
144submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700145static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
146 size_t count, loff_t *pos)
147{
148 int ret;
149 unsigned long flags;
150 struct ks_bridge *ksb = fp->private_data;
151 struct data_pkt *pkt;
152 size_t space, copied;
153
154read_start:
155 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
156 return -ENODEV;
157
158 spin_lock_irqsave(&ksb->lock, flags);
159 if (list_empty(&ksb->to_ks_list)) {
160 spin_unlock_irqrestore(&ksb->lock, flags);
161 ret = wait_event_interruptible(ksb->ks_wait_q,
162 !list_empty(&ksb->to_ks_list) ||
163 !test_bit(USB_DEV_CONNECTED, &ksb->flags));
164 if (ret < 0)
165 return ret;
166
167 goto read_start;
168 }
169
170 space = count;
171 copied = 0;
172 while (!list_empty(&ksb->to_ks_list) && space) {
173 size_t len;
174
175 pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
Hemant Kumarb48f4732012-09-24 12:32:32 -0700176 len = min_t(size_t, space, pkt->len - pkt->n_read);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700177 spin_unlock_irqrestore(&ksb->lock, flags);
178
Hemant Kumarb48f4732012-09-24 12:32:32 -0700179 ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700180 if (ret) {
181 pr_err("copy_to_user failed err:%d\n", ret);
182 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700183 return ret;
184 }
185
Hemant Kumarb48f4732012-09-24 12:32:32 -0700186 pkt->n_read += len;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700187 space -= len;
188 copied += len;
189
190 spin_lock_irqsave(&ksb->lock, flags);
191 if (pkt->n_read == pkt->len) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530192 /*
193 * re-init the packet and queue it
194 * for more data.
195 */
Vamsi Krishna5b944712012-06-29 18:36:23 -0700196 list_del_init(&pkt->list);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530197 pkt->n_read = 0;
198 pkt->len = MAX_DATA_PKT_SIZE;
199 spin_unlock_irqrestore(&ksb->lock, flags);
200 submit_one_urb(ksb, GFP_KERNEL, pkt);
201 spin_lock_irqsave(&ksb->lock, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700202 }
203 }
204 spin_unlock_irqrestore(&ksb->lock, flags);
205
206 dbg_log_event(ksb, "KS_READ", copied, 0);
207
208 pr_debug("count:%d space:%d copied:%d", count, space, copied);
209
210 return copied;
211}
212
213static void ksb_tx_cb(struct urb *urb)
214{
215 struct data_pkt *pkt = urb->context;
216 struct ks_bridge *ksb = pkt->ctxt;
217
218 dbg_log_event(ksb, "C TX_URB", urb->status, 0);
219 pr_debug("status:%d", urb->status);
220
Hemant Kumarb3779d12012-09-16 20:28:56 -0700221 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
Vamsi Krishna5b944712012-06-29 18:36:23 -0700222 usb_autopm_put_interface_async(ksb->ifc);
223
224 if (urb->status < 0)
225 pr_err_ratelimited("urb failed with err:%d", urb->status);
226
227 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700228
229 atomic_dec(&ksb->tx_pending_cnt);
230 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700231}
232
233static void ksb_tomdm_work(struct work_struct *w)
234{
235 struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
236 struct data_pkt *pkt;
237 unsigned long flags;
238 struct urb *urb;
239 int ret;
240
241 spin_lock_irqsave(&ksb->lock, flags);
242 while (!list_empty(&ksb->to_mdm_list)
243 && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
244 pkt = list_first_entry(&ksb->to_mdm_list,
245 struct data_pkt, list);
246 list_del_init(&pkt->list);
247 spin_unlock_irqrestore(&ksb->lock, flags);
248
249 urb = usb_alloc_urb(0, GFP_KERNEL);
250 if (!urb) {
251 pr_err_ratelimited("unable to allocate urb");
252 ksb_free_data_pkt(pkt);
253 return;
254 }
255
256 ret = usb_autopm_get_interface(ksb->ifc);
257 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
258 pr_err_ratelimited("autopm_get failed:%d", ret);
259 usb_free_urb(urb);
260 ksb_free_data_pkt(pkt);
261 return;
262 }
263 usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
264 pkt->buf, pkt->len, ksb_tx_cb, pkt);
265 usb_anchor_urb(urb, &ksb->submitted);
266
267 dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
268
Hemant Kumarb3779d12012-09-16 20:28:56 -0700269 atomic_inc(&ksb->tx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700270 ret = usb_submit_urb(urb, GFP_KERNEL);
271 if (ret) {
272 pr_err("out urb submission failed");
273 usb_unanchor_urb(urb);
274 usb_free_urb(urb);
275 ksb_free_data_pkt(pkt);
276 usb_autopm_put_interface(ksb->ifc);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700277 atomic_dec(&ksb->tx_pending_cnt);
278 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700279 return;
280 }
281
Hemant Kumar1432f6f2012-09-19 12:40:11 -0700282 usb_free_urb(urb);
283
Vamsi Krishna5b944712012-06-29 18:36:23 -0700284 spin_lock_irqsave(&ksb->lock, flags);
285 }
286 spin_unlock_irqrestore(&ksb->lock, flags);
287}
288
289static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
290 size_t count, loff_t *pos)
291{
292 int ret;
293 struct data_pkt *pkt;
294 unsigned long flags;
295 struct ks_bridge *ksb = fp->private_data;
296
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700297 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
298 return -ENODEV;
299
Pavankumar Kondeti7fcc7792012-12-28 17:15:41 +0530300 if (count > MAX_DATA_PKT_SIZE)
301 count = MAX_DATA_PKT_SIZE;
302
Vamsi Krishna5b944712012-06-29 18:36:23 -0700303 pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
304 if (IS_ERR(pkt)) {
305 pr_err("unable to allocate data packet");
306 return PTR_ERR(pkt);
307 }
308
309 ret = copy_from_user(pkt->buf, buf, count);
310 if (ret) {
311 pr_err("copy_from_user failed: err:%d", ret);
312 ksb_free_data_pkt(pkt);
313 return ret;
314 }
315
316 spin_lock_irqsave(&ksb->lock, flags);
317 list_add_tail(&pkt->list, &ksb->to_mdm_list);
318 spin_unlock_irqrestore(&ksb->lock, flags);
319
320 queue_work(ksb->wq, &ksb->to_mdm_work);
321
322 return count;
323}
324
325static int efs_fs_open(struct inode *ip, struct file *fp)
326{
327 struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
328
329 pr_debug(":%s", ksb->name);
330 dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
331
332 if (!ksb) {
333 pr_err("ksb is being removed");
334 return -ENODEV;
335 }
336
337 fp->private_data = ksb;
338 set_bit(FILE_OPENED, &ksb->flags);
339
340 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
341 queue_work(ksb->wq, &ksb->start_rx_work);
342
343 return 0;
344}
345
346static int ksb_fs_open(struct inode *ip, struct file *fp)
347{
348 struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
349
350 pr_debug(":%s", ksb->name);
351 dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
352
353 if (!ksb) {
354 pr_err("ksb is being removed");
355 return -ENODEV;
356 }
357
358 fp->private_data = ksb;
359 set_bit(FILE_OPENED, &ksb->flags);
360
361 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
362 queue_work(ksb->wq, &ksb->start_rx_work);
363
364 return 0;
365}
366
367static int ksb_fs_release(struct inode *ip, struct file *fp)
368{
369 struct ks_bridge *ksb = fp->private_data;
370
371 pr_debug(":%s", ksb->name);
372 dbg_log_event(ksb, "FS-RELEASE", 0, 0);
373
374 clear_bit(FILE_OPENED, &ksb->flags);
375 fp->private_data = NULL;
376
377 return 0;
378}
379
380static const struct file_operations ksb_fops = {
381 .owner = THIS_MODULE,
382 .read = ksb_fs_read,
383 .write = ksb_fs_write,
384 .open = ksb_fs_open,
385 .release = ksb_fs_release,
386};
387
388static struct miscdevice ksb_fboot_dev = {
389 .minor = MISC_DYNAMIC_MINOR,
390 .name = "ks_bridge",
391 .fops = &ksb_fops,
392};
393
394static const struct file_operations efs_fops = {
395 .owner = THIS_MODULE,
396 .read = ksb_fs_read,
397 .write = ksb_fs_write,
398 .open = efs_fs_open,
399 .release = ksb_fs_release,
400};
401
402static struct miscdevice ksb_efs_dev = {
403 .minor = MISC_DYNAMIC_MINOR,
404 .name = "efs_bridge",
405 .fops = &efs_fops,
406};
407
408static const struct usb_device_id ksb_usb_ids[] = {
409 { USB_DEVICE(0x5c6, 0x9008),
410 .driver_info = (unsigned long)&ksb_fboot_dev, },
411 { USB_DEVICE(0x5c6, 0x9048),
412 .driver_info = (unsigned long)&ksb_efs_dev, },
413 { USB_DEVICE(0x5c6, 0x904C),
414 .driver_info = (unsigned long)&ksb_efs_dev, },
Hemant Kumarce3c5bf2012-12-06 15:52:02 -0800415 { USB_DEVICE(0x5c6, 0x9075),
416 .driver_info = (unsigned long)&ksb_efs_dev, },
Vamsi Krishna5b944712012-06-29 18:36:23 -0700417
418 {} /* terminating entry */
419};
420MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
421
422static void ksb_rx_cb(struct urb *urb);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530423static void
424submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700425{
Vamsi Krishna5b944712012-06-29 18:36:23 -0700426 struct urb *urb;
427 int ret;
428
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530429 urb = usb_alloc_urb(0, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700430 if (!urb) {
431 pr_err("unable to allocate urb");
432 ksb_free_data_pkt(pkt);
433 return;
434 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700435
436 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
437 pkt->buf, pkt->len,
438 ksb_rx_cb, pkt);
439 usb_anchor_urb(urb, &ksb->submitted);
440
Hemant Kumarb3779d12012-09-16 20:28:56 -0700441 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
442 usb_unanchor_urb(urb);
443 usb_free_urb(urb);
444 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700445 return;
446 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700447
Hemant Kumarb3779d12012-09-16 20:28:56 -0700448 atomic_inc(&ksb->rx_pending_cnt);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530449 ret = usb_submit_urb(urb, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700450 if (ret) {
451 pr_err("in urb submission failed");
452 usb_unanchor_urb(urb);
453 usb_free_urb(urb);
454 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700455 atomic_dec(&ksb->rx_pending_cnt);
456 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700457 return;
458 }
459
Hemant Kumarb3779d12012-09-16 20:28:56 -0700460 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
461
Vamsi Krishna5b944712012-06-29 18:36:23 -0700462 usb_free_urb(urb);
463}
464static void ksb_rx_cb(struct urb *urb)
465{
466 struct data_pkt *pkt = urb->context;
467 struct ks_bridge *ksb = pkt->ctxt;
468
469 dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
470
471 pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
472
Hemant Kumar853ebf62012-08-31 18:38:32 -0700473 /*non zero len of data received while unlinking urb*/
474 if (urb->status == -ENOENT && urb->actual_length > 0)
475 goto add_to_list;
476
Vamsi Krishna5b944712012-06-29 18:36:23 -0700477 if (urb->status < 0) {
Hemant Kumar853ebf62012-08-31 18:38:32 -0700478 if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
479 && urb->status != -EPROTO)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700480 pr_err_ratelimited("urb failed with err:%d",
481 urb->status);
482 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700483 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700484 }
485
486 if (urb->actual_length == 0) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530487 submit_one_urb(ksb, GFP_ATOMIC, pkt);
488 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700489 }
490
Hemant Kumar853ebf62012-08-31 18:38:32 -0700491add_to_list:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700492 spin_lock(&ksb->lock);
493 pkt->len = urb->actual_length;
494 list_add_tail(&pkt->list, &ksb->to_ks_list);
495 spin_unlock(&ksb->lock);
496
497 /* wake up read thread */
498 wake_up(&ksb->ks_wait_q);
499
Hemant Kumarb3779d12012-09-16 20:28:56 -0700500done:
501 atomic_dec(&ksb->rx_pending_cnt);
502 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700503}
504
505static void ksb_start_rx_work(struct work_struct *w)
506{
507 struct ks_bridge *ksb =
508 container_of(w, struct ks_bridge, start_rx_work);
509 struct data_pkt *pkt;
510 struct urb *urb;
511 int i = 0;
512 int ret;
513
514 for (i = 0; i < NO_RX_REQS; i++) {
Hemant Kumarb3779d12012-09-16 20:28:56 -0700515
516 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
517 return;
518
Vamsi Krishna5b944712012-06-29 18:36:23 -0700519 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
520 if (IS_ERR(pkt)) {
521 pr_err("unable to allocate data pkt");
522 return;
523 }
524
525 urb = usb_alloc_urb(0, GFP_KERNEL);
526 if (!urb) {
527 pr_err("unable to allocate urb");
528 ksb_free_data_pkt(pkt);
529 return;
530 }
531
532 ret = usb_autopm_get_interface(ksb->ifc);
533 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
534 pr_err_ratelimited("autopm_get failed:%d", ret);
535 usb_free_urb(urb);
536 ksb_free_data_pkt(pkt);
537 return;
538 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700539
540 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
541 pkt->buf, pkt->len,
542 ksb_rx_cb, pkt);
543 usb_anchor_urb(urb, &ksb->submitted);
544
545 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
546
Hemant Kumarb3779d12012-09-16 20:28:56 -0700547 atomic_inc(&ksb->rx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700548 ret = usb_submit_urb(urb, GFP_KERNEL);
549 if (ret) {
550 pr_err("in urb submission failed");
551 usb_unanchor_urb(urb);
552 usb_free_urb(urb);
553 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700554 usb_autopm_put_interface(ksb->ifc);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700555 atomic_dec(&ksb->rx_pending_cnt);
556 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700557 return;
558 }
559
560 usb_autopm_put_interface_async(ksb->ifc);
561 usb_free_urb(urb);
562 }
563}
564
565static int
566ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
567{
568 __u8 ifc_num;
569 struct usb_host_interface *ifc_desc;
570 struct usb_endpoint_descriptor *ep_desc;
571 int i;
572 struct ks_bridge *ksb;
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700573 unsigned long flags;
574 struct data_pkt *pkt;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700575
576 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
577
578 switch (id->idProduct) {
579 case 0x9008:
580 if (ifc_num != 0)
581 return -ENODEV;
582 ksb = __ksb[BOOT_BRIDGE_INDEX];
583 break;
584 case 0x9048:
585 case 0x904C:
Hemant Kumarcfa601a2012-12-19 11:23:11 -0800586 case 0x9075:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700587 if (ifc_num != 2)
588 return -ENODEV;
589 ksb = __ksb[EFS_BRIDGE_INDEX];
590 break;
591 default:
592 return -ENODEV;
593 }
594
595 if (!ksb) {
596 pr_err("ksb is not initialized");
597 return -ENODEV;
598 }
599
600 ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
601 ksb->ifc = ifc;
602 ifc_desc = ifc->cur_altsetting;
603
604 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
605 ep_desc = &ifc_desc->endpoint[i].desc;
606
607 if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
608 ksb->in_epAddr = ep_desc->bEndpointAddress;
609
610 if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
611 ksb->out_epAddr = ep_desc->bEndpointAddress;
612 }
613
614 if (!(ksb->in_epAddr && ksb->out_epAddr)) {
615 pr_err("could not find bulk in and bulk out endpoints");
616 usb_put_dev(ksb->udev);
617 ksb->ifc = NULL;
618 return -ENODEV;
619 }
620
621 ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
622 ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
623
624 usb_set_intfdata(ifc, ksb);
625 set_bit(USB_DEV_CONNECTED, &ksb->flags);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700626 atomic_set(&ksb->tx_pending_cnt, 0);
627 atomic_set(&ksb->rx_pending_cnt, 0);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700628
629 dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
630
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700631 /*free up stale buffers if any from previous disconnect*/
632 spin_lock_irqsave(&ksb->lock, flags);
633 while (!list_empty(&ksb->to_ks_list)) {
634 pkt = list_first_entry(&ksb->to_ks_list,
635 struct data_pkt, list);
636 list_del_init(&pkt->list);
637 ksb_free_data_pkt(pkt);
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700638 }
639 while (!list_empty(&ksb->to_mdm_list)) {
640 pkt = list_first_entry(&ksb->to_mdm_list,
641 struct data_pkt, list);
642 list_del_init(&pkt->list);
643 ksb_free_data_pkt(pkt);
644 }
645 spin_unlock_irqrestore(&ksb->lock, flags);
646
Hemant Kumarda86bd22012-08-24 19:42:31 -0700647 ksb->fs_dev = (struct miscdevice *)id->driver_info;
648 misc_register(ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700649
Hemant Kumard26076c2012-09-07 19:00:21 -0700650 ifc->needs_remote_wakeup = 1;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700651 usb_enable_autosuspend(ksb->udev);
652
653 pr_debug("usb dev connected");
654
655 return 0;
656}
657
658static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
659{
660 struct ks_bridge *ksb = usb_get_intfdata(ifc);
661
662 dbg_log_event(ksb, "SUSPEND", 0, 0);
663
Vamsi Krishna5b944712012-06-29 18:36:23 -0700664 usb_kill_anchored_urbs(&ksb->submitted);
665
666 return 0;
667}
668
669static int ksb_usb_resume(struct usb_interface *ifc)
670{
671 struct ks_bridge *ksb = usb_get_intfdata(ifc);
672
673 dbg_log_event(ksb, "RESUME", 0, 0);
674
675 if (test_bit(FILE_OPENED, &ksb->flags))
676 queue_work(ksb->wq, &ksb->start_rx_work);
677
678 return 0;
679}
680
681static void ksb_usb_disconnect(struct usb_interface *ifc)
682{
683 struct ks_bridge *ksb = usb_get_intfdata(ifc);
684 unsigned long flags;
685 struct data_pkt *pkt;
686
687 dbg_log_event(ksb, "PID-DETACH", 0, 0);
688
689 clear_bit(USB_DEV_CONNECTED, &ksb->flags);
690 wake_up(&ksb->ks_wait_q);
691 cancel_work_sync(&ksb->to_mdm_work);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700692 cancel_work_sync(&ksb->start_rx_work);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700693
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700694 misc_deregister(ksb->fs_dev);
695
Vamsi Krishna5b944712012-06-29 18:36:23 -0700696 usb_kill_anchored_urbs(&ksb->submitted);
697
Hemant Kumarb3779d12012-09-16 20:28:56 -0700698 wait_event_interruptible_timeout(
699 ksb->pending_urb_wait,
700 !atomic_read(&ksb->tx_pending_cnt) &&
701 !atomic_read(&ksb->rx_pending_cnt),
702 msecs_to_jiffies(PENDING_URB_TIMEOUT));
703
Vamsi Krishna5b944712012-06-29 18:36:23 -0700704 spin_lock_irqsave(&ksb->lock, flags);
705 while (!list_empty(&ksb->to_ks_list)) {
706 pkt = list_first_entry(&ksb->to_ks_list,
707 struct data_pkt, list);
708 list_del_init(&pkt->list);
709 ksb_free_data_pkt(pkt);
710 }
711 while (!list_empty(&ksb->to_mdm_list)) {
712 pkt = list_first_entry(&ksb->to_mdm_list,
713 struct data_pkt, list);
714 list_del_init(&pkt->list);
715 ksb_free_data_pkt(pkt);
716 }
717 spin_unlock_irqrestore(&ksb->lock, flags);
718
Hemant Kumard26076c2012-09-07 19:00:21 -0700719 ifc->needs_remote_wakeup = 0;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700720 usb_put_dev(ksb->udev);
721 ksb->ifc = NULL;
722 usb_set_intfdata(ifc, NULL);
723
724 return;
725}
726
727static struct usb_driver ksb_usb_driver = {
728 .name = "ks_bridge",
729 .probe = ksb_usb_probe,
730 .disconnect = ksb_usb_disconnect,
731 .suspend = ksb_usb_suspend,
732 .resume = ksb_usb_resume,
733 .id_table = ksb_usb_ids,
734 .supports_autosuspend = 1,
735};
736
737static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
738{
739 unsigned long flags;
740 struct ks_bridge *ksb = s->private;
741 int i;
742
743 read_lock_irqsave(&ksb->dbg_lock, flags);
744 for (i = 0; i < DBG_MAX_MSG; i++) {
745 if (i == (ksb->dbg_idx - 1))
746 seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
747 else
748 seq_printf(s, "%s\n", ksb->dbgbuf[i]);
749 }
750 read_unlock_irqrestore(&ksb->dbg_lock, flags);
751
752 return 0;
753}
754
755static int ksb_debug_open(struct inode *ip, struct file *fp)
756{
757 return single_open(fp, ksb_debug_show, ip->i_private);
758
759 return 0;
760}
761
762static const struct file_operations dbg_fops = {
763 .open = ksb_debug_open,
764 .read = seq_read,
765 .llseek = seq_lseek,
766 .release = single_release,
767};
768static struct dentry *dbg_dir;
769static int __init ksb_init(void)
770{
771 struct ks_bridge *ksb;
772 int num_instances = 0;
773 int ret = 0;
774 int i;
775
776 dbg_dir = debugfs_create_dir("ks_bridge", NULL);
777 if (IS_ERR(dbg_dir))
778 pr_err("unable to create debug dir");
779
780 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
781 ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
782 if (!ksb) {
783 pr_err("unable to allocat mem for ks_bridge");
Hemant Kumarda86bd22012-08-24 19:42:31 -0700784 ret = -ENOMEM;
785 goto dev_free;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700786 }
787 __ksb[i] = ksb;
788
789 ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
790 if (!ksb->name) {
791 pr_info("unable to allocate name");
792 kfree(ksb);
793 ret = -ENOMEM;
794 goto dev_free;
795 }
796
797 spin_lock_init(&ksb->lock);
798 INIT_LIST_HEAD(&ksb->to_mdm_list);
799 INIT_LIST_HEAD(&ksb->to_ks_list);
800 init_waitqueue_head(&ksb->ks_wait_q);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700801 init_waitqueue_head(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700802 ksb->wq = create_singlethread_workqueue(ksb->name);
803 if (!ksb->wq) {
804 pr_err("unable to allocate workqueue");
805 kfree(ksb->name);
806 kfree(ksb);
807 ret = -ENOMEM;
808 goto dev_free;
809 }
810
811 INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
812 INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
813 init_usb_anchor(&ksb->submitted);
814
815 ksb->dbg_idx = 0;
816 ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
817
818 if (!IS_ERR(dbg_dir))
819 debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
820 ksb, &dbg_fops);
821
822 num_instances++;
823 }
824
825 ret = usb_register(&ksb_usb_driver);
826 if (ret) {
827 pr_err("unable to register ks bridge driver");
828 goto dev_free;
829 }
830
831 pr_info("init done");
832
833 return 0;
834
835dev_free:
836 if (!IS_ERR(dbg_dir))
837 debugfs_remove_recursive(dbg_dir);
838
839 for (i = 0; i < num_instances; i++) {
840 ksb = __ksb[i];
841
842 destroy_workqueue(ksb->wq);
843 kfree(ksb->name);
844 kfree(ksb);
845 }
846
847 return ret;
848
849}
850
851static void __exit ksb_exit(void)
852{
853 struct ks_bridge *ksb;
854 int i;
855
856 if (!IS_ERR(dbg_dir))
857 debugfs_remove_recursive(dbg_dir);
858
859 usb_deregister(&ksb_usb_driver);
860
861 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
862 ksb = __ksb[i];
863
864 destroy_workqueue(ksb->wq);
865 kfree(ksb->name);
866 kfree(ksb);
867 }
868}
869
870module_init(ksb_init);
871module_exit(ksb_exit);
872
873MODULE_DESCRIPTION(DRIVER_DESC);
874MODULE_VERSION(DRIVER_VERSION);
875MODULE_LICENSE("GPL v2");