diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/bluetooth | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 164 |
1 files changed, 162 insertions, 2 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 48ad2a7..a1cc9e3 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -90,6 +90,12 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) { struct hci_dev *hdev = hu->hdev; +#if defined(CONFIG_BT_CSR8811) + if(hdev == NULL) + return ; +#endif + + /* Update HCI stat counters */ switch (pkt_type) { case HCI_COMMAND_PKT: @@ -124,6 +130,11 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) struct hci_dev *hdev = hu->hdev; struct sk_buff *skb; +#if defined(CONFIG_BT_CSR8811) + if(hdev == NULL) + return -1; +#endif + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; @@ -136,6 +147,13 @@ restart: while ((skb = hci_uart_dequeue(hu))) { int len; +/* Samsung Bluetooth Feature.2012.01.19 + * Add wake_peer uart operation which is called before starting UART TX + */ +#if !defined(CONFIG_BT_CSR8811) + if (hdev->wake_peer) + hdev->wake_peer(hdev); +#endif set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); len = tty->ops->write(tty, skb->data, skb->len); @@ -331,6 +349,11 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) { struct hci_uart *hu = (void *)tty->disc_data; +#if defined(CONFIG_BT_CSR8811) + if(hu->hdev == NULL) + return ; +#endif + BT_DBG(""); if (!hu) @@ -361,12 +384,22 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f { struct hci_uart *hu = (void *)tty->disc_data; +#if defined(CONFIG_BT_CSR8811) + if(hu->hdev == NULL) + return ; +#endif + if (!hu || tty != hu->tty) return; if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) return; +/* CSR8811 Project(Dayton.Kim) 2012.02.23 */ + if (hu == NULL || hu->proto == NULL || hu->proto->recv == NULL || data == NULL) + return; +/* CSR8811 Project(Dayton.Kim) end */ + spin_lock(&hu->rx_lock); hu->proto->recv(hu, (void *) data, count); hu->hdev->stat.byte_rx += count; @@ -381,6 +414,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) BT_DBG(""); + BT_ERR("hci_uart_register_dev"); + /* Initialize and register HCI device */ hdev = hci_alloc_dev(); if (!hdev) { @@ -508,16 +543,141 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, /* * We don't provide read/write/poll interface for user space. */ +struct hci_uart_hook { + unsigned int len; + unsigned char *head; + unsigned char data[HCI_MAX_EVENT_SIZE + 1]; /* save packet type at data[0] and then place event packet */ +}; + +static struct hci_uart_hook *hook; +static DECLARE_WAIT_QUEUE_HEAD(read_wait); + +void hci_uart_tty_read_hook(struct sk_buff *skb) +{ + if (!hook) { + BT_DBG("%s: hooking wasn't requested, skip it", __func__); + goto hci_uart_tty_read_hook_exit; + } + + if (bt_cb(skb)->pkt_type != HCI_EVENT_PKT) { + BT_DBG("%s: Packet type is %d, skip it", __func__, bt_cb(skb)->pkt_type); + goto hci_uart_tty_read_hook_exit; + } + + BT_DBG("%s: Received len = %d", __func__, skb->len); + if (skb->len > sizeof(hook->data)-1) { + BT_DBG("Packet size exceeds max len, skip it"); + goto hci_uart_tty_read_hook_exit; + } + + memcpy(hook->data, &bt_cb(skb)->pkt_type, 1); + skb_copy_from_linear_data(skb, &hook->data[1], skb->len); + hook->len = skb->len + 1; + +hci_uart_tty_read_hook_exit: + wake_up_interruptible(&read_wait); +} +EXPORT_SYMBOL(hci_uart_tty_read_hook); + +static int hci_uart_tty_access_allowed(void) +{ + char name[TASK_COMM_LEN]; + get_task_comm(name, current_thread_info()->task); + BT_DBG("%s: %s", __func__, name); + if (strcmp(name, "brcm_poke_helpe")) { + BT_ERR("%s isn't allowed", name); + return -EACCES; + } + + return 0; +} + static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { - return 0; + struct hci_uart *hu = (void *) tty->disc_data; + struct hci_dev *hdev = hu->hdev; + int ret = 0, count; + + BT_DBG("%s: hu = 0x%p hci_dev = 0x%p, nr = %d", __func__, hu, hdev, nr); + + ret = hci_uart_tty_access_allowed(); + if (ret < 0) + return ret; + + if (!hook) + return -ENOMEM; + + if (!hook->len) + interruptible_sleep_on_timeout(&read_wait, 3 * HZ); + + if (!hook->len) { + BT_INFO("No data to read"); + } else { + count = nr > hook->len ? hook->len : nr; + + ret = copy_to_user(buf, hook->head, count); + + hook->len -= (count - ret); + hook->head += (count - ret); + + ret = count - ret; + } + + if (!hook->len) { + BT_DBG("%s: free hook", __func__); + kfree(hook); + hook = NULL; + } + + BT_DBG("%s: ret = %d", __func__, ret); + + return ret; } static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { - return 0; + struct hci_uart *hu = (void *) tty->disc_data; + struct hci_dev *hdev = hu->hdev; + int ret; + + BT_DBG("%s: hu = 0x%p, hci_dev = 0x%p", __func__, hu, hdev); + + ret = hci_uart_tty_access_allowed(); + if (ret < 0) + return ret; + + if (!hdev) + return -ENODEV; + + if (!hook) + hook = kzalloc(sizeof(*hook), GFP_KERNEL); + else { + /* Cuase brcm_poke_helper's read/write is serialized, + * it's almost safe to init hook data here + */ + BT_INFO("hook data still remains"); + memset(hook, 0, sizeof(*hook)); + } + + if (!hook) + return -ENOMEM; + + hook->head = hook->data; + + hci_uart_flush(hdev); + +#if 1 + if (hdev->wake_peer) + hdev->wake_peer(hdev); +#endif + + ret = tty->ops->write(tty, data, count); + + BT_DBG("%s: ret = %d", __func__, ret); + + return ret; } static unsigned int hci_uart_tty_poll(struct tty_struct *tty, |