aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/bluetooth
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_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.c164
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,