blob: b0785f6874abb9722a52132ff9e3f5d01d95ccb6 [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
Hemant Kumareff9b8f2013-01-16 18:55:14 -080036enum bus_id {
37 BUS_HSIC,
38 BUS_USB,
39 BUS_UNDEF,
40};
41
42#define BUSNAME_LEN 20
43
44static enum bus_id str_to_busid(const char *name)
45{
46 if (!strncasecmp("msm_hsic_host", name, BUSNAME_LEN))
47 return BUS_HSIC;
48 if (!strncasecmp("msm_ehci_host.0", name, BUSNAME_LEN))
49 return BUS_USB;
50
51 return BUS_UNDEF;
52}
53
Vamsi Krishna5b944712012-06-29 18:36:23 -070054struct data_pkt {
55 int n_read;
56 char *buf;
57 size_t len;
58 struct list_head list;
59 void *ctxt;
60};
61
62#define FILE_OPENED BIT(0)
63#define USB_DEV_CONNECTED BIT(1)
64#define NO_RX_REQS 10
Hemant Kumareff9b8f2013-01-16 18:55:14 -080065#define NO_BRIDGE_INSTANCES 4
66#define EFS_HSIC_BRIDGE_INDEX 2
67#define EFS_USB_BRIDGE_INDEX 3
Vamsi Krishna5b944712012-06-29 18:36:23 -070068#define MAX_DATA_PKT_SIZE 16384
Hemant Kumarb3779d12012-09-16 20:28:56 -070069#define PENDING_URB_TIMEOUT 10
Vamsi Krishna5b944712012-06-29 18:36:23 -070070
71struct ks_bridge {
72 char *name;
73 spinlock_t lock;
74 struct workqueue_struct *wq;
75 struct work_struct to_mdm_work;
76 struct work_struct start_rx_work;
77 struct list_head to_mdm_list;
78 struct list_head to_ks_list;
79 wait_queue_head_t ks_wait_q;
Hemant Kumarb3779d12012-09-16 20:28:56 -070080 wait_queue_head_t pending_urb_wait;
Hemant Kumareff9b8f2013-01-16 18:55:14 -080081 struct miscdevice fs_dev;
Hemant Kumarb3779d12012-09-16 20:28:56 -070082 atomic_t tx_pending_cnt;
83 atomic_t rx_pending_cnt;
Vamsi Krishna5b944712012-06-29 18:36:23 -070084
85 /* usb specific */
86 struct usb_device *udev;
87 struct usb_interface *ifc;
88 __u8 in_epAddr;
89 __u8 out_epAddr;
90 unsigned int in_pipe;
91 unsigned int out_pipe;
92 struct usb_anchor submitted;
93
94 unsigned long flags;
Vamsi Krishna5b944712012-06-29 18:36:23 -070095
96#define DBG_MSG_LEN 40
97#define DBG_MAX_MSG 500
98 unsigned int dbg_idx;
99 rwlock_t dbg_lock;
100 char (dbgbuf[DBG_MAX_MSG])[DBG_MSG_LEN]; /* buffer */
101};
102struct ks_bridge *__ksb[NO_BRIDGE_INSTANCES];
103
104/* by default debugging is enabled */
105static unsigned int enable_dbg = 1;
106module_param(enable_dbg, uint, S_IRUGO | S_IWUSR);
107
108static void
109dbg_log_event(struct ks_bridge *ksb, char *event, int d1, int d2)
110{
111 unsigned long flags;
112 unsigned long long t;
113 unsigned long nanosec;
114
115 if (!enable_dbg)
116 return;
117
118 write_lock_irqsave(&ksb->dbg_lock, flags);
119 t = cpu_clock(smp_processor_id());
120 nanosec = do_div(t, 1000000000)/1000;
121 scnprintf(ksb->dbgbuf[ksb->dbg_idx], DBG_MSG_LEN, "%5lu.%06lu:%s:%x:%x",
122 (unsigned long)t, nanosec, event, d1, d2);
123
124 ksb->dbg_idx++;
125 ksb->dbg_idx = ksb->dbg_idx % DBG_MAX_MSG;
126 write_unlock_irqrestore(&ksb->dbg_lock, flags);
127}
128
129static
130struct data_pkt *ksb_alloc_data_pkt(size_t count, gfp_t flags, void *ctxt)
131{
132 struct data_pkt *pkt;
133
134 pkt = kzalloc(sizeof(struct data_pkt), flags);
135 if (!pkt) {
136 pr_err("failed to allocate data packet\n");
137 return ERR_PTR(-ENOMEM);
138 }
139
140 pkt->buf = kmalloc(count, flags);
141 if (!pkt->buf) {
142 pr_err("failed to allocate data buffer\n");
143 kfree(pkt);
144 return ERR_PTR(-ENOMEM);
145 }
146
147 pkt->len = count;
148 INIT_LIST_HEAD(&pkt->list);
149 pkt->ctxt = ctxt;
150
151 return pkt;
152}
153
154static void ksb_free_data_pkt(struct data_pkt *pkt)
155{
156 kfree(pkt->buf);
157 kfree(pkt);
158}
159
160
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530161static void
162submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700163static ssize_t ksb_fs_read(struct file *fp, char __user *buf,
164 size_t count, loff_t *pos)
165{
166 int ret;
167 unsigned long flags;
168 struct ks_bridge *ksb = fp->private_data;
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530169 struct data_pkt *pkt = NULL;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700170 size_t space, copied;
171
172read_start:
173 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
174 return -ENODEV;
175
176 spin_lock_irqsave(&ksb->lock, flags);
177 if (list_empty(&ksb->to_ks_list)) {
178 spin_unlock_irqrestore(&ksb->lock, flags);
179 ret = wait_event_interruptible(ksb->ks_wait_q,
180 !list_empty(&ksb->to_ks_list) ||
181 !test_bit(USB_DEV_CONNECTED, &ksb->flags));
182 if (ret < 0)
183 return ret;
184
185 goto read_start;
186 }
187
188 space = count;
189 copied = 0;
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530190 while (!list_empty(&ksb->to_ks_list) && space &&
191 test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
Vamsi Krishna5b944712012-06-29 18:36:23 -0700192 size_t len;
193
194 pkt = list_first_entry(&ksb->to_ks_list, struct data_pkt, list);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530195 list_del_init(&pkt->list);
Hemant Kumarb48f4732012-09-24 12:32:32 -0700196 len = min_t(size_t, space, pkt->len - pkt->n_read);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700197 spin_unlock_irqrestore(&ksb->lock, flags);
198
Hemant Kumarb48f4732012-09-24 12:32:32 -0700199 ret = copy_to_user(buf + copied, pkt->buf + pkt->n_read, len);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700200 if (ret) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800201 dev_err(ksb->fs_dev.this_device,
202 "copy_to_user failed err:%d\n", ret);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700203 ksb_free_data_pkt(pkt);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530204 return -EFAULT;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700205 }
206
Hemant Kumarb48f4732012-09-24 12:32:32 -0700207 pkt->n_read += len;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700208 space -= len;
209 copied += len;
210
Vamsi Krishna5b944712012-06-29 18:36:23 -0700211 if (pkt->n_read == pkt->len) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530212 /*
213 * re-init the packet and queue it
214 * for more data.
215 */
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530216 pkt->n_read = 0;
217 pkt->len = MAX_DATA_PKT_SIZE;
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530218 submit_one_urb(ksb, GFP_KERNEL, pkt);
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530219 pkt = NULL;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700220 }
Pavankumar Kondeti157fd792013-02-02 09:42:33 +0530221 spin_lock_irqsave(&ksb->lock, flags);
222 }
223
224 /* put the partial packet back in the list */
225 if (!space && pkt && pkt->n_read != pkt->len) {
226 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
227 list_add(&pkt->list, &ksb->to_ks_list);
228 else
229 ksb_free_data_pkt(pkt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700230 }
231 spin_unlock_irqrestore(&ksb->lock, flags);
232
233 dbg_log_event(ksb, "KS_READ", copied, 0);
234
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800235 dev_dbg(ksb->fs_dev.this_device, "count:%d space:%d copied:%d", count,
236 space, copied);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700237
238 return copied;
239}
240
241static void ksb_tx_cb(struct urb *urb)
242{
243 struct data_pkt *pkt = urb->context;
244 struct ks_bridge *ksb = pkt->ctxt;
245
246 dbg_log_event(ksb, "C TX_URB", urb->status, 0);
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800247 dev_dbg(&ksb->udev->dev, "status:%d", urb->status);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700248
Hemant Kumarb3779d12012-09-16 20:28:56 -0700249 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
Vamsi Krishna5b944712012-06-29 18:36:23 -0700250 usb_autopm_put_interface_async(ksb->ifc);
251
252 if (urb->status < 0)
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800253 pr_err_ratelimited("%s: urb failed with err:%d",
254 ksb->fs_dev.name, urb->status);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700255
256 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700257
258 atomic_dec(&ksb->tx_pending_cnt);
259 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700260}
261
262static void ksb_tomdm_work(struct work_struct *w)
263{
264 struct ks_bridge *ksb = container_of(w, struct ks_bridge, to_mdm_work);
265 struct data_pkt *pkt;
266 unsigned long flags;
267 struct urb *urb;
268 int ret;
269
270 spin_lock_irqsave(&ksb->lock, flags);
271 while (!list_empty(&ksb->to_mdm_list)
272 && test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
273 pkt = list_first_entry(&ksb->to_mdm_list,
274 struct data_pkt, list);
275 list_del_init(&pkt->list);
276 spin_unlock_irqrestore(&ksb->lock, flags);
277
278 urb = usb_alloc_urb(0, GFP_KERNEL);
279 if (!urb) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800280 pr_err_ratelimited("%s: unable to allocate urb",
281 ksb->fs_dev.name);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700282 ksb_free_data_pkt(pkt);
283 return;
284 }
285
286 ret = usb_autopm_get_interface(ksb->ifc);
287 if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800288 pr_err_ratelimited("%s: autopm_get failed:%d",
289 ksb->fs_dev.name, ret);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700290 usb_free_urb(urb);
291 ksb_free_data_pkt(pkt);
292 return;
293 }
294 usb_fill_bulk_urb(urb, ksb->udev, ksb->out_pipe,
295 pkt->buf, pkt->len, ksb_tx_cb, pkt);
296 usb_anchor_urb(urb, &ksb->submitted);
297
298 dbg_log_event(ksb, "S TX_URB", pkt->len, 0);
299
Hemant Kumarb3779d12012-09-16 20:28:56 -0700300 atomic_inc(&ksb->tx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700301 ret = usb_submit_urb(urb, GFP_KERNEL);
302 if (ret) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800303 dev_err(&ksb->udev->dev, "out urb submission failed");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700304 usb_unanchor_urb(urb);
305 usb_free_urb(urb);
306 ksb_free_data_pkt(pkt);
307 usb_autopm_put_interface(ksb->ifc);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700308 atomic_dec(&ksb->tx_pending_cnt);
309 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700310 return;
311 }
312
Hemant Kumar1432f6f2012-09-19 12:40:11 -0700313 usb_free_urb(urb);
314
Vamsi Krishna5b944712012-06-29 18:36:23 -0700315 spin_lock_irqsave(&ksb->lock, flags);
316 }
317 spin_unlock_irqrestore(&ksb->lock, flags);
318}
319
320static ssize_t ksb_fs_write(struct file *fp, const char __user *buf,
321 size_t count, loff_t *pos)
322{
323 int ret;
324 struct data_pkt *pkt;
325 unsigned long flags;
326 struct ks_bridge *ksb = fp->private_data;
327
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700328 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
329 return -ENODEV;
330
Pavankumar Kondeti7fcc7792012-12-28 17:15:41 +0530331 if (count > MAX_DATA_PKT_SIZE)
332 count = MAX_DATA_PKT_SIZE;
333
Vamsi Krishna5b944712012-06-29 18:36:23 -0700334 pkt = ksb_alloc_data_pkt(count, GFP_KERNEL, ksb);
335 if (IS_ERR(pkt)) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800336 dev_err(ksb->fs_dev.this_device,
337 "unable to allocate data packet");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700338 return PTR_ERR(pkt);
339 }
340
341 ret = copy_from_user(pkt->buf, buf, count);
342 if (ret) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800343 dev_err(ksb->fs_dev.this_device,
344 "copy_from_user failed: err:%d", ret);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700345 ksb_free_data_pkt(pkt);
346 return ret;
347 }
348
349 spin_lock_irqsave(&ksb->lock, flags);
350 list_add_tail(&pkt->list, &ksb->to_mdm_list);
351 spin_unlock_irqrestore(&ksb->lock, flags);
352
353 queue_work(ksb->wq, &ksb->to_mdm_work);
354
355 return count;
356}
357
Vamsi Krishna5b944712012-06-29 18:36:23 -0700358static int ksb_fs_open(struct inode *ip, struct file *fp)
359{
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800360 struct miscdevice *mdev = fp->private_data;
361 struct ks_bridge *ksb = container_of(mdev, struct ks_bridge, fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700362
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800363 if (IS_ERR(ksb)) {
364 pr_err("ksb device not found");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700365 return -ENODEV;
366 }
367
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800368 dev_dbg(ksb->fs_dev.this_device, ":%s", ksb->fs_dev.name);
369 dbg_log_event(ksb, "FS-OPEN", 0, 0);
370
Vamsi Krishna5b944712012-06-29 18:36:23 -0700371 fp->private_data = ksb;
372 set_bit(FILE_OPENED, &ksb->flags);
373
374 if (test_bit(USB_DEV_CONNECTED, &ksb->flags))
375 queue_work(ksb->wq, &ksb->start_rx_work);
376
377 return 0;
378}
379
380static int ksb_fs_release(struct inode *ip, struct file *fp)
381{
382 struct ks_bridge *ksb = fp->private_data;
383
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800384 dev_dbg(ksb->fs_dev.this_device, ":%s", ksb->fs_dev.name);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700385 dbg_log_event(ksb, "FS-RELEASE", 0, 0);
386
387 clear_bit(FILE_OPENED, &ksb->flags);
388 fp->private_data = NULL;
389
390 return 0;
391}
392
393static const struct file_operations ksb_fops = {
394 .owner = THIS_MODULE,
395 .read = ksb_fs_read,
396 .write = ksb_fs_write,
397 .open = ksb_fs_open,
398 .release = ksb_fs_release,
399};
400
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800401static struct miscdevice ksb_fboot_dev[] = {
402 {
403 .minor = MISC_DYNAMIC_MINOR,
404 .name = "ks_hsic_bridge",
405 .fops = &ksb_fops,
406 },
407 {
408 .minor = MISC_DYNAMIC_MINOR,
409 .name = "ks_usb_bridge",
410 .fops = &ksb_fops,
411 },
Vamsi Krishna5b944712012-06-29 18:36:23 -0700412};
413
414static const struct file_operations efs_fops = {
415 .owner = THIS_MODULE,
416 .read = ksb_fs_read,
417 .write = ksb_fs_write,
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800418 .open = ksb_fs_open,
Vamsi Krishna5b944712012-06-29 18:36:23 -0700419 .release = ksb_fs_release,
420};
421
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800422static struct miscdevice ksb_efs_hsic_dev = {
Vamsi Krishna5b944712012-06-29 18:36:23 -0700423 .minor = MISC_DYNAMIC_MINOR,
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800424 .name = "efs_hsic_bridge",
Vamsi Krishna5b944712012-06-29 18:36:23 -0700425 .fops = &efs_fops,
426};
427
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800428static struct miscdevice ksb_efs_usb_dev = {
429 .minor = MISC_DYNAMIC_MINOR,
430 .name = "efs_usb_bridge",
431 .fops = &efs_fops,
432};
Vamsi Krishna5b944712012-06-29 18:36:23 -0700433static const struct usb_device_id ksb_usb_ids[] = {
434 { USB_DEVICE(0x5c6, 0x9008),
435 .driver_info = (unsigned long)&ksb_fboot_dev, },
436 { USB_DEVICE(0x5c6, 0x9048),
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800437 .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
Vamsi Krishna5b944712012-06-29 18:36:23 -0700438 { USB_DEVICE(0x5c6, 0x904C),
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800439 .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
Hemant Kumarce3c5bf2012-12-06 15:52:02 -0800440 { USB_DEVICE(0x5c6, 0x9075),
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800441 .driver_info = (unsigned long)&ksb_efs_hsic_dev, },
442 { USB_DEVICE(0x5c6, 0x9079),
443 .driver_info = (unsigned long)&ksb_efs_usb_dev, },
Vamsi Krishna5b944712012-06-29 18:36:23 -0700444
445 {} /* terminating entry */
446};
447MODULE_DEVICE_TABLE(usb, ksb_usb_ids);
448
449static void ksb_rx_cb(struct urb *urb);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530450static void
451submit_one_urb(struct ks_bridge *ksb, gfp_t flags, struct data_pkt *pkt)
Vamsi Krishna5b944712012-06-29 18:36:23 -0700452{
Vamsi Krishna5b944712012-06-29 18:36:23 -0700453 struct urb *urb;
454 int ret;
455
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530456 urb = usb_alloc_urb(0, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700457 if (!urb) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800458 dev_err(&ksb->udev->dev, "unable to allocate urb");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700459 ksb_free_data_pkt(pkt);
460 return;
461 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700462
463 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
464 pkt->buf, pkt->len,
465 ksb_rx_cb, pkt);
466 usb_anchor_urb(urb, &ksb->submitted);
467
Hemant Kumarb3779d12012-09-16 20:28:56 -0700468 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags)) {
469 usb_unanchor_urb(urb);
470 usb_free_urb(urb);
471 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700472 return;
473 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700474
Hemant Kumarb3779d12012-09-16 20:28:56 -0700475 atomic_inc(&ksb->rx_pending_cnt);
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530476 ret = usb_submit_urb(urb, flags);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700477 if (ret) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800478 dev_err(&ksb->udev->dev, "in urb submission failed");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700479 usb_unanchor_urb(urb);
480 usb_free_urb(urb);
481 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700482 atomic_dec(&ksb->rx_pending_cnt);
483 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700484 return;
485 }
486
Hemant Kumarb3779d12012-09-16 20:28:56 -0700487 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
488
Vamsi Krishna5b944712012-06-29 18:36:23 -0700489 usb_free_urb(urb);
490}
491static void ksb_rx_cb(struct urb *urb)
492{
493 struct data_pkt *pkt = urb->context;
494 struct ks_bridge *ksb = pkt->ctxt;
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530495 bool wakeup = true;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700496
497 dbg_log_event(ksb, "C RX_URB", urb->status, urb->actual_length);
498
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800499 dev_dbg(&ksb->udev->dev, "status:%d actual:%d", urb->status,
500 urb->actual_length);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700501
Hemant Kumar853ebf62012-08-31 18:38:32 -0700502 /*non zero len of data received while unlinking urb*/
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530503 if (urb->status == -ENOENT && (urb->actual_length > 0)) {
504 /*
505 * If we wakeup the reader process now, it may
506 * queue the URB before its reject flag gets
507 * cleared.
508 */
509 wakeup = false;
Hemant Kumar853ebf62012-08-31 18:38:32 -0700510 goto add_to_list;
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530511 }
Hemant Kumar853ebf62012-08-31 18:38:32 -0700512
Vamsi Krishna5b944712012-06-29 18:36:23 -0700513 if (urb->status < 0) {
Hemant Kumar853ebf62012-08-31 18:38:32 -0700514 if (urb->status != -ESHUTDOWN && urb->status != -ENOENT
515 && urb->status != -EPROTO)
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800516 pr_err_ratelimited("%s: urb failed with err:%d",
517 ksb->fs_dev.name, urb->status);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700518 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700519 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700520 }
521
522 if (urb->actual_length == 0) {
Pavankumar Kondeti5c915c12012-12-14 15:12:46 +0530523 submit_one_urb(ksb, GFP_ATOMIC, pkt);
524 goto done;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700525 }
526
Hemant Kumar853ebf62012-08-31 18:38:32 -0700527add_to_list:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700528 spin_lock(&ksb->lock);
529 pkt->len = urb->actual_length;
530 list_add_tail(&pkt->list, &ksb->to_ks_list);
531 spin_unlock(&ksb->lock);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700532 /* wake up read thread */
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530533 if (wakeup)
534 wake_up(&ksb->ks_wait_q);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700535done:
536 atomic_dec(&ksb->rx_pending_cnt);
537 wake_up(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700538}
539
540static void ksb_start_rx_work(struct work_struct *w)
541{
542 struct ks_bridge *ksb =
543 container_of(w, struct ks_bridge, start_rx_work);
544 struct data_pkt *pkt;
545 struct urb *urb;
546 int i = 0;
547 int ret;
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530548 bool put = true;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700549
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530550 ret = usb_autopm_get_interface(ksb->ifc);
551 if (ret < 0) {
552 if (ret != -EAGAIN && ret != -EACCES) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800553 pr_err_ratelimited("%s: autopm_get failed:%d",
554 ksb->fs_dev.name, ret);
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530555 return;
556 }
557 put = false;
558 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700559 for (i = 0; i < NO_RX_REQS; i++) {
Hemant Kumarb3779d12012-09-16 20:28:56 -0700560
561 if (!test_bit(USB_DEV_CONNECTED, &ksb->flags))
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530562 break;
Hemant Kumarb3779d12012-09-16 20:28:56 -0700563
Vamsi Krishna5b944712012-06-29 18:36:23 -0700564 pkt = ksb_alloc_data_pkt(MAX_DATA_PKT_SIZE, GFP_KERNEL, ksb);
565 if (IS_ERR(pkt)) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800566 dev_err(&ksb->udev->dev, "unable to allocate data pkt");
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530567 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700568 }
569
570 urb = usb_alloc_urb(0, GFP_KERNEL);
571 if (!urb) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800572 dev_err(&ksb->udev->dev, "unable to allocate urb");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700573 ksb_free_data_pkt(pkt);
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530574 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700575 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700576
577 usb_fill_bulk_urb(urb, ksb->udev, ksb->in_pipe,
578 pkt->buf, pkt->len,
579 ksb_rx_cb, pkt);
580 usb_anchor_urb(urb, &ksb->submitted);
581
582 dbg_log_event(ksb, "S RX_URB", pkt->len, 0);
583
Hemant Kumarb3779d12012-09-16 20:28:56 -0700584 atomic_inc(&ksb->rx_pending_cnt);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700585 ret = usb_submit_urb(urb, GFP_KERNEL);
586 if (ret) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800587 dev_err(&ksb->udev->dev, "in urb submission failed");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700588 usb_unanchor_urb(urb);
589 usb_free_urb(urb);
590 ksb_free_data_pkt(pkt);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700591 atomic_dec(&ksb->rx_pending_cnt);
592 wake_up(&ksb->pending_urb_wait);
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530593 break;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700594 }
595
Vamsi Krishna5b944712012-06-29 18:36:23 -0700596 usb_free_urb(urb);
597 }
Pavankumar Kondeti361d9af2013-01-21 21:14:26 +0530598 if (put)
599 usb_autopm_put_interface_async(ksb->ifc);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700600}
601
602static int
603ksb_usb_probe(struct usb_interface *ifc, const struct usb_device_id *id)
604{
605 __u8 ifc_num;
606 struct usb_host_interface *ifc_desc;
607 struct usb_endpoint_descriptor *ep_desc;
608 int i;
609 struct ks_bridge *ksb;
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700610 unsigned long flags;
611 struct data_pkt *pkt;
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800612 struct miscdevice *mdev, *fbdev;
613 struct usb_device *udev;
614 unsigned int bus_id;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700615
616 ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
617
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800618 udev = interface_to_usbdev(ifc);
619 fbdev = mdev = (struct miscdevice *)id->driver_info;
620
621 bus_id = str_to_busid(udev->bus->bus_name);
622 if (bus_id == BUS_UNDEF) {
623 dev_err(&udev->dev, "unknown usb bus %s, probe failed\n",
624 udev->bus->bus_name);
625 return -ENODEV;
626 }
627
Vamsi Krishna5b944712012-06-29 18:36:23 -0700628 switch (id->idProduct) {
629 case 0x9008:
630 if (ifc_num != 0)
631 return -ENODEV;
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800632 ksb = __ksb[bus_id];
633 mdev = &fbdev[bus_id];
Vamsi Krishna5b944712012-06-29 18:36:23 -0700634 break;
635 case 0x9048:
636 case 0x904C:
Hemant Kumarcfa601a2012-12-19 11:23:11 -0800637 case 0x9075:
Vamsi Krishna5b944712012-06-29 18:36:23 -0700638 if (ifc_num != 2)
639 return -ENODEV;
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800640 ksb = __ksb[EFS_HSIC_BRIDGE_INDEX];
641 break;
642 case 0x9079:
643 if (ifc_num != 2)
644 return -ENODEV;
645 ksb = __ksb[EFS_USB_BRIDGE_INDEX];
Vamsi Krishna5b944712012-06-29 18:36:23 -0700646 break;
647 default:
648 return -ENODEV;
649 }
650
651 if (!ksb) {
652 pr_err("ksb is not initialized");
653 return -ENODEV;
654 }
655
656 ksb->udev = usb_get_dev(interface_to_usbdev(ifc));
657 ksb->ifc = ifc;
658 ifc_desc = ifc->cur_altsetting;
659
660 for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
661 ep_desc = &ifc_desc->endpoint[i].desc;
662
663 if (!ksb->in_epAddr && usb_endpoint_is_bulk_in(ep_desc))
664 ksb->in_epAddr = ep_desc->bEndpointAddress;
665
666 if (!ksb->out_epAddr && usb_endpoint_is_bulk_out(ep_desc))
667 ksb->out_epAddr = ep_desc->bEndpointAddress;
668 }
669
670 if (!(ksb->in_epAddr && ksb->out_epAddr)) {
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800671 dev_err(&udev->dev,
672 "could not find bulk in and bulk out endpoints");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700673 usb_put_dev(ksb->udev);
674 ksb->ifc = NULL;
675 return -ENODEV;
676 }
677
678 ksb->in_pipe = usb_rcvbulkpipe(ksb->udev, ksb->in_epAddr);
679 ksb->out_pipe = usb_sndbulkpipe(ksb->udev, ksb->out_epAddr);
680
681 usb_set_intfdata(ifc, ksb);
682 set_bit(USB_DEV_CONNECTED, &ksb->flags);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700683 atomic_set(&ksb->tx_pending_cnt, 0);
684 atomic_set(&ksb->rx_pending_cnt, 0);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700685
686 dbg_log_event(ksb, "PID-ATT", id->idProduct, 0);
687
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700688 /*free up stale buffers if any from previous disconnect*/
689 spin_lock_irqsave(&ksb->lock, flags);
690 while (!list_empty(&ksb->to_ks_list)) {
691 pkt = list_first_entry(&ksb->to_ks_list,
692 struct data_pkt, list);
693 list_del_init(&pkt->list);
694 ksb_free_data_pkt(pkt);
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700695 }
696 while (!list_empty(&ksb->to_mdm_list)) {
697 pkt = list_first_entry(&ksb->to_mdm_list,
698 struct data_pkt, list);
699 list_del_init(&pkt->list);
700 ksb_free_data_pkt(pkt);
701 }
702 spin_unlock_irqrestore(&ksb->lock, flags);
703
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800704 ksb->fs_dev = *mdev;
705 misc_register(&ksb->fs_dev);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700706
Pavankumar Kondetid53a0f42013-02-05 15:38:03 +0530707 if (device_can_wakeup(&ksb->udev->dev)) {
708 ifc->needs_remote_wakeup = 1;
709 usb_enable_autosuspend(ksb->udev);
710 }
Vamsi Krishna5b944712012-06-29 18:36:23 -0700711
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800712 dev_dbg(&udev->dev, "usb dev connected");
Vamsi Krishna5b944712012-06-29 18:36:23 -0700713
714 return 0;
715}
716
717static int ksb_usb_suspend(struct usb_interface *ifc, pm_message_t message)
718{
719 struct ks_bridge *ksb = usb_get_intfdata(ifc);
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530720 unsigned long flags;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700721
722 dbg_log_event(ksb, "SUSPEND", 0, 0);
723
Vamsi Krishna5b944712012-06-29 18:36:23 -0700724 usb_kill_anchored_urbs(&ksb->submitted);
725
Pavankumar Kondetif0b7ac12013-01-30 16:17:16 +0530726 spin_lock_irqsave(&ksb->lock, flags);
727 if (!list_empty(&ksb->to_ks_list)) {
728 spin_unlock_irqrestore(&ksb->lock, flags);
729 dbg_log_event(ksb, "SUSPEND ABORT", 0, 0);
730 /*
731 * Now wakeup the reader process and queue
732 * Rx URBs for more data.
733 */
734 wake_up(&ksb->ks_wait_q);
735 queue_work(ksb->wq, &ksb->start_rx_work);
736 return -EBUSY;
737 }
738 spin_unlock_irqrestore(&ksb->lock, flags);
739
Vamsi Krishna5b944712012-06-29 18:36:23 -0700740 return 0;
741}
742
743static int ksb_usb_resume(struct usb_interface *ifc)
744{
745 struct ks_bridge *ksb = usb_get_intfdata(ifc);
746
747 dbg_log_event(ksb, "RESUME", 0, 0);
748
749 if (test_bit(FILE_OPENED, &ksb->flags))
750 queue_work(ksb->wq, &ksb->start_rx_work);
751
752 return 0;
753}
754
755static void ksb_usb_disconnect(struct usb_interface *ifc)
756{
757 struct ks_bridge *ksb = usb_get_intfdata(ifc);
758 unsigned long flags;
759 struct data_pkt *pkt;
760
761 dbg_log_event(ksb, "PID-DETACH", 0, 0);
762
763 clear_bit(USB_DEV_CONNECTED, &ksb->flags);
764 wake_up(&ksb->ks_wait_q);
765 cancel_work_sync(&ksb->to_mdm_work);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700766 cancel_work_sync(&ksb->start_rx_work);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700767
Hemant Kumareff9b8f2013-01-16 18:55:14 -0800768 misc_deregister(&ksb->fs_dev);
Hemant Kumar2f20bda2012-09-17 14:05:54 -0700769
Vamsi Krishna5b944712012-06-29 18:36:23 -0700770 usb_kill_anchored_urbs(&ksb->submitted);
771
Hemant Kumarb3779d12012-09-16 20:28:56 -0700772 wait_event_interruptible_timeout(
773 ksb->pending_urb_wait,
774 !atomic_read(&ksb->tx_pending_cnt) &&
775 !atomic_read(&ksb->rx_pending_cnt),
776 msecs_to_jiffies(PENDING_URB_TIMEOUT));
777
Vamsi Krishna5b944712012-06-29 18:36:23 -0700778 spin_lock_irqsave(&ksb->lock, flags);
779 while (!list_empty(&ksb->to_ks_list)) {
780 pkt = list_first_entry(&ksb->to_ks_list,
781 struct data_pkt, list);
782 list_del_init(&pkt->list);
783 ksb_free_data_pkt(pkt);
784 }
785 while (!list_empty(&ksb->to_mdm_list)) {
786 pkt = list_first_entry(&ksb->to_mdm_list,
787 struct data_pkt, list);
788 list_del_init(&pkt->list);
789 ksb_free_data_pkt(pkt);
790 }
791 spin_unlock_irqrestore(&ksb->lock, flags);
792
Hemant Kumard26076c2012-09-07 19:00:21 -0700793 ifc->needs_remote_wakeup = 0;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700794 usb_put_dev(ksb->udev);
795 ksb->ifc = NULL;
796 usb_set_intfdata(ifc, NULL);
797
798 return;
799}
800
801static struct usb_driver ksb_usb_driver = {
802 .name = "ks_bridge",
803 .probe = ksb_usb_probe,
804 .disconnect = ksb_usb_disconnect,
805 .suspend = ksb_usb_suspend,
806 .resume = ksb_usb_resume,
807 .id_table = ksb_usb_ids,
808 .supports_autosuspend = 1,
809};
810
811static ssize_t ksb_debug_show(struct seq_file *s, void *unused)
812{
813 unsigned long flags;
814 struct ks_bridge *ksb = s->private;
815 int i;
816
817 read_lock_irqsave(&ksb->dbg_lock, flags);
818 for (i = 0; i < DBG_MAX_MSG; i++) {
819 if (i == (ksb->dbg_idx - 1))
820 seq_printf(s, "-->%s\n", ksb->dbgbuf[i]);
821 else
822 seq_printf(s, "%s\n", ksb->dbgbuf[i]);
823 }
824 read_unlock_irqrestore(&ksb->dbg_lock, flags);
825
826 return 0;
827}
828
829static int ksb_debug_open(struct inode *ip, struct file *fp)
830{
831 return single_open(fp, ksb_debug_show, ip->i_private);
832
833 return 0;
834}
835
836static const struct file_operations dbg_fops = {
837 .open = ksb_debug_open,
838 .read = seq_read,
839 .llseek = seq_lseek,
840 .release = single_release,
841};
842static struct dentry *dbg_dir;
843static int __init ksb_init(void)
844{
845 struct ks_bridge *ksb;
846 int num_instances = 0;
847 int ret = 0;
848 int i;
849
850 dbg_dir = debugfs_create_dir("ks_bridge", NULL);
851 if (IS_ERR(dbg_dir))
852 pr_err("unable to create debug dir");
853
854 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
855 ksb = kzalloc(sizeof(struct ks_bridge), GFP_KERNEL);
856 if (!ksb) {
857 pr_err("unable to allocat mem for ks_bridge");
Hemant Kumarda86bd22012-08-24 19:42:31 -0700858 ret = -ENOMEM;
859 goto dev_free;
Vamsi Krishna5b944712012-06-29 18:36:23 -0700860 }
861 __ksb[i] = ksb;
862
863 ksb->name = kasprintf(GFP_KERNEL, "ks_bridge:%i", i + 1);
864 if (!ksb->name) {
865 pr_info("unable to allocate name");
866 kfree(ksb);
867 ret = -ENOMEM;
868 goto dev_free;
869 }
870
871 spin_lock_init(&ksb->lock);
872 INIT_LIST_HEAD(&ksb->to_mdm_list);
873 INIT_LIST_HEAD(&ksb->to_ks_list);
874 init_waitqueue_head(&ksb->ks_wait_q);
Hemant Kumarb3779d12012-09-16 20:28:56 -0700875 init_waitqueue_head(&ksb->pending_urb_wait);
Vamsi Krishna5b944712012-06-29 18:36:23 -0700876 ksb->wq = create_singlethread_workqueue(ksb->name);
877 if (!ksb->wq) {
878 pr_err("unable to allocate workqueue");
879 kfree(ksb->name);
880 kfree(ksb);
881 ret = -ENOMEM;
882 goto dev_free;
883 }
884
885 INIT_WORK(&ksb->to_mdm_work, ksb_tomdm_work);
886 INIT_WORK(&ksb->start_rx_work, ksb_start_rx_work);
887 init_usb_anchor(&ksb->submitted);
888
889 ksb->dbg_idx = 0;
890 ksb->dbg_lock = __RW_LOCK_UNLOCKED(lck);
891
892 if (!IS_ERR(dbg_dir))
893 debugfs_create_file(ksb->name, S_IRUGO, dbg_dir,
894 ksb, &dbg_fops);
895
896 num_instances++;
897 }
898
899 ret = usb_register(&ksb_usb_driver);
900 if (ret) {
901 pr_err("unable to register ks bridge driver");
902 goto dev_free;
903 }
904
905 pr_info("init done");
906
907 return 0;
908
909dev_free:
910 if (!IS_ERR(dbg_dir))
911 debugfs_remove_recursive(dbg_dir);
912
913 for (i = 0; i < num_instances; i++) {
914 ksb = __ksb[i];
915
916 destroy_workqueue(ksb->wq);
917 kfree(ksb->name);
918 kfree(ksb);
919 }
920
921 return ret;
922
923}
924
925static void __exit ksb_exit(void)
926{
927 struct ks_bridge *ksb;
928 int i;
929
930 if (!IS_ERR(dbg_dir))
931 debugfs_remove_recursive(dbg_dir);
932
933 usb_deregister(&ksb_usb_driver);
934
935 for (i = 0; i < NO_BRIDGE_INSTANCES; i++) {
936 ksb = __ksb[i];
937
938 destroy_workqueue(ksb->wq);
939 kfree(ksb->name);
940 kfree(ksb);
941 }
942}
943
944module_init(ksb_init);
945module_exit(ksb_exit);
946
947MODULE_DESCRIPTION(DRIVER_DESC);
948MODULE_VERSION(DRIVER_VERSION);
949MODULE_LICENSE("GPL v2");