build_wl18xx: add patch mechanism and bluetooth components
[wilink8-wlan/build-utilites.git] / patches / kernel_patches / imx-3.10.53 / 0002-Bluetooth-Add-tty-HCI-driver.patch
1 From c55f8870f94fef8a588358e4e2ff6eb368eb21bd Mon Sep 17 00:00:00 2001
2 From: Pavan Savoy <pavan_savoy@ti.com>
3 Date: Mon, 15 Oct 2012 17:47:35 -0500
4 Subject: [PATCH 2/7] Bluetooth: Add tty HCI driver
6 tty_hci driver exposes a /dev/hci_tty character device node, that intends to
7 emulate a generic /dev/ttyX device that would be used by the user-space
8 Bluetooth stacks to send/receive data to/from the WL combo-connectivity
9 chipsets.
11 The device driver has no internal logic of its own to intrepret data & all
12 such logic is handled by the user-space stack.
14 Change-Id: Ifa3860bbc7e252af210fde710bce14143239b552
15 Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
16  [Fixed checkpatch warnings]
17 Signed-off-by: Vishal Mahaveer <vishalm@ti.com>
18  [Fixed checkpatch --strict warnings]
19 Signed-off-by: Eyal Reizer <eyalr@ti.com>
20 ---
21  drivers/misc/ti-st/Kconfig   |    8 +
22  drivers/misc/ti-st/Makefile  |    1 +
23  drivers/misc/ti-st/tty_hci.c |  542 ++++++++++++++++++++++++++++++++++++++++++
24  3 files changed, 551 insertions(+)
25  create mode 100644 drivers/misc/ti-st/tty_hci.c
27 diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
28 index f34dcc5..f2df2c7 100644
29 --- a/drivers/misc/ti-st/Kconfig
30 +++ b/drivers/misc/ti-st/Kconfig
31 @@ -14,4 +14,12 @@ config TI_ST
32           are returned to relevant protocol drivers based on their
33           packet types.
34  
35 +config ST_HCI
36 +       tristate "HCI TTY emulation driver for Bluetooth"
37 +       depends on TI_ST
38 +       help
39 +         This enables the TTY device like emulation for HCI used by
40 +         user-space Bluetooth stacks.
41 +         It will provide a character device for user space Bluetooth stack to
42 +         send/receive data over shared transport.
43  endmenu
44 diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile
45 index 78d7ebb..4546219 100644
46 --- a/drivers/misc/ti-st/Makefile
47 +++ b/drivers/misc/ti-st/Makefile
48 @@ -4,3 +4,4 @@
49  #
50  obj-$(CONFIG_TI_ST)            += st_drv.o
51  st_drv-objs                    := st_core.o st_kim.o st_ll.o
52 +obj-$(CONFIG_ST_HCI)           += tty_hci.o
53 diff --git a/drivers/misc/ti-st/tty_hci.c b/drivers/misc/ti-st/tty_hci.c
54 new file mode 100644
55 index 0000000..5b27b04
56 --- /dev/null
57 +++ b/drivers/misc/ti-st/tty_hci.c
58 @@ -0,0 +1,542 @@
59 +/*
60 + *  TTY emulation for user-space Bluetooth stacks over HCI-H4
61 + *  Copyright (C) 2011-2012 Texas Instruments
62 + *  Author: Pavan Savoy <pavan_savoy@ti.com>
63 + *
64 + *  This program is free software; you can redistribute it and/or modify
65 + *  it under the terms of the GNU General Public License version 2 as
66 + *  published by the Free Software Foundation.
67 + *
68 + *  This program is distributed in the hope that it will be useful,
69 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
70 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
71 + *  GNU General Public License for more details.
72 + */
73 +
74 +/** define one of the following for debugging
75 +#define DEBUG
76 +#define VERBOSE
77 +*/
78 +
79 +#define pr_fmt(fmt) "(hci_tty): " fmt
80 +#include <linux/module.h>
81 +#include <linux/cdev.h>
82 +#include <linux/fs.h>
83 +#include <linux/device.h>
84 +
85 +#include <linux/uaccess.h>
86 +#include <linux/tty.h>
87 +#include <linux/sched.h>
88 +
89 +#include <linux/delay.h>
90 +#include <linux/firmware.h>
91 +#include <linux/platform_device.h>
92 +#include <linux/poll.h>
93 +#include <linux/skbuff.h>
94 +#include <linux/interrupt.h>
95 +
96 +#include <linux/ti_wilink_st.h>
97 +
98 +/* Number of seconds to wait for registration completion
99 + * when ST returns PENDING status.
100 + */
101 +#define BT_REGISTER_TIMEOUT   6000     /* 6 sec */
103 +/**
104 + * struct ti_st - driver operation structure
105 + * @hdev: hci device pointer which binds to bt driver
106 + * @reg_status: ST registration callback status
107 + * @st_write: write function provided by the ST driver
108 + *     to be used by the driver during send_frame.
109 + * @wait_reg_completion - completion sync between ti_st_open
110 + *     and st_reg_completion_cb.
111 + */
112 +struct ti_st {
113 +       struct hci_dev *hdev;
114 +       char reg_status;
115 +       long (*st_write)(struct sk_buff *);
116 +       struct completion wait_reg_completion;
117 +       wait_queue_head_t data_q;
118 +       struct sk_buff_head rx_list;
119 +};
121 +#define DEVICE_NAME     "hci_tty"
123 +/***********Functions called from ST driver**********************************/
124 +/* Called by Shared Transport layer when receive data is
125 + * available */
126 +static long st_receive(void *priv_data, struct sk_buff *skb)
127 +{
128 +       struct ti_st    *hst = (void *)priv_data;
130 +       pr_debug("@ %s", __func__);
131 +#ifdef VERBOSE
132 +       print_hex_dump(KERN_INFO, ">rx>", DUMP_PREFIX_NONE,
133 +                      16, 1, skb->data, skb->len, 0);
134 +#endif
135 +       skb_queue_tail(&hst->rx_list, skb);
136 +       wake_up_interruptible(&hst->data_q);
137 +       return 0;
138 +}
140 +/* Called by ST layer to indicate protocol registration completion
141 + * status.ti_st_open() function will wait for signal from this
142 + * API when st_register() function returns ST_PENDING.
143 + */
144 +static void st_reg_completion_cb(void *priv_data, char data)
145 +{
146 +       struct ti_st    *lhst = (void *)priv_data;
148 +       pr_info("@ %s\n", __func__);
149 +       /* Save registration status for use in ti_st_open() */
150 +       lhst->reg_status = data;
151 +       /* complete the wait in ti_st_open() */
152 +       complete(&lhst->wait_reg_completion);
153 +}
155 +/* protocol structure registered with shared transport */
156 +#define MAX_BT_CHNL_IDS 3
157 +static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
158 +       {
159 +               .chnl_id = 0x04, /* HCI Events */
160 +               .hdr_len = 2,
161 +               .offset_len_in_hdr = 1,
162 +               .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
163 +               .reserve = 8,
164 +       },
165 +       {
166 +               .chnl_id = 0x02, /* ACL */
167 +               .hdr_len = 4,
168 +               .offset_len_in_hdr = 2,
169 +               .len_size = 2,  /* sizeof(dlen) in struct hci_acl_hdr */
170 +               .reserve = 8,
171 +       },
172 +       {
173 +               .chnl_id = 0x03, /* SCO */
174 +               .hdr_len = 3,
175 +               .offset_len_in_hdr = 2,
176 +               .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
177 +               .reserve = 8,
178 +       },
179 +};
180 +/** hci_tty_open Function
181 + *  This function will perform an register on ST driver.
182 + *
183 + *  Parameters :
184 + *  @file  : File pointer for BT char driver
185 + *  @inod  :
186 + *  Returns  0 -  on success
187 + *           else suitable error code
188 + */
189 +int hci_tty_open(struct inode *inod, struct file *file)
190 +{
191 +       int i = 0, err = 0;
192 +       unsigned long timeleft;
193 +       struct ti_st *hst;
195 +       pr_info("inside %s (%p, %p)\n", __func__, inod, file);
197 +       hst = kzalloc(sizeof(*hst), GFP_KERNEL);
198 +       file->private_data = hst;
199 +       hst = file->private_data;
201 +       for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
202 +               ti_st_proto[i].priv_data = hst;
203 +               ti_st_proto[i].max_frame_size = 1026;
204 +               ti_st_proto[i].recv = st_receive;
205 +               ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;
207 +               /* Prepare wait-for-completion handler */
208 +               init_completion(&hst->wait_reg_completion);
209 +               /* Reset ST registration callback status flag,
210 +                * this value will be updated in
211 +                * st_reg_completion_cb()
212 +                * function whenever it called from ST driver.
213 +                */
214 +               hst->reg_status = -EINPROGRESS;
216 +               err = st_register(&ti_st_proto[i]);
217 +               if (!err)
218 +                       goto done;
220 +               if (err != -EINPROGRESS) {
221 +                       pr_err("st_register failed %d", err);
222 +                       goto error;
223 +               }
225 +               /* ST is busy with either protocol
226 +                * registration or firmware download.
227 +                */
228 +               pr_debug("waiting for registration completion signal from ST");
229 +               timeleft = wait_for_completion_timeout
230 +                       (&hst->wait_reg_completion,
231 +                        msecs_to_jiffies(BT_REGISTER_TIMEOUT));
232 +               if (!timeleft) {
233 +                       pr_err("Timeout(%d sec),didn't get reg completion signal from ST",
234 +                              BT_REGISTER_TIMEOUT / 1000);
235 +                       err = -ETIMEDOUT;
236 +                       goto error;
237 +               }
239 +               /* Is ST registration callback
240 +                * called with ERROR status? */
241 +               if (hst->reg_status != 0) {
242 +                       pr_err("ST registration completed with invalid status %d",
243 +                              hst->reg_status);
244 +                       err = -EAGAIN;
245 +                       goto error;
246 +               }
248 +done:
249 +               hst->st_write = ti_st_proto[i].write;
250 +               if (!hst->st_write) {
251 +                       pr_err("undefined ST write function");
252 +                       for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
253 +                               /* Undo registration with ST */
254 +                               err = st_unregister(&ti_st_proto[i]);
255 +                               if (err)
256 +                                       pr_err("st_unregister() failed with error %d",
257 +                                              err);
258 +                               hst->st_write = NULL;
259 +                       }
260 +                       return -EIO;
261 +               }
262 +       }
264 +       skb_queue_head_init(&hst->rx_list);
265 +       init_waitqueue_head(&hst->data_q);
267 +       return 0;
269 +error:
270 +       kfree(hst);
271 +       return err;
272 +}
274 +/** hci_tty_release Function
275 + *  This function will un-registers from the ST driver.
276 + *
277 + *  Parameters :
278 + *  @file  : File pointer for BT char driver
279 + *  @inod  :
280 + *  Returns  0 -  on success
281 + *           else suitable error code
282 + */
283 +int hci_tty_release(struct inode *inod, struct file *file)
284 +{
285 +       int err, i;
286 +       struct ti_st *hst = file->private_data;
288 +       pr_info("inside %s (%p, %p)\n", __func__, inod, file);
290 +       for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
291 +               err = st_unregister(&ti_st_proto[i]);
292 +               if (err)
293 +                       pr_err("st_unregister(%d) failed with error %d",
294 +                              ti_st_proto[i].chnl_id, err);
295 +       }
297 +       hst->st_write = NULL;
298 +       skb_queue_purge(&hst->rx_list);
299 +       kfree(hst);
300 +       return err;
301 +}
303 +/** hci_tty_read Function
304 + *
305 + *  Parameters :
306 + *  @file  : File pointer for BT char driver
307 + *  @data  : Data which needs to be passed to APP
308 + *  @size  : Length of the data passesd
309 + *  offset :
310 + *  Returns  Size of packet received -  on success
311 + *           else suitable error code
312 + */
313 +ssize_t hci_tty_read(struct file *file, char __user *data, size_t size,
314 +               loff_t *offset)
315 +{
316 +       int len = 0, tout;
317 +       struct sk_buff *skb = NULL, *rskb = NULL;
318 +       struct ti_st    *hst;
320 +       pr_debug("inside %s (%p, %p, %u, %p)\n",
321 +                __func__, file, data, size, offset);
323 +       /* Validate input parameters */
324 +       if ((NULL == file) || (((NULL == data) || (0 == size)))) {
325 +               pr_err("Invalid input params passed to %s", __func__);
326 +               return -EINVAL;
327 +       }
329 +       hst = file->private_data;
331 +       /* cannot come here if poll-ed before reading
332 +        * if not poll-ed wait on the same wait_q
333 +        */
334 +       tout = wait_event_interruptible_timeout(hst->data_q,
335 +                       !skb_queue_empty(&hst->rx_list),
336 +                               msecs_to_jiffies(1000));
337 +       /* Check for timed out condition */
338 +       if (0 == tout) {
339 +               pr_err("Device Read timed out\n");
340 +               return -ETIMEDOUT;
341 +       }
343 +       /* hst->rx_list not empty skb already present */
344 +       skb = skb_dequeue(&hst->rx_list);
345 +       if (!skb) {
346 +               pr_err("dequed skb is null?\n");
347 +               return -EIO;
348 +       }
350 +#ifdef VERBOSE
351 +       print_hex_dump(KERN_INFO, ">in>", DUMP_PREFIX_NONE,
352 +                      16, 1, skb->data, skb->len, 0);
353 +#endif
355 +       /* Forward the data to the user */
356 +       if (skb->len >= size) {
357 +               pr_err("FIONREAD not done before read\n");
358 +               return -ENOMEM;
359 +       } else {
360 +               /* returning skb */
361 +               rskb = alloc_skb(size, GFP_KERNEL);
362 +               if (!rskb) {
363 +                       pr_err("alloc_skb error\n");
364 +                       return -ENOMEM;
365 +               }
367 +               /* cb[0] has the pkt_type 0x04 or 0x02 or 0x03 */
368 +               memcpy(skb_put(rskb, 1), &skb->cb[0], 1);
369 +               memcpy(skb_put(rskb, skb->len), skb->data, skb->len);
371 +               if (copy_to_user(data, rskb->data, rskb->len)) {
372 +                       pr_err("unable to copy to user space\n");
373 +                       /* Queue the skb back to head */
374 +                       skb_queue_head(&hst->rx_list, skb);
375 +                       kfree_skb(rskb);
376 +                       return -EIO;
377 +               }
378 +       }
380 +       len = rskb->len;        /* len of returning skb */
381 +       kfree_skb(skb);
382 +       kfree_skb(rskb);
383 +       pr_debug("total size read= %d\n", len);
384 +       return len;
385 +}
387 +/* hci_tty_write Function
388 + *
389 + *  Parameters :
390 + *  @file   : File pointer for BT char driver
391 + *  @data   : packet data from BT application
392 + *  @size   : Size of the packet data
393 + *  @offset :
394 + *  Returns  Size of packet on success
395 + *           else suitable error code
396 + */
397 +ssize_t hci_tty_write(struct file *file, const char __user *data,
398 +               size_t size, loff_t *offset)
399 +{
400 +       struct ti_st *hst = file->private_data;
401 +       struct  sk_buff *skb;
403 +       pr_debug("inside %s (%p, %p, %u, %p)\n",
404 +                __func__, file, data, size, offset);
406 +       if (!hst->st_write) {
407 +               pr_err(" Can't write to ST, hhci_tty->st_write null ?");
408 +               return -EINVAL;
409 +       }
411 +       skb = alloc_skb(size, GFP_KERNEL);
412 +       /* Validate Created SKB */
413 +       if (NULL == skb) {
414 +               pr_err("Error aaloacting SKB");
415 +               return -ENOMEM;
416 +       }
418 +       /* Forward the data from the user space to ST core */
419 +       if (copy_from_user(skb_put(skb, size), data, size)) {
420 +               pr_err(" Unable to copy from user space");
421 +               kfree_skb(skb);
422 +               return -EIO;
423 +       }
425 +#ifdef VERBOSE
426 +       pr_debug("start data..");
427 +       print_hex_dump(KERN_INFO, "<out<", DUMP_PREFIX_NONE,
428 +                      16, 1, skb->data, size, 0);
429 +       pr_debug("\n..end data");
430 +#endif
432 +       hst->st_write(skb);
433 +       return size;
434 +}
436 +/** hci_tty_ioctl Function
437 + *  This will peform the functions as directed by the command and command
438 + *  argument.
439 + *
440 + *  Parameters :
441 + *  @file  : File pointer for BT char driver
442 + *  @cmd   : IOCTL Command
443 + *  @arg   : Command argument for IOCTL command
444 + *  Returns  0 on success
445 + *           else suitable error code
446 + */
447 +static long hci_tty_ioctl(struct file *file,
448 +               unsigned int cmd, unsigned long arg)
449 +{
450 +       struct sk_buff *skb = NULL;
451 +       int             retcode = 0;
452 +       struct ti_st    *hst;
454 +       pr_debug("inside %s (%p, %u, %lx)", __func__, file, cmd, arg);
456 +       /* Validate input parameters */
457 +       if ((NULL == file) || (0 == cmd)) {
458 +               pr_err("invalid input parameters passed to %s", __func__);
459 +               return -EINVAL;
460 +       }
462 +       hst = file->private_data;
464 +       switch (cmd) {
465 +       case FIONREAD:
466 +               /* Deque the SKB from the head if rx_list is not empty
467 +                * update the argument with skb->len to provide amount of data
468 +                * available in the available SKB +1 for the PKT_TYPE
469 +                * field not provided in data by TI-ST.
470 +                */
471 +               skb = skb_dequeue(&hst->rx_list);
472 +               if (skb != NULL) {
473 +                       *(unsigned int *)arg = skb->len + 1;
474 +                       /* Re-Store the SKB for furtur Read operations */
475 +                       skb_queue_head(&hst->rx_list, skb);
476 +               } else {
477 +                       *(unsigned int *)arg = 0;
478 +               }
479 +               pr_debug("returning %d\n", *(unsigned int *)arg);
480 +               break;
481 +       default:
482 +               pr_debug("Un-Identified IOCTL %d", cmd);
483 +               retcode = 0;
484 +               break;
485 +       }
487 +       return retcode;
488 +}
490 +/** hci_tty_poll Function
491 + *  This function will wait till some data is received to the hci_tty driver from ST
492 + *
493 + *  Parameters :
494 + *  @file  : File pointer for BT char driver
495 + *  @wait  : POLL wait information
496 + *  Returns  status of POLL on success
497 + *           else suitable error code
498 + */
499 +static unsigned int hci_tty_poll(struct file *file, poll_table *wait)
500 +{
501 +       struct ti_st    *hst = file->private_data;
502 +       unsigned long mask = 0;
504 +       pr_debug("@ %s\n", __func__);
506 +       /* wait to be completed by st_receive */
507 +       poll_wait(file, &hst->data_q, wait);
508 +       pr_debug("poll broke\n");
510 +       if (!skb_queue_empty(&hst->rx_list)) {
511 +               pr_debug("rx list que !empty\n");
512 +               mask |= POLLIN; /* TODO: check app for mask */
513 +       }
515 +       return mask;
516 +}
518 +/* BT Char driver function pointers
519 + * These functions are called from USER space by pefroming File Operations
520 + * on /dev/hci_tty node exposed by this driver during init
521 + */
522 +const struct file_operations hci_tty_chrdev_ops = {
523 +       .owner = THIS_MODULE,
524 +       .open = hci_tty_open,
525 +       .read = hci_tty_read,
526 +       .write = hci_tty_write,
527 +       .unlocked_ioctl = hci_tty_ioctl,
528 +       .poll = hci_tty_poll,
529 +       .release = hci_tty_release,
530 +};
532 +/*********Functions called during insmod and delmod****************************/
534 +static int hci_tty_major;              /* major number */
535 +static struct class *hci_tty_class;    /* class during class_create */
536 +static struct device *hci_tty_dev;     /* dev during device_create */
537 +/** hci_tty_init Function
538 + *  This function Initializes the hci_tty driver parametes and exposes
539 + *  /dev/hci_tty node to user space
540 + *
541 + *  Parameters : NULL
542 + *  Returns  0 on success
543 + *           else suitable error code
544 + */
545 +static int __init hci_tty_init(void)
546 +{
547 +       pr_info("inside %s\n", __func__);
549 +       /* Expose the device DEVICE_NAME to user space
550 +        * And obtain the major number for the device
551 +        */
552 +       hci_tty_major = register_chrdev(0, DEVICE_NAME, &hci_tty_chrdev_ops);
554 +       if (0 > hci_tty_major) {
555 +               pr_err("Error when registering to char dev");
556 +               return hci_tty_major;
557 +       }
559 +       /*  udev */
560 +       hci_tty_class = class_create(THIS_MODULE, DEVICE_NAME);
561 +       if (IS_ERR(hci_tty_class)) {
562 +               pr_err("Something went wrong in class_create");
563 +               unregister_chrdev(hci_tty_major, DEVICE_NAME);
564 +               return -1;
565 +       }
567 +       hci_tty_dev =
568 +               device_create(hci_tty_class, NULL, MKDEV(hci_tty_major, 0),
569 +                             NULL, DEVICE_NAME);
570 +       if (IS_ERR(hci_tty_dev)) {
571 +               pr_err("Error in device create");
572 +               unregister_chrdev(hci_tty_major, DEVICE_NAME);
573 +               class_destroy(hci_tty_class);
574 +               return -1;
575 +       }
576 +       pr_info("allocated %d, %d\n", hci_tty_major, 0);
577 +       return 0;
578 +}
580 +/** hci_tty_exit Function
581 + *  This function Destroys the hci_tty driver parametes and /dev/hci_tty node
582 + *
583 + *  Parameters : NULL
584 + *  Returns   NULL
585 + */
586 +static void __exit hci_tty_exit(void)
587 +{
588 +       pr_info("inside %s\n", __func__);
589 +       pr_info("bye.. freeing up %d\n", hci_tty_major);
591 +       device_destroy(hci_tty_class, MKDEV(hci_tty_major, 0));
592 +       class_destroy(hci_tty_class);
593 +       unregister_chrdev(hci_tty_major, DEVICE_NAME);
594 +}
596 +module_init(hci_tty_init);
597 +module_exit(hci_tty_exit);
599 +MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>");
600 +MODULE_LICENSE("GPL");
601 -- 
602 1.7.9.5