diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 121bf7c98de..5c046932abd 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -4,7 +4,7 @@ * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2005 Marcel Holtmann - * Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2000-2001, 2010-2012, Code Aurora Forum. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -51,6 +51,7 @@ static bool reset = 0; static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; +static void hci_uart_tty_wakeup_action(unsigned long data); int hci_uart_register_proto(struct hci_uart_proto *p) { @@ -276,6 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; spin_lock_init(&hu->rx_lock); + tasklet_init(&hu->tty_wakeup_task, hci_uart_tty_wakeup_action, + (unsigned long)hu); /* Flush any pending characters in the driver and line discipline. */ @@ -309,6 +312,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); + tasklet_kill(&hu->tty_wakeup_task); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { hu->proto->close(hu); if (hdev) { @@ -323,6 +328,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) * * Callback for transmit wakeup. Called when low level * device driver can accept more send data. + * This callback gets called from the isr context so + * schedule the send data operation to tasklet. * * Arguments: tty pointer to associated tty instance data * Return Value: None @@ -330,12 +337,26 @@ static void hci_uart_tty_close(struct tty_struct *tty) static void hci_uart_tty_wakeup(struct tty_struct *tty) { struct hci_uart *hu = (void *)tty->disc_data; + tasklet_schedule(&hu->tty_wakeup_task); +} + +/* hci_uart_tty_wakeup_action() + * + * Scheduled action to transmit data when low level device + * driver can accept more data. + */ +static void hci_uart_tty_wakeup_action(unsigned long data) +{ + struct hci_uart *hu = (struct hci_uart *)data; + struct tty_struct *tty; BT_DBG(""); if (!hu) return; + tty = hu->tty; + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (tty != hu->tty) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index dc482397e47..123fc24beb5 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -4,7 +4,7 @@ * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2004-2005 Marcel Holtmann - * Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved. + * Copyright (c) 2000-2001, 2010, 2012 Code Aurora Forum. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -66,6 +66,7 @@ struct hci_uart { unsigned long hdev_flags; struct hci_uart_proto *proto; + struct tasklet_struct tty_wakeup_task; void *priv; struct sk_buff *tx_skb;