blob: d96de2923c97c610fe5ade99fe93b3baf632667c [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;
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530151 struct data_pkt *pkt = NULL;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700152 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;
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530172 while (!list_empty(&ksb->to_ks_list) && space &&
173 test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
Vamsi Krishna5b944712012-06-29 18:36:23 -0700174 size_t len;
175
176 pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530177 list_del_init(&pkt->list);
Hemant Kumarb48f4732012-09-24 12:32:32 -0700178 len = min_t(size_t, space, pkt->len - pkt->n_read);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700179 spin_unlock_irqrestore(&ksb->lock, flags);
180
Hemant Kumarb48f4732012-09-24 12:32:32 -0700181 ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700182 if (ret) {
183 pr_err("copy_to_user failed err:%d\n", ret);
184 ksb_free_data_pkt(pkt);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530185 return -EFAULT;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700186 }
187
Hemant Kumarb48f4732012-09-24 12:32:32 -0700188 pkt->n_read += len;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700189 space -= len;
190 copied += len;
191
Vamsi Krishna5b944712012-06-29 18:36:23 -0700192 if (pkt->n_read == pkt->len) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530193 /*
194 * re-init the packet and queue it
195 * for more data.
196 */
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530197 pkt->n_read = 0;
198 pkt->len = MAX_DATA_PKT_SIZE;
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530199 submit_one_urb(ksb, GFP_KERNEL, pkt);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530200 pkt = NULL;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700201 }
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530202 spin_lock_irqsave(&ksb->lock, flags);
203 }
204
205 /* put the partial packet back in the list */
206 if (!space && pkt && pkt->n_read != pkt->len) {
207 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
208 list_add(&pkt->list, &ksb->to_ks_list);
209 else
210 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700211 }
212 spin_unlock_irqrestore(&ksb->lock, flags);
213
214 dbg_log_event(ksb, "KS_READ", copied, 0);
215
216 pr_debug("count:%d space:%d copied:%d", count, space, copied);
217
218 return copied;
219}
220
221static void ksb_tx_cb(struct urb *urb)
222{
223 struct data_pkt *pkt = urb->context;
224 struct ks_bridge *ksb = pkt->ctxt;
225
226 dbg_log_event(ksb, "C TX_URB", urb->status, 0);
227 pr_debug("status:%d", urb->status);
228
Hemant Kumarb3779d12012-09-16 20:28:56 -0700229 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
Vamsi Krishna5b944712012-06-29 18:36:23 -0700230 usb_autopm_put_interface_async(ksb->ifc);
231
232 if (urb->status < 0)
233 pr_err_ratelimited("urb failed with err:%d", urb->status);
234
235 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700236
237 atomic_dec(&ksb->tx_pending_cnt);
238 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700239}
240
241static void ksb_tomdm_work(struct work_struct *w)
242{
243 struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
244 struct data_pkt *pkt;
245 unsigned long flags;
246 struct urb *urb;
247 int ret;
248
249 spin_lock_irqsave(&ksb->lock, flags);
250 while (!list_empty(&ksb->to_mdm_list)
251 && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
252 pkt = list_first_entry(&ksb->to_mdm_list,
253 struct data_pkt, list);
254 list_del_init(&pkt->list);
255 spin_unlock_irqrestore(&ksb->lock, flags);
256
257 urb = usb_alloc_urb(0, GFP_KERNEL);
258 if (!urb) {
259 pr_err_ratelimited("unable to allocate urb");
260 ksb_free_data_pkt(pkt);
261 return;
262 }
263
264 ret = usb_autopm_get_interface(ksb->ifc);
265 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
266 pr_err_ratelimited("autopm_get failed:%d", ret);
267 usb_free_urb(urb);
268 ksb_free_data_pkt(pkt);
269 return;
270 }
271 usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
272 pkt->buf, pkt->len, ksb_tx_cb, pkt);
273 usb_anchor_urb(urb, &ksb->submitted);
274
275 dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
276
Hemant Kumarb3779d12012-09-16 20:28:56 -0700277 atomic_inc(&ksb->tx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700278 ret = usb_submit_urb(urb, GFP_KERNEL);
279 if (ret) {
280 pr_err("out urb submission failed");
281 usb_unanchor_urb(urb);
282 usb_free_urb(urb);
283 ksb_free_data_pkt(pkt);
284 usb_autopm_put_interface(ksb->ifc);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700285 atomic_dec(&ksb->tx_pending_cnt);
286 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700287 return;
288 }
289
Hemant Kumar1432f6f2012-09-19 12:40:11 -0700290 usb_free_urb(urb);
291
Vamsi Krishna5b944712012-06-29 18:36:23 -0700292 spin_lock_irqsave(&ksb->lock, flags);
293 }
294 spin_unlock_irqrestore(&ksb->lock, flags);
295}
296
297static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
298 size_t count, loff_t *pos)
299{
300 int ret;
301 struct data_pkt *pkt;
302 unsigned long flags;
303 struct ks_bridge *ksb = fp->private_data;
304
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700305 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
306 return -ENODEV;
307
Pavankumar Kondeti7fcc7792012-12-28 17:15:41 +0530308 if (count > MAX_DATA_PKT_SIZE)
309 count = MAX_DATA_PKT_SIZE;
310
Vamsi Krishna5b944712012-06-29 18:36:23 -0700311 pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
312 if (IS_ERR(pkt)) {
313 pr_err("unable to allocate data packet");
314 return PTR_ERR(pkt);
315 }
316
317 ret = copy_from_user(pkt->buf, buf, count);
318 if (ret) {
319 pr_err("copy_from_user failed: err:%d", ret);
320 ksb_free_data_pkt(pkt);
321 return ret;
322 }
323
324 spin_lock_irqsave(&ksb->lock, flags);
325 list_add_tail(&pkt->list, &ksb->to_mdm_list);
326 spin_unlock_irqrestore(&ksb->lock, flags);
327
328 queue_work(ksb->wq, &ksb->to_mdm_work);
329
330 return count;
331}
332
333static int efs_fs_open(struct inode *ip, struct file *fp)
334{
335 struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
336
337 pr_debug(":%s", ksb->name);
338 dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
339
340 if (!ksb) {
341 pr_err("ksb is being removed");
342 return -ENODEV;
343 }
344
345 fp->private_data = ksb;
346 set_bit(FILE_OPENED, &ksb->flags);
347
348 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
349 queue_work(ksb->wq, &ksb->start_rx_work);
350
351 return 0;
352}
353
354static int ksb_fs_open(struct inode *ip, struct file *fp)
355{
356 struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
357
358 pr_debug(":%s", ksb->name);
359 dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
360
361 if (!ksb) {
362 pr_err("ksb is being removed");
363 return -ENODEV;
364 }
365
366 fp->private_data = ksb;
367 set_bit(FILE_OPENED, &ksb->flags);
368
369 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
370 queue_work(ksb->wq, &ksb->start_rx_work);
371
372 return 0;
373}
374
375static int ksb_fs_release(struct inode *ip, struct file *fp)
376{
377 struct ks_bridge *ksb = fp->private_data;
378
379 pr_debug(":%s", ksb->name);
380 dbg_log_event(ksb, "FS-RELEASE", 0, 0);
381
382 clear_bit(FILE_OPENED, &ksb->flags);
383 fp->private_data = NULL;
384
385 return 0;
386}
387
388static const struct file_operations ksb_fops = {
389 .owner = THIS_MODULE,
390 .read = ksb_fs_read,
391 .write = ksb_fs_write,
392 .open = ksb_fs_open,
393 .release = ksb_fs_release,
394};
395
396static struct miscdevice ksb_fboot_dev = {
397 .minor = MISC_DYNAMIC_MINOR,
398 .name = "ks_bridge",
399 .fops = &ksb_fops,
400};
401
402static const struct file_operations efs_fops = {
403 .owner = THIS_MODULE,
404 .read = ksb_fs_read,
405 .write = ksb_fs_write,
406 .open = efs_fs_open,
407 .release = ksb_fs_release,
408};
409
410static struct miscdevice ksb_efs_dev = {
411 .minor = MISC_DYNAMIC_MINOR,
412 .name = "efs_bridge",
413 .fops = &efs_fops,
414};
415
416static const struct usb_device_id ksb_usb_ids[] = {
417 { USB_DEVICE(0x5c6, 0x9008),
418 .driver_info = (unsigned long)&ksb_fboot_dev, },
419 { USB_DEVICE(0x5c6, 0x9048),
420 .driver_info = (unsigned long)&ksb_efs_dev, },
421 { USB_DEVICE(0x5c6, 0x904C),
422 .driver_info = (unsigned long)&ksb_efs_dev, },
Hemant Kumarce3c5bf2012-12-06 15:52:02 -0800423 { USB_DEVICE(0x5c6, 0x9075),
424 .driver_info = (unsigned long)&ksb_efs_dev, },
Vamsi Krishna5b944712012-06-29 18:36:23 -0700425
426 {} /* terminating entry */
427};
428MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
429
430static void ksb_rx_cb(struct urb *urb);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530431static void
432submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700433{
Vamsi Krishna5b944712012-06-29 18:36:23 -0700434 struct urb *urb;
435 int ret;
436
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530437 urb = usb_alloc_urb(0, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700438 if (!urb) {
439 pr_err("unable to allocate urb");
440 ksb_free_data_pkt(pkt);
441 return;
442 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700443
444 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
445 pkt->buf, pkt->len,
446 ksb_rx_cb, pkt);
447 usb_anchor_urb(urb, &ksb->submitted);
448
Hemant Kumarb3779d12012-09-16 20:28:56 -0700449 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
450 usb_unanchor_urb(urb);
451 usb_free_urb(urb);
452 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700453 return;
454 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700455
Hemant Kumarb3779d12012-09-16 20:28:56 -0700456 atomic_inc(&ksb->rx_pending_cnt);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530457 ret = usb_submit_urb(urb, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700458 if (ret) {
459 pr_err("in urb submission failed");
460 usb_unanchor_urb(urb);
461 usb_free_urb(urb);
462 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700463 atomic_dec(&ksb->rx_pending_cnt);
464 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700465 return;
466 }
467
Hemant Kumarb3779d12012-09-16 20:28:56 -0700468 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
469
Vamsi Krishna5b944712012-06-29 18:36:23 -0700470 usb_free_urb(urb);
471}
472static void ksb_rx_cb(struct urb *urb)
473{
474 struct data_pkt *pkt = urb->context;
475 struct ks_bridge *ksb = pkt->ctxt;
476
477 dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
478
479 pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
480
Hemant Kumar853ebf62012-08-31 18:38:32 -0700481 /*non zero len of data received while unlinking urb*/
482 if (urb->status == -ENOENT && urb->actual_length > 0)
483 goto add_to_list;
484
Vamsi Krishna5b944712012-06-29 18:36:23 -0700485 if (urb->status < 0) {
Hemant Kumar853ebf62012-08-31 18:38:32 -0700486 if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
487 && urb->status != -EPROTO)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700488 pr_err_ratelimited("urb failed with err:%d",
489 urb->status);
490 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700491 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700492 }
493
494 if (urb->actual_length == 0) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530495 submit_one_urb(ksb, GFP_ATOMIC, pkt);
496 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700497 }
498
Hemant Kumar853ebf62012-08-31 18:38:32 -0700499add_to_list:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700500 spin_lock(&ksb->lock);
501 pkt->len = urb->actual_length;
502 list_add_tail(&pkt->list, &ksb->to_ks_list);
503 spin_unlock(&ksb->lock);
504
505 /* wake up read thread */
506 wake_up(&ksb->ks_wait_q);
507
Hemant Kumarb3779d12012-09-16 20:28:56 -0700508done:
509 atomic_dec(&ksb->rx_pending_cnt);
510 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700511}
512
513static void ksb_start_rx_work(struct work_struct *w)
514{
515 struct ks_bridge *ksb =
516 container_of(w, struct ks_bridge, start_rx_work);
517 struct data_pkt *pkt;
518 struct urb *urb;
519 int i = 0;
520 int ret;
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530521 bool put = true;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700522
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530523 ret = usb_autopm_get_interface(ksb->ifc);
524 if (ret < 0) {
525 if (ret != -EAGAIN && ret != -EACCES) {
526 pr_err_ratelimited("autopm_get failed:%d", ret);
527 return;
528 }
529 put = false;
530 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700531 for (i = 0; i < NO_RX_REQS; i++) {
Hemant Kumarb3779d12012-09-16 20:28:56 -0700532
533 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530534 break;
Hemant Kumarb3779d12012-09-16 20:28:56 -0700535
Vamsi Krishna5b944712012-06-29 18:36:23 -0700536 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
537 if (IS_ERR(pkt)) {
538 pr_err("unable to allocate data pkt");
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530539 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700540 }
541
542 urb = usb_alloc_urb(0, GFP_KERNEL);
543 if (!urb) {
544 pr_err("unable to allocate urb");
545 ksb_free_data_pkt(pkt);
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530546 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700547 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700548
549 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
550 pkt->buf, pkt->len,
551 ksb_rx_cb, pkt);
552 usb_anchor_urb(urb, &ksb->submitted);
553
554 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
555
Hemant Kumarb3779d12012-09-16 20:28:56 -0700556 atomic_inc(&ksb->rx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700557 ret = usb_submit_urb(urb, GFP_KERNEL);
558 if (ret) {
559 pr_err("in urb submission failed");
560 usb_unanchor_urb(urb);
561 usb_free_urb(urb);
562 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700563 atomic_dec(&ksb->rx_pending_cnt);
564 wake_up(&ksb->pending_urb_wait);
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530565 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700566 }
567
Vamsi Krishna5b944712012-06-29 18:36:23 -0700568 usb_free_urb(urb);
569 }
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530570 if (put)
571 usb_autopm_put_interface_async(ksb->ifc);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700572}
573
574static int
575ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
576{
577 __u8 ifc_num;
578 struct usb_host_interface *ifc_desc;
579 struct usb_endpoint_descriptor *ep_desc;
580 int i;
581 struct ks_bridge *ksb;
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700582 unsigned long flags;
583 struct data_pkt *pkt;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700584
585 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
586
587 switch (id->idProduct) {
588 case 0x9008:
589 if (ifc_num != 0)
590 return -ENODEV;
591 ksb = __ksb[BOOT_BRIDGE_INDEX];
592 break;
593 case 0x9048:
594 case 0x904C:
Hemant Kumarcfa601a2012-12-19 11:23:11 -0800595 case 0x9075:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700596 if (ifc_num != 2)
597 return -ENODEV;
598 ksb = __ksb[EFS_BRIDGE_INDEX];
599 break;
600 default:
601 return -ENODEV;
602 }
603
604 if (!ksb) {
605 pr_err("ksb is not initialized");
606 return -ENODEV;
607 }
608
609 ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
610 ksb->ifc = ifc;
611 ifc_desc = ifc->cur_altsetting;
612
613 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
614 ep_desc = &ifc_desc->endpoint[i].desc;
615
616 if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
617 ksb->in_epAddr = ep_desc->bEndpointAddress;
618
619 if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
620 ksb->out_epAddr = ep_desc->bEndpointAddress;
621 }
622
623 if (!(ksb->in_epAddr && ksb->out_epAddr)) {
624 pr_err("could not find bulk in and bulk out endpoints");
625 usb_put_dev(ksb->udev);
626 ksb->ifc = NULL;
627 return -ENODEV;
628 }
629
630 ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
631 ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
632
633 usb_set_intfdata(ifc, ksb);
634 set_bit(USB_DEV_CONNECTED, &ksb->flags);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700635 atomic_set(&ksb->tx_pending_cnt, 0);
636 atomic_set(&ksb->rx_pending_cnt, 0);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700637
638 dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
639
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700640 /*free up stale buffers if any from previous disconnect*/
641 spin_lock_irqsave(&ksb->lock, flags);
642 while (!list_empty(&ksb->to_ks_list)) {
643 pkt = list_first_entry(&ksb->to_ks_list,
644 struct data_pkt, list);
645 list_del_init(&pkt->list);
646 ksb_free_data_pkt(pkt);
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700647 }
648 while (!list_empty(&ksb->to_mdm_list)) {
649 pkt = list_first_entry(&ksb->to_mdm_list,
650 struct data_pkt, list);
651 list_del_init(&pkt->list);
652 ksb_free_data_pkt(pkt);
653 }
654 spin_unlock_irqrestore(&ksb->lock, flags);
655
Hemant Kumarda86bd22012-08-24 19:42:31 -0700656 ksb->fs_dev = (struct miscdevice *)id->driver_info;
657 misc_register(ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700658
Hemant Kumard26076c2012-09-07 19:00:21 -0700659 ifc->needs_remote_wakeup = 1;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700660 usb_enable_autosuspend(ksb->udev);
661
662 pr_debug("usb dev connected");
663
664 return 0;
665}
666
667static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
668{
669 struct ks_bridge *ksb = usb_get_intfdata(ifc);
670
671 dbg_log_event(ksb, "SUSPEND", 0, 0);
672
Vamsi Krishna5b944712012-06-29 18:36:23 -0700673 usb_kill_anchored_urbs(&ksb->submitted);
674
675 return 0;
676}
677
678static int ksb_usb_resume(struct usb_interface *ifc)
679{
680 struct ks_bridge *ksb = usb_get_intfdata(ifc);
681
682 dbg_log_event(ksb, "RESUME", 0, 0);
683
684 if (test_bit(FILE_OPENED, &ksb->flags))
685 queue_work(ksb->wq, &ksb->start_rx_work);
686
687 return 0;
688}
689
690static void ksb_usb_disconnect(struct usb_interface *ifc)
691{
692 struct ks_bridge *ksb = usb_get_intfdata(ifc);
693 unsigned long flags;
694 struct data_pkt *pkt;
695
696 dbg_log_event(ksb, "PID-DETACH", 0, 0);
697
698 clear_bit(USB_DEV_CONNECTED, &ksb->flags);
699 wake_up(&ksb->ks_wait_q);
700 cancel_work_sync(&ksb->to_mdm_work);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700701 cancel_work_sync(&ksb->start_rx_work);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700702
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700703 misc_deregister(ksb->fs_dev);
704
Vamsi Krishna5b944712012-06-29 18:36:23 -0700705 usb_kill_anchored_urbs(&ksb->submitted);
706
Hemant Kumarb3779d12012-09-16 20:28:56 -0700707 wait_event_interruptible_timeout(
708 ksb->pending_urb_wait,
709 !atomic_read(&ksb->tx_pending_cnt) &&
710 !atomic_read(&ksb->rx_pending_cnt),
711 msecs_to_jiffies(PENDING_URB_TIMEOUT));
712
Vamsi Krishna5b944712012-06-29 18:36:23 -0700713 spin_lock_irqsave(&ksb->lock, flags);
714 while (!list_empty(&ksb->to_ks_list)) {
715 pkt = list_first_entry(&ksb->to_ks_list,
716 struct data_pkt, list);
717 list_del_init(&pkt->list);
718 ksb_free_data_pkt(pkt);
719 }
720 while (!list_empty(&ksb->to_mdm_list)) {
721 pkt = list_first_entry(&ksb->to_mdm_list,
722 struct data_pkt, list);
723 list_del_init(&pkt->list);
724 ksb_free_data_pkt(pkt);
725 }
726 spin_unlock_irqrestore(&ksb->lock, flags);
727
Hemant Kumard26076c2012-09-07 19:00:21 -0700728 ifc->needs_remote_wakeup = 0;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700729 usb_put_dev(ksb->udev);
730 ksb->ifc = NULL;
731 usb_set_intfdata(ifc, NULL);
732
733 return;
734}
735
736static struct usb_driver ksb_usb_driver = {
737 .name = "ks_bridge",
738 .probe = ksb_usb_probe,
739 .disconnect = ksb_usb_disconnect,
740 .suspend = ksb_usb_suspend,
741 .resume = ksb_usb_resume,
742 .id_table = ksb_usb_ids,
743 .supports_autosuspend = 1,
744};
745
746static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
747{
748 unsigned long flags;
749 struct ks_bridge *ksb = s->private;
750 int i;
751
752 read_lock_irqsave(&ksb->dbg_lock, flags);
753 for (i = 0; i < DBG_MAX_MSG; i++) {
754 if (i == (ksb->dbg_idx - 1))
755 seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
756 else
757 seq_printf(s, "%s\n", ksb->dbgbuf[i]);
758 }
759 read_unlock_irqrestore(&ksb->dbg_lock, flags);
760
761 return 0;
762}
763
764static int ksb_debug_open(struct inode *ip, struct file *fp)
765{
766 return single_open(fp, ksb_debug_show, ip->i_private);
767
768 return 0;
769}
770
771static const struct file_operations dbg_fops = {
772 .open = ksb_debug_open,
773 .read = seq_read,
774 .llseek = seq_lseek,
775 .release = single_release,
776};
777static struct dentry *dbg_dir;
778static int __init ksb_init(void)
779{
780 struct ks_bridge *ksb;
781 int num_instances = 0;
782 int ret = 0;
783 int i;
784
785 dbg_dir = debugfs_create_dir("ks_bridge", NULL);
786 if (IS_ERR(dbg_dir))
787 pr_err("unable to create debug dir");
788
789 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
790 ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
791 if (!ksb) {
792 pr_err("unable to allocat mem for ks_bridge");
Hemant Kumarda86bd22012-08-24 19:42:31 -0700793 ret = -ENOMEM;
794 goto dev_free;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700795 }
796 __ksb[i] = ksb;
797
798 ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
799 if (!ksb->name) {
800 pr_info("unable to allocate name");
801 kfree(ksb);
802 ret = -ENOMEM;
803 goto dev_free;
804 }
805
806 spin_lock_init(&ksb->lock);
807 INIT_LIST_HEAD(&ksb->to_mdm_list);
808 INIT_LIST_HEAD(&ksb->to_ks_list);
809 init_waitqueue_head(&ksb->ks_wait_q);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700810 init_waitqueue_head(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700811 ksb->wq = create_singlethread_workqueue(ksb->name);
812 if (!ksb->wq) {
813 pr_err("unable to allocate workqueue");
814 kfree(ksb->name);
815 kfree(ksb);
816 ret = -ENOMEM;
817 goto dev_free;
818 }
819
820 INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
821 INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
822 init_usb_anchor(&ksb->submitted);
823
824 ksb->dbg_idx = 0;
825 ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
826
827 if (!IS_ERR(dbg_dir))
828 debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
829 ksb, &dbg_fops);
830
831 num_instances++;
832 }
833
834 ret = usb_register(&ksb_usb_driver);
835 if (ret) {
836 pr_err("unable to register ks bridge driver");
837 goto dev_free;
838 }
839
840 pr_info("init done");
841
842 return 0;
843
844dev_free:
845 if (!IS_ERR(dbg_dir))
846 debugfs_remove_recursive(dbg_dir);
847
848 for (i = 0; i < num_instances; i++) {
849 ksb = __ksb[i];
850
851 destroy_workqueue(ksb->wq);
852 kfree(ksb->name);
853 kfree(ksb);
854 }
855
856 return ret;
857
858}
859
860static void __exit ksb_exit(void)
861{
862 struct ks_bridge *ksb;
863 int i;
864
865 if (!IS_ERR(dbg_dir))
866 debugfs_remove_recursive(dbg_dir);
867
868 usb_deregister(&ksb_usb_driver);
869
870 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
871 ksb = __ksb[i];
872
873 destroy_workqueue(ksb->wq);
874 kfree(ksb->name);
875 kfree(ksb);
876 }
877}
878
879module_init(ksb_init);
880module_exit(ksb_exit);
881
882MODULE_DESCRIPTION(DRIVER_DESC);
883MODULE_VERSION(DRIVER_VERSION);
884MODULE_LICENSE("GPL v2");