blob: d2461a5af5f8694ad8b10b48c5de9f60ba87158d [file] [log] [blame]
Vamsi Krishna5b944712012-06-29 18:36:23 -07001/*
2 * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3 *
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 Kumarda86bd22012-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;
73 unsigned int alloced_read_pkts;
74
75#define DBG_MSG_LEN 40
76#define DBG_MAX_MSG 500
77 unsigned int dbg_idx;
78 rwlock_t dbg_lock;
79 char (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
80};
81struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
82
83/* by default debugging is enabled */
84static unsigned int enable_dbg = 1;
85module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
86
87static void
88dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
89{
90 unsigned long flags;
91 unsigned long long t;
92 unsigned long nanosec;
93
94 if (!enable_dbg)
95 return;
96
97 write_lock_irqsave(&ksb->dbg_lock, flags);
98 t = cpu_clock(smp_processor_id());
99 nanosec = do_div(t, 1000000000)/1000;
100 scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
101 (unsigned long)t, nanosec, event, d1, d2);
102
103 ksb->dbg_idx++;
104 ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
105 write_unlock_irqrestore(&ksb->dbg_lock, flags);
106}
107
108static
109struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
110{
111 struct data_pkt *pkt;
112
113 pkt = kzalloc(sizeof(struct data_pkt), flags);
114 if (!pkt) {
115 pr_err("failed to allocate data packet\n");
116 return ERR_PTR(-ENOMEM);
117 }
118
119 pkt->buf = kmalloc(count, flags);
120 if (!pkt->buf) {
121 pr_err("failed to allocate data buffer\n");
122 kfree(pkt);
123 return ERR_PTR(-ENOMEM);
124 }
125
126 pkt->len = count;
127 INIT_LIST_HEAD(&pkt->list);
128 pkt->ctxt = ctxt;
129
130 return pkt;
131}
132
133static void ksb_free_data_pkt(struct data_pkt *pkt)
134{
135 kfree(pkt->buf);
136 kfree(pkt);
137}
138
139
140static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
141 size_t count, loff_t *pos)
142{
143 int ret;
144 unsigned long flags;
145 struct ks_bridge *ksb = fp->private_data;
146 struct data_pkt *pkt;
147 size_t space, copied;
148
149read_start:
150 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
151 return -ENODEV;
152
153 spin_lock_irqsave(&ksb->lock, flags);
154 if (list_empty(&ksb->to_ks_list)) {
155 spin_unlock_irqrestore(&ksb->lock, flags);
156 ret = wait_event_interruptible(ksb->ks_wait_q,
157 !list_empty(&ksb->to_ks_list) ||
158 !test_bit(USB_DEV_CONNECTED, &ksb->flags));
159 if (ret < 0)
160 return ret;
161
162 goto read_start;
163 }
164
165 space = count;
166 copied = 0;
167 while (!list_empty(&ksb->to_ks_list) && space) {
168 size_t len;
169
170 pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
Hemant Kumarb48f4732012-09-24 12:32:32 -0700171 len = min_t(size_t, space, pkt->len - pkt->n_read);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700172 spin_unlock_irqrestore(&ksb->lock, flags);
173
Hemant Kumarb48f4732012-09-24 12:32:32 -0700174 ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700175 if (ret) {
176 pr_err("copy_to_user failed err:%d\n", ret);
177 ksb_free_data_pkt(pkt);
178 ksb->alloced_read_pkts--;
179 return ret;
180 }
181
Hemant Kumarb48f4732012-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) {
188 list_del_init(&pkt->list);
189 ksb_free_data_pkt(pkt);
190 ksb->alloced_read_pkts--;
191 }
192 }
193 spin_unlock_irqrestore(&ksb->lock, flags);
194
195 dbg_log_event(ksb, "KS_READ", copied, 0);
196
197 pr_debug("count:%d space:%d copied:%d", count, space, copied);
198
199 return copied;
200}
201
202static void ksb_tx_cb(struct urb *urb)
203{
204 struct data_pkt *pkt = urb->context;
205 struct ks_bridge *ksb = pkt->ctxt;
206
207 dbg_log_event(ksb, "C TX_URB", urb->status, 0);
208 pr_debug("status:%d", urb->status);
209
210 if (ksb->ifc)
211 usb_autopm_put_interface_async(ksb->ifc);
212
213 if (urb->status < 0)
214 pr_err_ratelimited("urb failed with err:%d", urb->status);
215
216 ksb_free_data_pkt(pkt);
217}
218
219static void ksb_tomdm_work(struct work_struct *w)
220{
221 struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
222 struct data_pkt *pkt;
223 unsigned long flags;
224 struct urb *urb;
225 int ret;
226
227 spin_lock_irqsave(&ksb->lock, flags);
228 while (!list_empty(&ksb->to_mdm_list)
229 && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
230 pkt = list_first_entry(&ksb->to_mdm_list,
231 struct data_pkt, list);
232 list_del_init(&pkt->list);
233 spin_unlock_irqrestore(&ksb->lock, flags);
234
235 urb = usb_alloc_urb(0, GFP_KERNEL);
236 if (!urb) {
237 pr_err_ratelimited("unable to allocate urb");
238 ksb_free_data_pkt(pkt);
239 return;
240 }
241
242 ret = usb_autopm_get_interface(ksb->ifc);
243 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
244 pr_err_ratelimited("autopm_get failed:%d", ret);
245 usb_free_urb(urb);
246 ksb_free_data_pkt(pkt);
247 return;
248 }
249 usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
250 pkt->buf, pkt->len, ksb_tx_cb, pkt);
251 usb_anchor_urb(urb, &ksb->submitted);
252
253 dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
254
255 ret = usb_submit_urb(urb, GFP_KERNEL);
256 if (ret) {
257 pr_err("out urb submission failed");
258 usb_unanchor_urb(urb);
259 usb_free_urb(urb);
260 ksb_free_data_pkt(pkt);
261 usb_autopm_put_interface(ksb->ifc);
262 return;
263 }
264
Hemant Kumar1432f6f2012-09-19 12:40:11 -0700265 usb_free_urb(urb);
266
Vamsi Krishna5b944712012-06-29 18:36:23 -0700267 spin_lock_irqsave(&ksb->lock, flags);
268 }
269 spin_unlock_irqrestore(&ksb->lock, flags);
270}
271
272static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
273 size_t count, loff_t *pos)
274{
275 int ret;
276 struct data_pkt *pkt;
277 unsigned long flags;
278 struct ks_bridge *ksb = fp->private_data;
279
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700280 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
281 return -ENODEV;
282
Vamsi Krishna5b944712012-06-29 18:36:23 -0700283 pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
284 if (IS_ERR(pkt)) {
285 pr_err("unable to allocate data packet");
286 return PTR_ERR(pkt);
287 }
288
289 ret = copy_from_user(pkt->buf, buf, count);
290 if (ret) {
291 pr_err("copy_from_user failed: err:%d", ret);
292 ksb_free_data_pkt(pkt);
293 return ret;
294 }
295
296 spin_lock_irqsave(&ksb->lock, flags);
297 list_add_tail(&pkt->list, &ksb->to_mdm_list);
298 spin_unlock_irqrestore(&ksb->lock, flags);
299
300 queue_work(ksb->wq, &ksb->to_mdm_work);
301
302 return count;
303}
304
305static int efs_fs_open(struct inode *ip, struct file *fp)
306{
307 struct ks_bridge *ksb = __ksb[EFS_BRIDGE_INDEX];
308
309 pr_debug(":%s", ksb->name);
310 dbg_log_event(ksb, "EFS-FS-OPEN", 0, 0);
311
312 if (!ksb) {
313 pr_err("ksb is being removed");
314 return -ENODEV;
315 }
316
317 fp->private_data = ksb;
318 set_bit(FILE_OPENED, &ksb->flags);
319
320 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
321 queue_work(ksb->wq, &ksb->start_rx_work);
322
323 return 0;
324}
325
326static int ksb_fs_open(struct inode *ip, struct file *fp)
327{
328 struct ks_bridge *ksb = __ksb[BOOT_BRIDGE_INDEX];
329
330 pr_debug(":%s", ksb->name);
331 dbg_log_event(ksb, "KS-FS-OPEN", 0, 0);
332
333 if (!ksb) {
334 pr_err("ksb is being removed");
335 return -ENODEV;
336 }
337
338 fp->private_data = ksb;
339 set_bit(FILE_OPENED, &ksb->flags);
340
341 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
342 queue_work(ksb->wq, &ksb->start_rx_work);
343
344 return 0;
345}
346
347static int ksb_fs_release(struct inode *ip, struct file *fp)
348{
349 struct ks_bridge *ksb = fp->private_data;
350
351 pr_debug(":%s", ksb->name);
352 dbg_log_event(ksb, "FS-RELEASE", 0, 0);
353
354 clear_bit(FILE_OPENED, &ksb->flags);
355 fp->private_data = NULL;
356
357 return 0;
358}
359
360static const struct file_operations ksb_fops = {
361 .owner = THIS_MODULE,
362 .read = ksb_fs_read,
363 .write = ksb_fs_write,
364 .open = ksb_fs_open,
365 .release = ksb_fs_release,
366};
367
368static struct miscdevice ksb_fboot_dev = {
369 .minor = MISC_DYNAMIC_MINOR,
370 .name = "ks_bridge",
371 .fops = &ksb_fops,
372};
373
374static const struct file_operations efs_fops = {
375 .owner = THIS_MODULE,
376 .read = ksb_fs_read,
377 .write = ksb_fs_write,
378 .open = efs_fs_open,
379 .release = ksb_fs_release,
380};
381
382static struct miscdevice ksb_efs_dev = {
383 .minor = MISC_DYNAMIC_MINOR,
384 .name = "efs_bridge",
385 .fops = &efs_fops,
386};
387
388static const struct usb_device_id ksb_usb_ids[] = {
389 { USB_DEVICE(0x5c6, 0x9008),
390 .driver_info = (unsigned long)&ksb_fboot_dev, },
391 { USB_DEVICE(0x5c6, 0x9048),
392 .driver_info = (unsigned long)&ksb_efs_dev, },
393 { USB_DEVICE(0x5c6, 0x904C),
394 .driver_info = (unsigned long)&ksb_efs_dev, },
395
396 {} /* terminating entry */
397};
398MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
399
400static void ksb_rx_cb(struct urb *urb);
401static void submit_one_urb(struct ks_bridge *ksb)
402{
403 struct data_pkt *pkt;
404 struct urb *urb;
405 int ret;
406
407 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_ATOMIC, ksb);
408 if (IS_ERR(pkt)) {
409 pr_err("unable to allocate data pkt");
410 return;
411 }
412
413 urb = usb_alloc_urb(0, GFP_ATOMIC);
414 if (!urb) {
415 pr_err("unable to allocate urb");
416 ksb_free_data_pkt(pkt);
417 return;
418 }
419 ksb->alloced_read_pkts++;
420
421 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
422 pkt->buf, pkt->len,
423 ksb_rx_cb, pkt);
424 usb_anchor_urb(urb, &ksb->submitted);
425
426 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
427
428 ret = usb_submit_urb(urb, GFP_ATOMIC);
429 if (ret) {
430 pr_err("in urb submission failed");
431 usb_unanchor_urb(urb);
432 usb_free_urb(urb);
433 ksb_free_data_pkt(pkt);
434 ksb->alloced_read_pkts--;
435 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 Kumar853ebf62012-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 Kumar853ebf62012-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);
459 ksb->alloced_read_pkts--;
460 return;
461 }
462
463 if (urb->actual_length == 0) {
464 ksb_free_data_pkt(pkt);
465 ksb->alloced_read_pkts--;
466 goto resubmit_urb;
467 }
468
Hemant Kumar853ebf62012-08-31 18:38:32 -0700469add_to_list:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700470 spin_lock(&ksb->lock);
471 pkt->len = urb->actual_length;
472 list_add_tail(&pkt->list, &ksb->to_ks_list);
473 spin_unlock(&ksb->lock);
474
475 /* wake up read thread */
476 wake_up(&ksb->ks_wait_q);
477
478resubmit_urb:
479 submit_one_urb(ksb);
480
481}
482
483static void ksb_start_rx_work(struct work_struct *w)
484{
485 struct ks_bridge *ksb =
486 container_of(w, struct ks_bridge, start_rx_work);
487 struct data_pkt *pkt;
488 struct urb *urb;
489 int i = 0;
490 int ret;
491
492 for (i = 0; i < NO_RX_REQS; i++) {
493 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
494 if (IS_ERR(pkt)) {
495 pr_err("unable to allocate data pkt");
496 return;
497 }
498
499 urb = usb_alloc_urb(0, GFP_KERNEL);
500 if (!urb) {
501 pr_err("unable to allocate urb");
502 ksb_free_data_pkt(pkt);
503 return;
504 }
505
506 ret = usb_autopm_get_interface(ksb->ifc);
507 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
508 pr_err_ratelimited("autopm_get failed:%d", ret);
509 usb_free_urb(urb);
510 ksb_free_data_pkt(pkt);
511 return;
512 }
513 ksb->alloced_read_pkts++;
514
515 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
516 pkt->buf, pkt->len,
517 ksb_rx_cb, pkt);
518 usb_anchor_urb(urb, &ksb->submitted);
519
520 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
521
522 ret = usb_submit_urb(urb, GFP_KERNEL);
523 if (ret) {
524 pr_err("in urb submission failed");
525 usb_unanchor_urb(urb);
526 usb_free_urb(urb);
527 ksb_free_data_pkt(pkt);
528 ksb->alloced_read_pkts--;
529 usb_autopm_put_interface(ksb->ifc);
530 return;
531 }
532
533 usb_autopm_put_interface_async(ksb->ifc);
534 usb_free_urb(urb);
535 }
536}
537
538static int
539ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
540{
541 __u8 ifc_num;
542 struct usb_host_interface *ifc_desc;
543 struct usb_endpoint_descriptor *ep_desc;
544 int i;
545 struct ks_bridge *ksb;
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700546 unsigned long flags;
547 struct data_pkt *pkt;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700548
549 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
550
551 switch (id->idProduct) {
552 case 0x9008:
553 if (ifc_num != 0)
554 return -ENODEV;
555 ksb = __ksb[BOOT_BRIDGE_INDEX];
556 break;
557 case 0x9048:
558 case 0x904C:
559 if (ifc_num != 2)
560 return -ENODEV;
561 ksb = __ksb[EFS_BRIDGE_INDEX];
562 break;
563 default:
564 return -ENODEV;
565 }
566
567 if (!ksb) {
568 pr_err("ksb is not initialized");
569 return -ENODEV;
570 }
571
572 ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
573 ksb->ifc = ifc;
574 ifc_desc = ifc->cur_altsetting;
575
576 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
577 ep_desc = &ifc_desc->endpoint[i].desc;
578
579 if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
580 ksb->in_epAddr = ep_desc->bEndpointAddress;
581
582 if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
583 ksb->out_epAddr = ep_desc->bEndpointAddress;
584 }
585
586 if (!(ksb->in_epAddr && ksb->out_epAddr)) {
587 pr_err("could not find bulk in and bulk out endpoints");
588 usb_put_dev(ksb->udev);
589 ksb->ifc = NULL;
590 return -ENODEV;
591 }
592
593 ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
594 ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
595
596 usb_set_intfdata(ifc, ksb);
597 set_bit(USB_DEV_CONNECTED, &ksb->flags);
598
599 dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
600
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700601 /*free up stale buffers if any from previous disconnect*/
602 spin_lock_irqsave(&ksb->lock, flags);
603 while (!list_empty(&ksb->to_ks_list)) {
604 pkt = list_first_entry(&ksb->to_ks_list,
605 struct data_pkt, list);
606 list_del_init(&pkt->list);
607 ksb_free_data_pkt(pkt);
608 ksb->alloced_read_pkts--;
609 }
610 while (!list_empty(&ksb->to_mdm_list)) {
611 pkt = list_first_entry(&ksb->to_mdm_list,
612 struct data_pkt, list);
613 list_del_init(&pkt->list);
614 ksb_free_data_pkt(pkt);
615 }
616 spin_unlock_irqrestore(&ksb->lock, flags);
617
Hemant Kumarda86bd22012-08-24 19:42:31 -0700618 ksb->fs_dev = (struct miscdevice *)id->driver_info;
619 misc_register(ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700620
Hemant Kumard26076c2012-09-07 19:00:21 -0700621 ifc->needs_remote_wakeup = 1;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700622 usb_enable_autosuspend(ksb->udev);
623
624 pr_debug("usb dev connected");
625
626 return 0;
627}
628
629static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
630{
631 struct ks_bridge *ksb = usb_get_intfdata(ifc);
632
633 dbg_log_event(ksb, "SUSPEND", 0, 0);
634
Hemant Kumar853ebf62012-08-31 18:38:32 -0700635 pr_debug("read cnt: %d", ksb->alloced_read_pkts);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700636
637 usb_kill_anchored_urbs(&ksb->submitted);
638
639 return 0;
640}
641
642static int ksb_usb_resume(struct usb_interface *ifc)
643{
644 struct ks_bridge *ksb = usb_get_intfdata(ifc);
645
646 dbg_log_event(ksb, "RESUME", 0, 0);
647
648 if (test_bit(FILE_OPENED, &ksb->flags))
649 queue_work(ksb->wq, &ksb->start_rx_work);
650
651 return 0;
652}
653
654static void ksb_usb_disconnect(struct usb_interface *ifc)
655{
656 struct ks_bridge *ksb = usb_get_intfdata(ifc);
657 unsigned long flags;
658 struct data_pkt *pkt;
659
660 dbg_log_event(ksb, "PID-DETACH", 0, 0);
661
662 clear_bit(USB_DEV_CONNECTED, &ksb->flags);
663 wake_up(&ksb->ks_wait_q);
664 cancel_work_sync(&ksb->to_mdm_work);
665
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700666 misc_deregister(ksb->fs_dev);
667
Vamsi Krishna5b944712012-06-29 18:36:23 -0700668 usb_kill_anchored_urbs(&ksb->submitted);
669
670 spin_lock_irqsave(&ksb->lock, flags);
671 while (!list_empty(&ksb->to_ks_list)) {
672 pkt = list_first_entry(&ksb->to_ks_list,
673 struct data_pkt, list);
674 list_del_init(&pkt->list);
675 ksb_free_data_pkt(pkt);
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700676 ksb->alloced_read_pkts--;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700677 }
678 while (!list_empty(&ksb->to_mdm_list)) {
679 pkt = list_first_entry(&ksb->to_mdm_list,
680 struct data_pkt, list);
681 list_del_init(&pkt->list);
682 ksb_free_data_pkt(pkt);
683 }
684 spin_unlock_irqrestore(&ksb->lock, flags);
685
Hemant Kumard26076c2012-09-07 19:00:21 -0700686 ifc->needs_remote_wakeup = 0;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700687 usb_put_dev(ksb->udev);
688 ksb->ifc = NULL;
689 usb_set_intfdata(ifc, NULL);
690
691 return;
692}
693
694static struct usb_driver ksb_usb_driver = {
695 .name = "ks_bridge",
696 .probe = ksb_usb_probe,
697 .disconnect = ksb_usb_disconnect,
698 .suspend = ksb_usb_suspend,
699 .resume = ksb_usb_resume,
700 .id_table = ksb_usb_ids,
701 .supports_autosuspend = 1,
702};
703
704static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
705{
706 unsigned long flags;
707 struct ks_bridge *ksb = s->private;
708 int i;
709
710 read_lock_irqsave(&ksb->dbg_lock, flags);
711 for (i = 0; i < DBG_MAX_MSG; i++) {
712 if (i == (ksb->dbg_idx - 1))
713 seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
714 else
715 seq_printf(s, "%s\n", ksb->dbgbuf[i]);
716 }
717 read_unlock_irqrestore(&ksb->dbg_lock, flags);
718
719 return 0;
720}
721
722static int ksb_debug_open(struct inode *ip, struct file *fp)
723{
724 return single_open(fp, ksb_debug_show, ip->i_private);
725
726 return 0;
727}
728
729static const struct file_operations dbg_fops = {
730 .open = ksb_debug_open,
731 .read = seq_read,
732 .llseek = seq_lseek,
733 .release = single_release,
734};
735static struct dentry *dbg_dir;
736static int __init ksb_init(void)
737{
738 struct ks_bridge *ksb;
739 int num_instances = 0;
740 int ret = 0;
741 int i;
742
743 dbg_dir = debugfs_create_dir("ks_bridge", NULL);
744 if (IS_ERR(dbg_dir))
745 pr_err("unable to create debug dir");
746
747 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
748 ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
749 if (!ksb) {
750 pr_err("unable to allocat mem for ks_bridge");
Hemant Kumarda86bd22012-08-24 19:42:31 -0700751 ret = -ENOMEM;
752 goto dev_free;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700753 }
754 __ksb[i] = ksb;
755
756 ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
757 if (!ksb->name) {
758 pr_info("unable to allocate name");
759 kfree(ksb);
760 ret = -ENOMEM;
761 goto dev_free;
762 }
763
764 spin_lock_init(&ksb->lock);
765 INIT_LIST_HEAD(&ksb->to_mdm_list);
766 INIT_LIST_HEAD(&ksb->to_ks_list);
767 init_waitqueue_head(&ksb->ks_wait_q);
768 ksb->wq = create_singlethread_workqueue(ksb->name);
769 if (!ksb->wq) {
770 pr_err("unable to allocate workqueue");
771 kfree(ksb->name);
772 kfree(ksb);
773 ret = -ENOMEM;
774 goto dev_free;
775 }
776
777 INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
778 INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
779 init_usb_anchor(&ksb->submitted);
780
781 ksb->dbg_idx = 0;
782 ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
783
784 if (!IS_ERR(dbg_dir))
785 debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
786 ksb, &dbg_fops);
787
788 num_instances++;
789 }
790
791 ret = usb_register(&ksb_usb_driver);
792 if (ret) {
793 pr_err("unable to register ks bridge driver");
794 goto dev_free;
795 }
796
797 pr_info("init done");
798
799 return 0;
800
801dev_free:
802 if (!IS_ERR(dbg_dir))
803 debugfs_remove_recursive(dbg_dir);
804
805 for (i = 0; i < num_instances; i++) {
806 ksb = __ksb[i];
807
808 destroy_workqueue(ksb->wq);
809 kfree(ksb->name);
810 kfree(ksb);
811 }
812
813 return ret;
814
815}
816
817static void __exit ksb_exit(void)
818{
819 struct ks_bridge *ksb;
820 int i;
821
822 if (!IS_ERR(dbg_dir))
823 debugfs_remove_recursive(dbg_dir);
824
825 usb_deregister(&ksb_usb_driver);
826
827 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
828 ksb = __ksb[i];
829
830 destroy_workqueue(ksb->wq);
831 kfree(ksb->name);
832 kfree(ksb);
833 }
834}
835
836module_init(ksb_init);
837module_exit(ksb_exit);
838
839MODULE_DESCRIPTION(DRIVER_DESC);
840MODULE_VERSION(DRIVER_VERSION);
841MODULE_LICENSE("GPL v2");