blob: cb47b729b4662c55a818053b0101a6f11a216026 [file] [log] [blame]
Vamsi Krishna5b944712012-06-29 18:36:23 -07001/*
Pavankumar Kondeti4fde7d42012-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
51
52struct ks_bridge {
53 char *name;
54 spinlock_t lock;
55 struct workqueue_struct *wq;
56 struct work_struct to_mdm_work;
57 struct work_struct start_rx_work;
58 struct list_head to_mdm_list;
59 struct list_head to_ks_list;
60 wait_queue_head_t ks_wait_q;
Hemant Kumar38980ec42012-08-24 19:42:31 -070061 struct miscdevice *fs_dev;
Vamsi Krishna5b944712012-06-29 18:36:23 -070062
63 /* usb specific */
64 struct usb_device *udev;
65 struct usb_interface *ifc;
66 __u8 in_epAddr;
67 __u8 out_epAddr;
68 unsigned int in_pipe;
69 unsigned int out_pipe;
70 struct usb_anchor submitted;
71
72 unsigned long flags;
Vamsi Krishna5b944712012-06-29 18:36:23 -070073
74#define DBG_MSG_LEN 40
75#define DBG_MAX_MSG 500
76 unsigned int dbg_idx;
77 rwlock_t dbg_lock;
78 char (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
79};
80struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
81
82/* by default debugging is enabled */
83static unsigned int enable_dbg = 1;
84module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
85
86static void
87dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
88{
89 unsigned long flags;
90 unsigned long long t;
91 unsigned long nanosec;
92
93 if (!enable_dbg)
94 return;
95
96 write_lock_irqsave(&ksb->dbg_lock, flags);
97 t = cpu_clock(smp_processor_id());
98 nanosec = do_div(t, 1000000000)/1000;
99 scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
100 (unsigned long)t, nanosec, event, d1, d2);
101
102 ksb->dbg_idx++;
103 ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
104 write_unlock_irqrestore(&ksb->dbg_lock, flags);
105}
106
107static
108struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
109{
110 struct data_pkt *pkt;
111
112 pkt = kzalloc(sizeof(struct data_pkt), flags);
113 if (!pkt) {
114 pr_err("failed to allocate data packet\n");
115 return ERR_PTR(-ENOMEM);
116 }
117
118 pkt->buf = kmalloc(count, flags);
119 if (!pkt->buf) {
120 pr_err("failed to allocate data buffer\n");
121 kfree(pkt);
122 return ERR_PTR(-ENOMEM);
123 }
124
125 pkt->len = count;
126 INIT_LIST_HEAD(&pkt->list);
127 pkt->ctxt = ctxt;
128
129 return pkt;
130}
131
132static void ksb_free_data_pkt(struct data_pkt *pkt)
133{
134 kfree(pkt->buf);
135 kfree(pkt);
136}
137
138
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530139static void
140submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700141static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
142 size_t count, loff_t *pos)
143{
144 int ret;
145 unsigned long flags;
146 struct ks_bridge *ksb = fp->private_data;
147 struct data_pkt *pkt;
148 size_t space, copied;
149
150read_start:
151 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
152 return -ENODEV;
153
154 spin_lock_irqsave(&ksb->lock, flags);
155 if (list_empty(&ksb->to_ks_list)) {
156 spin_unlock_irqrestore(&ksb->lock, flags);
157 ret = wait_event_interruptible(ksb->ks_wait_q,
158 !list_empty(&ksb->to_ks_list) ||
159 !test_bit(USB_DEV_CONNECTED, &ksb->flags));
160 if (ret < 0)
161 return ret;
162
163 goto read_start;
164 }
165
166 space = count;
167 copied = 0;
168 while (!list_empty(&ksb->to_ks_list) && space) {
169 size_t len;
170
171 pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
Hemant Kumard45f96c2012-09-24 12:32:32 -0700172 len = min_t(size_t, space, pkt->len - pkt->n_read);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700173 spin_unlock_irqrestore(&ksb->lock, flags);
174
Hemant Kumard45f96c2012-09-24 12:32:32 -0700175 ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700176 if (ret) {
177 pr_err("copy_to_user failed err:%d\n", ret);
178 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700179 return ret;
180 }
181
Hemant Kumard45f96c2012-09-24 12:32:32 -0700182 pkt->n_read += len;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700183 space -= len;
184 copied += len;
185
186 spin_lock_irqsave(&ksb->lock, flags);
187 if (pkt->n_read == pkt->len) {
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530188 /*
189 * re-init the packet and queue it
190 * for more data.
191 */
Vamsi Krishna5b944712012-06-29 18:36:23 -0700192 list_del_init(&pkt->list);
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530193 pkt->n_read = 0;
194 pkt->len = MAX_DATA_PKT_SIZE;
195 spin_unlock_irqrestore(&ksb->lock, flags);
196 submit_one_urb(ksb, GFP_KERNEL, pkt);
197 spin_lock_irqsave(&ksb->lock, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700198 }
199 }
200 spin_unlock_irqrestore(&ksb->lock, flags);
201
202 dbg_log_event(ksb, "KS_READ", copied, 0);
203
204 pr_debug("count:%d space:%d copied:%d", count, space, copied);
205
206 return copied;
207}
208
209static void ksb_tx_cb(struct urb *urb)
210{
211 struct data_pkt *pkt = urb->context;
212 struct ks_bridge *ksb = pkt->ctxt;
213
214 dbg_log_event(ksb, "C TX_URB", urb->status, 0);
215 pr_debug("status:%d", urb->status);
216
217 if (ksb->ifc)
218 usb_autopm_put_interface_async(ksb->ifc);
219
220 if (urb->status < 0)
221 pr_err_ratelimited("urb failed with err:%d", urb->status);
222
223 ksb_free_data_pkt(pkt);
224}
225
226static void ksb_tomdm_work(struct work_struct *w)
227{
228 struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
229 struct data_pkt *pkt;
230 unsigned long flags;
231 struct urb *urb;
232 int ret;
233
234 spin_lock_irqsave(&ksb->lock, flags);
235 while (!list_empty(&ksb->to_mdm_list)
236 && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
237 pkt = list_first_entry(&ksb->to_mdm_list,
238 struct data_pkt, list);
239 list_del_init(&pkt->list);
240 spin_unlock_irqrestore(&ksb->lock, flags);
241
242 urb = usb_alloc_urb(0, GFP_KERNEL);
243 if (!urb) {
244 pr_err_ratelimited("unable to allocate urb");
245 ksb_free_data_pkt(pkt);
246 return;
247 }
248
249 ret = usb_autopm_get_interface(ksb->ifc);
250 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
251 pr_err_ratelimited("autopm_get failed:%d", ret);
252 usb_free_urb(urb);
253 ksb_free_data_pkt(pkt);
254 return;
255 }
256 usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
257 pkt->buf, pkt->len, ksb_tx_cb, pkt);
258 usb_anchor_urb(urb, &ksb->submitted);
259
260 dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
261
262 ret = usb_submit_urb(urb, GFP_KERNEL);
263 if (ret) {
264 pr_err("out urb submission failed");
265 usb_unanchor_urb(urb);
266 usb_free_urb(urb);
267 ksb_free_data_pkt(pkt);
268 usb_autopm_put_interface(ksb->ifc);
269 return;
270 }
271
Hemant Kumar9b230b52012-09-19 12:40:11 -0700272 usb_free_urb(urb);
273
Vamsi Krishna5b944712012-06-29 18:36:23 -0700274 spin_lock_irqsave(&ksb->lock, flags);
275 }
276 spin_unlock_irqrestore(&ksb->lock, flags);
277}
278
279static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
280 size_t count, loff_t *pos)
281{
282 int ret;
283 struct data_pkt *pkt;
284 unsigned long flags;
285 struct ks_bridge *ksb = fp->private_data;
286
Pavankumar Kondeti4fde7d42012-12-28 17:15:41 +0530287
288 if (count > MAX_DATA_PKT_SIZE)
289 count = MAX_DATA_PKT_SIZE;
290
Vamsi Krishna5b944712012-06-29 18:36:23 -0700291 pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
292 if (IS_ERR(pkt)) {
293 pr_err("unable to allocate data packet");
294 return PTR_ERR(pkt);
295 }
296
297 ret = copy_from_user(pkt->buf, buf, count);
298 if (ret) {
299 pr_err("copy_from_user failed: err:%d", ret);
300 ksb_free_data_pkt(pkt);
301 return ret;
302 }
303
304 spin_lock_irqsave(&ksb->lock, flags);
305 list_add_tail(&pkt->list, &ksb->to_mdm_list);
306 spin_unlock_irqrestore(&ksb->lock, flags);
307
308 queue_work(ksb->wq, &ksb->to_mdm_work);
309
310 return count;
311}
312
313static int efs_fs_open(struct inode *ip, struct file *fp)
314{
315 struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
316
317 pr_debug(":%s", ksb->name);
318 dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
319
320 if (!ksb) {
321 pr_err("ksb is being removed");
322 return -ENODEV;
323 }
324
325 fp->private_data = ksb;
326 set_bit(FILE_OPENED, &ksb->flags);
327
328 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
329 queue_work(ksb->wq, &ksb->start_rx_work);
330
331 return 0;
332}
333
334static int ksb_fs_open(struct inode *ip, struct file *fp)
335{
336 struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
337
338 pr_debug(":%s", ksb->name);
339 dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
340
341 if (!ksb) {
342 pr_err("ksb is being removed");
343 return -ENODEV;
344 }
345
346 fp->private_data = ksb;
347 set_bit(FILE_OPENED, &ksb->flags);
348
349 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
350 queue_work(ksb->wq, &ksb->start_rx_work);
351
352 return 0;
353}
354
355static int ksb_fs_release(struct inode *ip, struct file *fp)
356{
357 struct ks_bridge *ksb = fp->private_data;
358
359 pr_debug(":%s", ksb->name);
360 dbg_log_event(ksb, "FS-RELEASE", 0, 0);
361
362 clear_bit(FILE_OPENED, &ksb->flags);
363 fp->private_data = NULL;
364
365 return 0;
366}
367
368static const struct file_operations ksb_fops = {
369 .owner = THIS_MODULE,
370 .read = ksb_fs_read,
371 .write = ksb_fs_write,
372 .open = ksb_fs_open,
373 .release = ksb_fs_release,
374};
375
376static struct miscdevice ksb_fboot_dev = {
377 .minor = MISC_DYNAMIC_MINOR,
378 .name = "ks_bridge",
379 .fops = &ksb_fops,
380};
381
382static const struct file_operations efs_fops = {
383 .owner = THIS_MODULE,
384 .read = ksb_fs_read,
385 .write = ksb_fs_write,
386 .open = efs_fs_open,
387 .release = ksb_fs_release,
388};
389
390static struct miscdevice ksb_efs_dev = {
391 .minor = MISC_DYNAMIC_MINOR,
392 .name = "efs_bridge",
393 .fops = &efs_fops,
394};
395
396static const struct usb_device_id ksb_usb_ids[] = {
397 { USB_DEVICE(0x5c6, 0x9008),
398 .driver_info = (unsigned long)&ksb_fboot_dev, },
399 { USB_DEVICE(0x5c6, 0x9048),
400 .driver_info = (unsigned long)&ksb_efs_dev, },
401 { USB_DEVICE(0x5c6, 0x904C),
402 .driver_info = (unsigned long)&ksb_efs_dev, },
403
404 {} /* terminating entry */
405};
406MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
407
408static void ksb_rx_cb(struct urb *urb);
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530409static void
410submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700411{
Vamsi Krishna5b944712012-06-29 18:36:23 -0700412 struct urb *urb;
413 int ret;
414
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530415 urb = usb_alloc_urb(0, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700416 if (!urb) {
417 pr_err("unable to allocate urb");
418 ksb_free_data_pkt(pkt);
419 return;
420 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700421
422 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
423 pkt->buf, pkt->len,
424 ksb_rx_cb, pkt);
425 usb_anchor_urb(urb, &ksb->submitted);
426
427 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
428
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530429 ret = usb_submit_urb(urb, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700430 if (ret) {
431 pr_err("in urb submission failed");
432 usb_unanchor_urb(urb);
433 usb_free_urb(urb);
434 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700435 return;
436 }
437
438 usb_free_urb(urb);
439}
440static void ksb_rx_cb(struct urb *urb)
441{
442 struct data_pkt *pkt = urb->context;
443 struct ks_bridge *ksb = pkt->ctxt;
444
445 dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
446
447 pr_debug("status:%d actual:%d", urb->status, urb->actual_length);
448
Hemant Kumara6194c12012-08-31 18:38:32 -0700449 /*non zero len of data received while unlinking urb*/
450 if (urb->status == -ENOENT && urb->actual_length > 0)
451 goto add_to_list;
452
Vamsi Krishna5b944712012-06-29 18:36:23 -0700453 if (urb->status < 0) {
Hemant Kumara6194c12012-08-31 18:38:32 -0700454 if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
455 && urb->status != -EPROTO)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700456 pr_err_ratelimited("urb failed with err:%d",
457 urb->status);
458 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700459 return;
460 }
461
462 if (urb->actual_length == 0) {
Pavankumar Kondeti009bbd62012-12-14 15:12:46 +0530463 submit_one_urb(ksb, GFP_ATOMIC, pkt);
464 return;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700465 }
466
Hemant Kumara6194c12012-08-31 18:38:32 -0700467add_to_list:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700468 spin_lock(&ksb->lock);
469 pkt->len = urb->actual_length;
470 list_add_tail(&pkt->list, &ksb->to_ks_list);
471 spin_unlock(&ksb->lock);
472
473 /* wake up read thread */
474 wake_up(&ksb->ks_wait_q);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700475}
476
477static void ksb_start_rx_work(struct work_struct *w)
478{
479 struct ks_bridge *ksb =
480 container_of(w, struct ks_bridge, start_rx_work);
481 struct data_pkt *pkt;
482 struct urb *urb;
483 int i = 0;
484 int ret;
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530485 bool put = true;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700486
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530487 ret = usb_autopm_get_interface(ksb->ifc);
488 if (ret < 0) {
489 if (ret != -EAGAIN && ret != -EACCES) {
490 pr_err_ratelimited("autopm_get failed:%d", ret);
491 return;
492 }
493 put = false;
494 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700495 for (i = 0; i < NO_RX_REQS; i++) {
496 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
497 if (IS_ERR(pkt)) {
498 pr_err("unable to allocate data pkt");
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530499 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700500 }
501
502 urb = usb_alloc_urb(0, GFP_KERNEL);
503 if (!urb) {
504 pr_err("unable to allocate urb");
505 ksb_free_data_pkt(pkt);
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530506 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700507 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700508
509 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
510 pkt->buf, pkt->len,
511 ksb_rx_cb, pkt);
512 usb_anchor_urb(urb, &ksb->submitted);
513
514 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
515
516 ret = usb_submit_urb(urb, GFP_KERNEL);
517 if (ret) {
518 pr_err("in urb submission failed");
519 usb_unanchor_urb(urb);
520 usb_free_urb(urb);
521 ksb_free_data_pkt(pkt);
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530522 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700523 }
524
Vamsi Krishna5b944712012-06-29 18:36:23 -0700525 usb_free_urb(urb);
526 }
Pavankumar Kondeti76fe5292013-01-21 21:14:26 +0530527 if (put)
528 usb_autopm_put_interface_async(ksb->ifc);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700529}
530
531static int
532ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
533{
534 __u8 ifc_num;
535 struct usb_host_interface *ifc_desc;
536 struct usb_endpoint_descriptor *ep_desc;
537 int i;
538 struct ks_bridge *ksb;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700539
540 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
541
542 switch (id->idProduct) {
543 case 0x9008:
544 if (ifc_num != 0)
545 return -ENODEV;
546 ksb = __ksb[BOOT_BRIDGE_INDEX];
547 break;
548 case 0x9048:
549 case 0x904C:
550 if (ifc_num != 2)
551 return -ENODEV;
552 ksb = __ksb[EFS_BRIDGE_INDEX];
553 break;
554 default:
555 return -ENODEV;
556 }
557
558 if (!ksb) {
559 pr_err("ksb is not initialized");
560 return -ENODEV;
561 }
562
563 ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
564 ksb->ifc = ifc;
565 ifc_desc = ifc->cur_altsetting;
566
567 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
568 ep_desc = &ifc_desc->endpoint[i].desc;
569
570 if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
571 ksb->in_epAddr = ep_desc->bEndpointAddress;
572
573 if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
574 ksb->out_epAddr = ep_desc->bEndpointAddress;
575 }
576
577 if (!(ksb->in_epAddr && ksb->out_epAddr)) {
578 pr_err("could not find bulk in and bulk out endpoints");
579 usb_put_dev(ksb->udev);
580 ksb->ifc = NULL;
581 return -ENODEV;
582 }
583
584 ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
585 ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
586
587 usb_set_intfdata(ifc, ksb);
588 set_bit(USB_DEV_CONNECTED, &ksb->flags);
589
590 dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
591
Hemant Kumar38980ec42012-08-24 19:42:31 -0700592 ksb->fs_dev = (struct miscdevice *)id->driver_info;
593 misc_register(ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700594
Hemant Kumarf292a322012-09-07 19:00:21 -0700595 ifc->needs_remote_wakeup = 1;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700596 usb_enable_autosuspend(ksb->udev);
597
598 pr_debug("usb dev connected");
599
600 return 0;
601}
602
603static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
604{
605 struct ks_bridge *ksb = usb_get_intfdata(ifc);
606
607 dbg_log_event(ksb, "SUSPEND", 0, 0);
608
Vamsi Krishna5b944712012-06-29 18:36:23 -0700609 usb_kill_anchored_urbs(&ksb->submitted);
610
611 return 0;
612}
613
614static int ksb_usb_resume(struct usb_interface *ifc)
615{
616 struct ks_bridge *ksb = usb_get_intfdata(ifc);
617
618 dbg_log_event(ksb, "RESUME", 0, 0);
619
620 if (test_bit(FILE_OPENED, &ksb->flags))
621 queue_work(ksb->wq, &ksb->start_rx_work);
622
623 return 0;
624}
625
626static void ksb_usb_disconnect(struct usb_interface *ifc)
627{
628 struct ks_bridge *ksb = usb_get_intfdata(ifc);
629 unsigned long flags;
630 struct data_pkt *pkt;
631
632 dbg_log_event(ksb, "PID-DETACH", 0, 0);
633
634 clear_bit(USB_DEV_CONNECTED, &ksb->flags);
635 wake_up(&ksb->ks_wait_q);
636 cancel_work_sync(&ksb->to_mdm_work);
637
Hemant Kumar38980ec42012-08-24 19:42:31 -0700638 misc_deregister(ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700639
Hemant Kumar38980ec42012-08-24 19:42:31 -0700640 usb_kill_anchored_urbs(&ksb->submitted);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700641 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);
647 }
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 Kumarf292a322012-09-07 19:00:21 -0700656 ifc->needs_remote_wakeup = 0;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700657 usb_put_dev(ksb->udev);
658 ksb->ifc = NULL;
659 usb_set_intfdata(ifc, NULL);
660
661 return;
662}
663
664static struct usb_driver ksb_usb_driver = {
665 .name = "ks_bridge",
666 .probe = ksb_usb_probe,
667 .disconnect = ksb_usb_disconnect,
668 .suspend = ksb_usb_suspend,
669 .resume = ksb_usb_resume,
670 .id_table = ksb_usb_ids,
671 .supports_autosuspend = 1,
672};
673
674static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
675{
676 unsigned long flags;
677 struct ks_bridge *ksb = s->private;
678 int i;
679
680 read_lock_irqsave(&ksb->dbg_lock, flags);
681 for (i = 0; i < DBG_MAX_MSG; i++) {
682 if (i == (ksb->dbg_idx - 1))
683 seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
684 else
685 seq_printf(s, "%s\n", ksb->dbgbuf[i]);
686 }
687 read_unlock_irqrestore(&ksb->dbg_lock, flags);
688
689 return 0;
690}
691
692static int ksb_debug_open(struct inode *ip, struct file *fp)
693{
694 return single_open(fp, ksb_debug_show, ip->i_private);
695
696 return 0;
697}
698
699static const struct file_operations dbg_fops = {
700 .open = ksb_debug_open,
701 .read = seq_read,
702 .llseek = seq_lseek,
703 .release = single_release,
704};
705static struct dentry *dbg_dir;
706static int __init ksb_init(void)
707{
708 struct ks_bridge *ksb;
709 int num_instances = 0;
710 int ret = 0;
711 int i;
712
713 dbg_dir = debugfs_create_dir("ks_bridge", NULL);
714 if (IS_ERR(dbg_dir))
715 pr_err("unable to create debug dir");
716
717 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
718 ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
719 if (!ksb) {
720 pr_err("unable to allocat mem for ks_bridge");
Hemant Kumar38980ec42012-08-24 19:42:31 -0700721 ret = -ENOMEM;
722 goto dev_free;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700723 }
724 __ksb[i] = ksb;
725
726 ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
727 if (!ksb->name) {
728 pr_info("unable to allocate name");
729 kfree(ksb);
730 ret = -ENOMEM;
731 goto dev_free;
732 }
733
734 spin_lock_init(&ksb->lock);
735 INIT_LIST_HEAD(&ksb->to_mdm_list);
736 INIT_LIST_HEAD(&ksb->to_ks_list);
737 init_waitqueue_head(&ksb->ks_wait_q);
738 ksb->wq = create_singlethread_workqueue(ksb->name);
739 if (!ksb->wq) {
740 pr_err("unable to allocate workqueue");
741 kfree(ksb->name);
742 kfree(ksb);
743 ret = -ENOMEM;
744 goto dev_free;
745 }
746
747 INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
748 INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
749 init_usb_anchor(&ksb->submitted);
750
751 ksb->dbg_idx = 0;
752 ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
753
754 if (!IS_ERR(dbg_dir))
755 debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
756 ksb, &dbg_fops);
757
758 num_instances++;
759 }
760
761 ret = usb_register(&ksb_usb_driver);
762 if (ret) {
763 pr_err("unable to register ks bridge driver");
764 goto dev_free;
765 }
766
767 pr_info("init done");
768
769 return 0;
770
771dev_free:
772 if (!IS_ERR(dbg_dir))
773 debugfs_remove_recursive(dbg_dir);
774
775 for (i = 0; i < num_instances; i++) {
776 ksb = __ksb[i];
777
778 destroy_workqueue(ksb->wq);
779 kfree(ksb->name);
780 kfree(ksb);
781 }
782
783 return ret;
784
785}
786
787static void __exit ksb_exit(void)
788{
789 struct ks_bridge *ksb;
790 int i;
791
792 if (!IS_ERR(dbg_dir))
793 debugfs_remove_recursive(dbg_dir);
794
795 usb_deregister(&ksb_usb_driver);
796
797 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
798 ksb = __ksb[i];
799
800 destroy_workqueue(ksb->wq);
801 kfree(ksb->name);
802 kfree(ksb);
803 }
804}
805
806module_init(ksb_init);
807module_exit(ksb_exit);
808
809MODULE_DESCRIPTION(DRIVER_DESC);
810MODULE_VERSION(DRIVER_VERSION);
811MODULE_LICENSE("GPL v2");