Added support for Atheros AR300x Bluetooth Chip
Subsystems (2)
PATCH 1/1 Added support for Atheros AR300x Bluetooth Chip
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time. It then wakes up the chip in case of a Bluetooth activity.
--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 378 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.c
drivers/bluetooth/Kconfig +11 -0
@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART
drivers/bluetooth/Makefile +1 -0
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)
drivers/bluetooth/hci_ath.c new file +353 -0
353 lines not on this page · raw message
drivers/bluetooth/hci_ldisc.c +6 -0
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))
drivers/bluetooth/hci_uart.h +7 -1
@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Signature · 1 line
1.6.3.3
Quoted 452 lines · suraj
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time. It then wakes up the chip in case of a Bluetooth activity.
Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 378 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +11
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +353
-0@@ -0,0 +1,353 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; +mm_segment_t oldfs; + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); +return status; +} + +static void ath_context_switch (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + + status =ath_wakeup_ar3001 (tty); +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +int ath_check_sleep_cmd (struct ath_struct *ath,unsigned char *packet) +{ +if (packet[0 ] ==0x04 && packet[1 ] ==0xFC ) + ath->cur_sleep = packet[3 ]; + +return 0 ; +} + + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + ath->cur_sleep =0 ; + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +BT_DBG ("hu %p" , hu); +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb); + +wake_up_interruptible (&ath->wqevt); + hu->priv =NULL ; +kfree (ath); +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping\n" ); +kfree (skb); +return 0 ; + } +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); +if (skbuf !=NULL ) +ath_check_sleep_cmd (ath, &skbuf->data[1 ]); + +return skbuf; +} + +static inline int ath_check_data_len (struct ath_struct *ath,int len) +{ + registerint room =skb_tailroom (ath->rx_skb); +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; +return len; + } + +return 0 ; +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; + registerchar *ptr; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +struct sk_buff *skbuf; + registerint len, type, dlen; + + skbuf =NULL ; +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + ptr = data; +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); +ath_check_data_len (ath, eh->plen); +continue ; +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); +BT_DBG ("ACL header: dlen %d" , dlen); +ath_check_data_len (ath, dlen); +continue ; +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; +BT_DBG ("SCO header: dlen %d" , sh->dlen); +ath_check_data_len (ath, sh->dlen); +continue ; + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + }return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); +if (!err) +BT_INFO ("HCIATH protocol initialized" ); + +else +BT_ERR ("HCIATH protocol registration failed" ); +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +2
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
drivers/bluetooth/hci_uart.h int bcsp_deinit(void); · line 99
Quoted 8 lines
drivers/bluetooth/hci_uart.h +5
-0@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Hi Marcel,
Can you please give your comments regarding the patch that I have sent you?
Regards
Suraj
Quoted 464 lines · suraj
Quoted 452 lines · suraj
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time. It then wakes up the chip in case of a Bluetooth activity.
Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 378 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +11
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +353
-0@@ -0,0 +1,353 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; +mm_segment_t oldfs; + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); +return status; +} + +static void ath_context_switch (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + + status =ath_wakeup_ar3001 (tty); +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +int ath_check_sleep_cmd (struct ath_struct *ath,unsigned char *packet) +{ +if (packet[0 ] ==0x04 && packet[1 ] ==0xFC ) + ath->cur_sleep = packet[3 ]; + +return 0 ; +} + + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + ath->cur_sleep =0 ; + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +BT_DBG ("hu %p" , hu); +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb); + +wake_up_interruptible (&ath->wqevt); + hu->priv =NULL ; +kfree (ath); +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping\n" ); +kfree (skb); +return 0 ; + } +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); +if (skbuf !=NULL ) +ath_check_sleep_cmd (ath, &skbuf->data[1 ]); + +return skbuf; +} + +static inline int ath_check_data_len (struct ath_struct *ath,int len) +{ + registerint room =skb_tailroom (ath->rx_skb); +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; +return len; + } + +return 0 ; +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; + registerchar *ptr; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +struct sk_buff *skbuf; + registerint len, type, dlen; + + skbuf =NULL ; +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + ptr = data; +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); +ath_check_data_len (ath, eh->plen); +continue ; +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); +BT_DBG ("ACL header: dlen %d" , dlen); +ath_check_data_len (ath, dlen); +continue ; +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; +BT_DBG ("SCO header: dlen %d" , sh->dlen); +ath_check_data_len (ath, sh->dlen); +continue ; + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + }return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); +if (!err) +BT_INFO ("HCIATH protocol initialized" ); + +else +BT_ERR ("HCIATH protocol registration failed" ); +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +2
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;drivers/bluetooth/hci_uart.h int bcsp_deinit(void); · line 99
Quoted 8 lines
drivers/bluetooth/hci_uart.h +5
-0@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Hi Marcel,
Quoted 5 lines
Can you please give your comments regarding the patch that I have sent you?
Regards
Suraj
Hi marcel,
A gentle remainder.
Can you please update the above driver to the Linux tree? If you find any issues please let me know so that I can do the needful.
Regards
Suraj
A message that is not in the archive (sent off-list or not yet received): 1271673889.19858.4.camel@atheros013-desktop
Re: Support for Atheros AR300x Bluetooth Chip
Some code comments below, Marcel if you have time please see if you have any other feedback for their next iteration as well so that they can incorporate on v3.
Suraj, on your v3 patch please use [PATCH v3], you can do this with git format patch by using --subject-prefix="PATCH v3".
Quoted 9 lines · Suraj Sumangala
Quoted 8 lines · suraj
Quoted 7 lines · suraj
Quoted 6 lines · suraj
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time. It then wakes up the chip in case of a Bluetooth activity.
Signed-off-by Suraj <[email protected]>
Don't indent the SOB, just leave it all the way to the left.
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 378 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +11
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +49
-0@@ -0,0 +1,353 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock;
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 57
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +int ath_wakeup_ar3001 (struct tty_struct *tty) +{
ath_wakeup_ar3001() should be made static
Quoted 55 lines
Quoted 55 lines
Quoted 55 lines
Quoted 55 lines
drivers/bluetooth/hci_ath.c new file +55
-0+struct termios settings; +int status =0x00 ; +mm_segment_t oldfs; + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); +return status; +} + +static void ath_context_switch (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + + status =ath_wakeup_ar3001 (tty); +if (!(status &TIOCM_CTS )) +return ;
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 120
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+ } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +int ath_check_sleep_cmd (struct ath_struct *ath,unsigned char *packet)
ath_check_sleep_cmd() should be made static. Also just make it return void, you're not checking the return value. Since its so small why not just fold the code in on ath_dequeue() ? If you're worried about the > 80 lines just do something like:
if (skbuf != NULL) if (packet[0] == 0x04 && packet[1] == 0xFC) ath->cur_sleep = packet[3]; }
or
if (!skbuf) return NULL; /* * Add some comment here explaining why you do this * as I already forgot too. */ if (packet[0] == 0x04 && packet[1] == 0xFC) ath->cur_sleep = packet[3]; return skbuf;
Please do add the comments about why this is done.
Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
drivers/bluetooth/hci_ath.c new file +44
-0+{ +if (packet[0 ] ==0x04 && packet[1 ] ==0xFC ) + ath->cur_sleep = packet[3 ]; + +return 0 ; +} + + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + ath->cur_sleep =0 ; + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +BT_DBG ("hu %p" , hu); +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv;
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 172
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb); + +wake_up_interruptible (&ath->wqevt);
cancel_work_sync(&ath->wqevt);
would wait for it for the scheduled work to finish, how about that instead. The wake up interruptible seems more like a hack here, no?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/bluetooth/hci_ath.c new file +5
-0+ hu->priv =NULL ; +kfree (ath); +return 0 ; +} +
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 185
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping\n" );
No need for \n here
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
drivers/bluetooth/hci_ath.c new file +21
-0+kfree (skb); +return 0 ; + } +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq);
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 214
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+if (skbuf !=NULL ) +ath_check_sleep_cmd (ath, &skbuf->data[1 ]); + +return skbuf; +} + +static inline int ath_check_data_len (struct ath_struct *ath,int len) +{
Remove the inline, and remove the return type, you never check it. Repeat this type of review for every other routine you have. If you are not using the return type just remove the thing. If code is used just once then it will automatically get the inline, if its used more than once on the same routine I am not sure if you get your inline -- but I doubt there is a serious performance penalty here.
Quoted 104 lines
Quoted 104 lines
Quoted 104 lines
Quoted 104 lines
drivers/bluetooth/hci_ath.c new file +104
-0+ registerint room =skb_tailroom (ath->rx_skb); +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; +return len; + } + +return 0 ; +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; + registerchar *ptr; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +struct sk_buff *skbuf; + registerint len, type, dlen; + + skbuf =NULL ; +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + ptr = data; +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); +ath_check_data_len (ath, eh->plen); +continue ; +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); +BT_DBG ("ACL header: dlen %d" , dlen); +ath_check_data_len (ath, dlen); +continue ; +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; +BT_DBG ("SCO header: dlen %d" , sh->dlen); +ath_check_data_len (ath, sh->dlen); +continue ; + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) {
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 326
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + }return count;
Please the return in a new line. This routien can later be cleaned up and split into a a couple of helpers, for now its OK I guess.
Quoted 96 lines
Quoted 96 lines
Quoted 83 lines
Quoted 72 lines
drivers/bluetooth/hci_ath.c new file +27
-0+} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); +if (!err) +BT_INFO ("HCIATH protocol initialized" ); + +else +BT_ERR ("HCIATH protocol registration failed" ); +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +2
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;drivers/bluetooth/hci_uart.h int bcsp_deinit(void); · line 99
Quoted 8 lines
drivers/bluetooth/hci_uart.h +5
-0@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Hi Marcel,
Quoted 5 lines
Can you please give your comments regarding the patch that I have sent you?
Regards
SurajHi marcel,
A gentle remainder.
Can you please update the above driver to the Linux tree? If you find any issues please let me know so that I can do the needful.
Quoted 7 lines
Quoted 2 lines
Regards
SurajHi Luis,
I had sent source code to support Atheros AR300x Bluetooth Chip to Marcel for sending it upstream before around two month.
I don't see it being two months, I see it being one month but one month without feedback is indeed quite a while. In my timeline I see it as:
02-22-2010 - Marcel responded to your first patch version for UART bluetooth 02-22-2010 - Suarj posted resplies to Marcel's questions 03-01-2010 - Suraj poked Marcel for feedback based on Suraj's comments
----------
03-11-2010 - Suraj posts new V2 patch but its sent busted with tabs/space mixup 03-11-2010 - Marcel asks for a resend
----------
03-14-2010 - Suaraj posts V3 patch with tabs/spaces fixed 03-23-2010 - First poke to Marcel and list
03-29-2010 - Second poke to Marcel and list
03-31-2010 - Patch for userspace hciattach.c changes posted
Please ensure to use [PATCH vX] for each X iteration so that it is clear this is a new iteration.
Quoted 2 lines
I am yet to get any response for that from his telling whether it is approved or rejected even after number of remainder mails.
I'd just poke again, every two days until you get a reply :)
Quoted 5 lines
Can you please help me on this? I am not sure what should be my next step.
Regards
Suraj
Marcel, *poke* re: Atheros AR300x Bluetooth Chip
To help I've reviewed this patch and the previous comments, I've made some of my own above. Please also install sparse and use it every time you make changes to the kernel and sparse check the code you write.
git clone git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
git checkout -b rel-042 v0.4.2
make -j
# no need to be root make install
Then to sparse check your code do:
make C=1 M=drivers/bluetooth/
This would have caught the two static checks I noted above.
Luis
PATCH 1/1 Added Host level support for Atheros AR3xxx Bluetooth Chip
In reply to surajAdded support for Atheros AR3xxx Bluetooth chip
Implemented feature to download firmware configuration from host.
--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 159 +++++++- tools/hciattach.h | 2 + tools/hciattach_ar3k.c | 1228 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1395 insertions(+), 1 deletions(-) create mode 100755 tools/hciattach_ar3k.c
Makefile.tools +1 -0
@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ tools/hciattach_st.c \ tools/hciattach_ti.c \ + tools/hciattach_ar3k.c \ tools/hciattach_tialt.c tools_hciattach_LDADD = lib/libbluetooth.la
tools/hciattach.8 +6 -0
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are .B any Unspecified HCI_UART interface, no vendor specific options .TP +.B ar3kalt +Atheros AR3xxx based modules with power management disabled +.TP +.B ar3k +Atheros AR3xxx based modules +.TP .B ericsson Ericsson based modules .TP
tools/hciattach.c +158 -1
171 lines not on this page · raw message
tools/hciattach.h +2 -0
@@ -36,6 +36,7 @@#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5int read_hci_event (int fd,unsigned char * buf,int size);int set_speed (int fd,struct termios *ti,int speed);
@@ -45,3 +46,4 @@ int texas_post(int fd, struct termios *ti);int texasalt_init (int fd,int speed,struct termios *ti);int stlc2500_init (int fd,bdaddr_t *bdaddr);int bgb2xx_init (int dd,bdaddr_t *bdaddr); +int ath_ps_download (int fd);
tools/hciattach_ar3k.c new file +1228 -0
1,228 lines not on this page · raw message
Signature · 1 line
1.7.0
Hi Suraj,
Quoted 154 lines · suraj
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time. It then wakes up the chip in case of a Bluetooth activity.
Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 378 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +11
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +99
-0@@ -0,0 +1,353 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; +mm_segment_t oldfs; + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status; + + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + oldfs =get_fs (); +set_fs (KERNEL_DS ); +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); +set_fs (oldfs); +return status; +} + +static void ath_context_switch (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu;
drivers/bluetooth/hci_ath.c line 109
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { +
Extra new line here.
Quoted 23 lines
drivers/bluetooth/hci_ath.c new file +23
-0+ status =ath_wakeup_ar3001 (tty); +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +int ath_check_sleep_cmd (struct ath_struct *ath,unsigned char *packet) +{ +if (packet[0 ] ==0x04 && packet[1 ] ==0xFC ) + ath->cur_sleep = packet[3 ]; + +return 0 ; +} + + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath;
drivers/bluetooth/hci_ath.c line 142
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + ath->cur_sleep =0 ;
You've used kzalloc, so cur_sleep is already 0
Quoted 12 lines
drivers/bluetooth/hci_ath.c new file +12
-0+ hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv;
drivers/bluetooth/hci_ath.c line 164
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+BT_DBG ("hu %p" , hu); +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv;
Add a extra line before the BT_DBG()
Quoted 15 lines
drivers/bluetooth/hci_ath.c new file +15
-0+BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb); + +wake_up_interruptible (&ath->wqevt); + hu->priv =NULL ; +kfree (ath); +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb)
drivers/bluetooth/hci_ath.c line 189
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+{ +struct ath_struct *ath = hu->priv; +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping\n" ); +kfree (skb); +return 0 ; + } +BT_DBG ("hu %p skb %p" , hu, skb);
Add a extra line before the BT_DBG()
Quoted 31 lines
drivers/bluetooth/hci_ath.c new file +31
-0+ +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); +if (skbuf !=NULL ) +ath_check_sleep_cmd (ath, &skbuf->data[1 ]); + +return skbuf; +} + +static inline int ath_check_data_len (struct ath_struct *ath,int len) +{ + registerint room =skb_tailroom (ath->rx_skb); +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb);
drivers/bluetooth/hci_ath.c line 230
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; +return len; + } + +return 0 ;
You can return ath->rx_count here and remove the return from the else. Or ad the return 0 on the if (len > room).
drivers/bluetooth/hci_ath.c line 242
Quoted 12 lines
drivers/bluetooth/hci_ath.c new file +12
-0+} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; + registerchar *ptr; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +struct sk_buff *skbuf; + registerint len, type, dlen;
Wouldn't be better let the compiler choose which vars it will put on the registers?
drivers/bluetooth/hci_ath.c line 244
Quoted 2 lines
drivers/bluetooth/hci_ath.c new file +2
-0+ + skbuf =NULL ;
You never use skbuf after here.
drivers/bluetooth/hci_ath.c line 247
Quoted 3 lines
drivers/bluetooth/hci_ath.c new file +3
-0+BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + ptr = data;
You can set ptr to data when you declare it.
Quoted 89 lines
drivers/bluetooth/hci_ath.c new file +89
-0+while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); +ath_check_data_len (ath, eh->plen); +continue ; +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); +BT_DBG ("ACL header: dlen %d" , dlen); +ath_check_data_len (ath, dlen); +continue ; +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; +BT_DBG ("SCO header: dlen %d" , sh->dlen); +ath_check_data_len (ath, sh->dlen); +continue ; + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + }return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush,
drivers/bluetooth/hci_ath.c line 346
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); +if (!err) +BT_INFO ("HCIATH protocol initialized" ); + +else +BT_ERR ("HCIATH protocol registration failed" );
Add a new line here.
Quoted 69 lines
drivers/bluetooth/hci_ath.c new file +7
-0+return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Signature · 8 lines
1.6.3.3 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Gustavo F. Padovan http://padovan.org
PATCH v3 1/1 Added support for Atheros AR300x Bluetooth Chip
In reply to surajThis protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
It then wakes up the chip in case of a Bluetooth activity.
* Third version
** Updated with extra spacing and indentation
** made function definitions static
** Removed inline and register keyword usage.
** Removed unused return calls.
** Incorporated code comments by Luis and Gustavo
Thanks Luis and Gustavo for your comments
--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 409 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.c
drivers/bluetooth/Kconfig +11 -0
@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART
drivers/bluetooth/Makefile +1 -0
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)
drivers/bluetooth/hci_ath.c new file +384 -0
384 lines not on this page · raw message
drivers/bluetooth/hci_ldisc.c +6 -0
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))
drivers/bluetooth/hci_uart.h +7 -1
@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Signature · 1 line
1.7.0
Hi Suraj,
Quoted 163 lines · suraj
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
It then wakes up the chip in case of a Bluetooth activity.* Third version
** Updated with extra spacing and indentation
** made function definitions static
** Removed inline and register keyword usage.
** Removed unused return calls.
** Incorporated code comments by Luis and GustavoThanks Luis and Gustavo for your comments
Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 409 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +11
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +98
-0@@ -0,0 +1,384 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; + + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status; + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_context_switch (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu;
drivers/bluetooth/hci_ath.c line 108
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { +
Extra blank line here.
Quoted 95 lines
drivers/bluetooth/hci_ath.c new file +95
-0+ status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb); + +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; + +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu)
drivers/bluetooth/hci_ath.c line 213
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + +
Another extra blank line here.
Quoted 34 lines
drivers/bluetooth/hci_ath.c new file +34
-0+/* +* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ]; + +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */
drivers/bluetooth/hci_ath.c line 257
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +
Extra blank line here too.
Quoted 185 lines
drivers/bluetooth/hci_ath.c new file +127
-0+BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; + +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; + +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err) +BT_INFO ("HCIATH protocol initialized" ); +else +BT_ERR ("HCIATH protocol registration failed" ); + +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Signature · 1 line
1.7.0
Signature · 2 lines
Gustavo F. Padovan http://padovan.org
Quoted 4 lines · Suraj Sumangala
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
It then wakes up the chip in case of a Bluetooth activity.
The above commit log needs some more work. Try to keep the commit log entry subject to about 50 characters, the context should not pass around 75 characters. Your commit also indicates this is a "protocol" ? This is driver, and you do have some hacks for enhancing power saving, but that is not that relevant to the commit log.
How about:
---
Add support for the Atheros AR300x Bluetooth Chip
This adds support for the Atheros Bluetooth serial protocol to support the AR300x chipsets. The serial protocol implements enhanced power management features for the AR300x chipsets.
---
Of course you will need to adjust the subject and prepend it with PATCH v4, just as you did with a v3 for this patch.
Then, this stuff:
Quoted 3 lines
* Third version
** Updated with extra spacing and indentation
Do you use checkpatch.pl for your patches? If not please add check your patches after committing them with:
git show ./scripts/checkpatch.pl -
vi drivers/bluetooth/hci_ath.c
git commit -a --amend
And repeat until checkpatch.pl is git happy :)
Quoted 6 lines
** made function definitions static
** Removed inline and register keyword usage.
** Removed unused return calls.
** Incorporated code comments by Luis and GustavoThanks Luis and Gustavo for your comments
Remove it from the commit log, if you do want to add some extra text to the patch youc an put it below the three dashes ("-") where the diff stat goes:
Quoted 5 lines
Signed-off-by Suraj <[email protected]>---
^^^
These are the three lines, anything below is ignored by git am when the maintainer applies the patch. So you can add anything you want ignored by git am here.
Quoted 14 lines
drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 409 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +0
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
drivers/bluetooth/Kconfig config BT_HCIUART_BCSP · line 68
Quoted 10 lines
drivers/bluetooth/Kconfig +8
-0Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips.
Please adjust the description as well. How about:
+ HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets, it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enabling this + option will build HCI Atheros support into the hci_uart driver. + Enable this option if you have an UART Atheros AR300x serial + device.
Quoted 76 lines
drivers/bluetooth/Kconfig +3
-0+ + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +54
-0@@ -0,0 +1,384 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +};
drivers/bluetooth/hci_ath.c line 64
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; + + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status;
No need for double () parens here. This should be fine:
+ if (status & TIOCM_CTS)
+ return status;
You would use double parens if you are doing a check against another flag as well.
Quoted 20 lines
drivers/bluetooth/hci_ath.c new file +20
-0+ +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL );
drivers/bluetooth/hci_ath.c line 94
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_context_switch (struct work_struct *work)
Can you please rename this to ath_hci_uart_work()
Quoted 61 lines
drivers/bluetooth/hci_ath.c new file +61
-0+{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + + status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */
drivers/bluetooth/hci_ath.c line 165
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb);
No need for the check, kfree_skb() does that for you and it has it optimized for the case where the skb you pass is NULL. You can just do:
+ kfree_skb(ath->rx_skb);
drivers/bluetooth/hci_ath.c line 173
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+ +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +}
Did you give this new patch a spin by looping bringing up, scanning, bringing the interface down? Or have a loop doing a scan while in another window you bring the interface up and down?
drivers/bluetooth/hci_ath.c line 182
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; + +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */
Add a space after packet. Why does it not support SCO over HCI BTW? Just curious. I'm new to BT :) Is this common? If this is common can't the BT stack be informed of these things so that they don't pass the skbs to the driver?
This could be done in a separate patch though if this is the case though.
Quoted 32 lines
drivers/bluetooth/hci_ath.c new file +32
-0+BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + + +/*
drivers/bluetooth/hci_ath.c line 224
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ];
Might as well just do this:
+ if (skbuf->data[0] == 0x01 &&
+ skbuf->data[1] == 0x04 &&
+ skbuf->data[2] == 0xFC)
+ ath->cur_sleep = skbuf->data[4];
Is this sort of check done in any other drivers/protocols? If so a helper could be added to hci_uart.h if this is the case, but likely better though a separate patch.
Quoted 218 lines
drivers/bluetooth/hci_ath.c new file +160
-0+ +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; + +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; + +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err) +BT_INFO ("HCIATH protocol initialized" ); +else +BT_ERR ("HCIATH protocol registration failed" ); + +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Signature · 1 line
1.7.0
Hi Luis,
Quoted 34 lines · Luis Rodriguez
Quoted 4 lines · Suraj Sumangala
This protocol implements support for power management feature provided by AR300x chip. This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
It then wakes up the chip in case of a Bluetooth activity.The above commit log needs some more work. Try to keep the commit log entry subject to about 50 characters, the context should not pass around 75 characters. Your commit also indicates this is a "protocol" ? This is driver, and you do have some hacks for enhancing power saving, but that is not that relevant to the commit log.
How about:
---
Add support for the Atheros AR300x Bluetooth ChipThis adds support for the Atheros Bluetooth serial protocol to support the AR300x chipsets. The serial protocol implements enhanced power management features for the AR300x chipsets.
Reviewed-by Luis R. Rodriguez <[email protected]>Signed-off-by Suraj <[email protected]>---
Of course you will need to adjust the subject and prepend it with PATCH v4, just as you did with a v3 for this patch.
Then, this stuff:
Quoted 3 lines
* Third version
** Updated with extra spacing and indentation
Quoted 8 lines
Do you use checkpatch.pl for your patches? If not please add check your patches after committing them with:
git show
./scripts/checkpatch.pl-
vidrivers/bluetooth/hci_ath.c
git commit -a --amendAnd repeat until checkpatch.pl is git happy :)
Yes, I had done a checkpatch round with the patch. it looked happy. Did you see any issue that could should have been caught by it?
Quoted 267 lines
Quoted 7 lines
** made function definitions static
** Removed inline and register keyword usage.
** Removed unused return calls.
** Incorporated code comments by Luis and GustavoThanks Luis and Gustavo for your comments
Remove it from the commit log, if you do want to add some extra text to the patch youc an put it below the three dashes ("-") where the diff stat goes:
Quoted 4 lines
Signed-off-by Suraj <[email protected]>---
^^^
These are the three lines, anything below is ignored by git am when the maintainer applies the patch. So you can add anything you want ignored by git am here.
Quoted 14 lines
drivers/bluetooth/Kconfig | 11 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 409 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +0
-0@@ -58,6 +58,17 @@ config BT_HCIUART_BCSPdrivers/bluetooth/Kconfig config BT_HCIUART_BCSP · line 68
Quoted 10 lines
drivers/bluetooth/Kconfig +8
-0Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x Board support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between Bluetooth device and host with support for Atheros AR300x + power management feature. This protocol is required for + serial Bluetooth devices that are based on Atheros AR300x chips.Please adjust the description as well. How about:
(quoted diff) +9
-0+ HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets, it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enabling this + option will build HCI Atheros support into the hci_uart driver. + Enable this option if you have an UART Atheros AR300x serial + device.Quoted 78 lines
drivers/bluetooth/Kconfig +3
-0+ + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +54
-0@@ -0,0 +1,384 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +};drivers/bluetooth/hci_ath.c line 64
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status =0x00 ; + + status = tty->driver->ops->tiocmget (tty,NULL ); + +if ((status &TIOCM_CTS )) +return status;No need for double () parens here. This should be fine:
(quoted diff) +2
-0+ if (status & TIOCM_CTS) + return status;You would use double parens if you are doing a check against another flag as well.
Quoted 20 lines
drivers/bluetooth/hci_ath.c new file +20
-0+ +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL );drivers/bluetooth/hci_ath.c line 94
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_context_switch (struct work_struct *work)Can you please rename this to
ath_hci_uart_work()Quoted 61 lines
drivers/bluetooth/hci_ath.c new file +61
-0+{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + + status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_context_switch); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ drivers/bluetooth/hci_ath.c line 165
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +if (ath->rx_skb) +kfree_skb (ath->rx_skb);No need for the check,
kfree_skb()does that for you and it has it optimized for the case where the skb you pass is NULL. You can just do:+
kfree_skb(ath->rx_skb);
Quoted 14 lines
drivers/bluetooth/hci_ath.c line 173
Quoted 8 lines
drivers/bluetooth/hci_ath.c new file +8
-0+ +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +}Did you give this new patch a spin by looping bringing up, scanning, bringing the interface down? Or have a loop doing a scan while in another window you bring the interface up and down?
Yep, Have been testing it for sometime. Haven't seen any issue yet (Hope I dont see any :-) )
Quoted 6 lines
Quoted 6 lines
drivers/bluetooth/hci_ath.c new file +6
-0+ +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; +
Quoted 9 lines
drivers/bluetooth/hci_ath.c line 182
Quoted 3 lines
drivers/bluetooth/hci_ath.c new file +3
-0+if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet.AR3001 does not support SCO over HCI */ Add a space after packet. Why does it not support SCO over HCI BTW? Just curious. I'm new to BT :) Is this common? If this is common can't the BT stack be informed of these things so that they don't pass the skbs to the driver?
From my experience, it is common for smaller BT devices (headsets) and devices with memory limitations.
I guess, there is no way to tell SCO routing using any HCI cmd/Event.
In the Linux Ubuntu distro that I use, it is controlled using the "SCORouting" flag in "/etc/bluetooth/audio.conf". Since it is a user configuration, driver can not assume that the flag will be set.
So, this is like a precautionary check.
Quoted 53 lines
This could be done in a separate patch though if this is the case though.
Quoted 32 lines
drivers/bluetooth/hci_ath.c new file +32
-0+BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + + +/* drivers/bluetooth/hci_ath.c line 224
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ];Might as well just do this:
drivers/bluetooth/hci_ath.c new file +4
-0+if (skbuf->data[0 ] ==0x01 && + skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ];
Quoted 3 lines
Is this sort of check done in any other
drivers/protocols? If so a helper could be added tohci_uart.hif this is the case, but likely better though a separate patch.
No, this check is done only for this specific driver/protocol.
This is the reason why we had to go for board specific driver change. Otherways, we could have used the default HCI driver implementation.
Quoted 205 lines
Quoted 205 lines
drivers/bluetooth/hci_ath.c new file +160
-0+ +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data; + +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data; + dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data; + +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err) +BT_INFO ("HCIATH protocol initialized" ); +else +BT_ERR ("HCIATH protocol registration failed" ); + +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +2
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
Quoted 14 lines
Quoted 10 lines
drivers/bluetooth/hci_uart.h +5
-1@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif --Quoted 4 lines
1.7.0
Thanks for the comments.
Regards,
Suraj
PATCH v4 1/1 Add support for the Atheros AR300x Bluetooth Chip
In reply to surajThis implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.
--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.c
drivers/bluetooth/Kconfig +14 -0
@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x serial Bluetooth support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets. it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enable this option + if you have an UART Atheros AR300x serial device. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART
drivers/bluetooth/Makefile +1 -0
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)
drivers/bluetooth/hci_ath.c new file +378 -0
378 lines not on this page · raw message
drivers/bluetooth/hci_ldisc.c +6 -0
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))
drivers/bluetooth/hci_uart.h +7 -1
@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Signature · 1 line
1.7.0
Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip
Quoted 7 lines · Suraj Sumangala
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Signed-off-by Suraj <[email protected]>
Looks good to me now, thanks for your patience and the resends. Marcel?
Luis
Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip
In reply to surajQuoted 323 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +14
-0@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x serial Bluetooth support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets. it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enable this option + if you have an UART Atheros AR300x serial device. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +265
-0@@ -0,0 +1,378 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status = tty->driver->ops->tiocmget (tty,NULL ); + +if (status &TIOCM_CTS ) +return status; + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_hci_uart_work (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_hci_uart_work); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +kfree_skb (ath->rx_skb); + +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; + +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet. AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + +/* +* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && + skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ]; + +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ;
drivers/bluetooth/hci_ath.c line 275
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data;
Use hci_event_hdr() here like hci_h4.c does.
drivers/bluetooth/hci_ath.c line 284
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
And hci_acl_hdr() here.
drivers/bluetooth/hci_ath.c line 293
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
hci_sco_hdr() here.
Quoted 48 lines
drivers/bluetooth/hci_ath.c new file +48
-0+ +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ;
drivers/bluetooth/hci_ath.c line 351
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +}
Just out of curiosity. I never worked in the driver world, but is it ok to duplicate lots of code when working with drivers? hci_h4.c and this patch share lots of similar code. ath_recv() and h4_recv() are exactly the same except for one line, the ath->rx_count = 0; at case HCIATH_W4_DATA. Does this line makes real difference? recv() is not the only function duplicating code here.
Quoted 12 lines
drivers/bluetooth/hci_ath.c new file +12
-0+ +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void )
drivers/bluetooth/hci_ath.c line 373
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+{ +int err =hci_uart_register_proto (&athp); + +if (!err) +BT_INFO ("HCIATH protocol initialized" ); +else +BT_ERR ("HCIATH protocol registration failed" ); + +return err; +}
BTW, we never check this return value on hci_ldisc.c, why?
Quoted 65 lines
drivers/bluetooth/hci_ath.c new file +5
-0+ +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif Signature · 1 line
1.7.0
Signature · 2 lines
Gustavo F. Padovan http://padovan.org
Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip
Hi Gustavo,
Quoted 419 lines · Gustavo F. Padovan
Quoted 323 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +14
-0@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x serial Bluetooth support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets. it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enable this option + if you have an UART Atheros AR300x serial device. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +265
-0@@ -0,0 +1,378 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status = tty->driver->ops->tiocmget (tty,NULL ); + +if (status &TIOCM_CTS ) +return status; + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_hci_uart_work (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_hci_uart_work); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +kfree_skb (ath->rx_skb); + +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; + +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet. AR3001 does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + +/* +* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && + skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ]; + +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ;drivers/bluetooth/hci_ath.c line 275
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data;Use
hci_event_hdr()here likehci_h4.cdoes.drivers/bluetooth/hci_ath.c line 284
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data;And
hci_acl_hdr()here.drivers/bluetooth/hci_ath.c line 293
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
hci_sco_hdr()here.Quoted 57 lines
drivers/bluetooth/hci_ath.c new file +57
-0+ +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count;
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 351
Quoted 1 line
drivers/bluetooth/hci_ath.c new file +1
-0+}Just out of curiosity. I never worked in the driver world, but is it ok to duplicate lots of code when working with drivers?
hci_h4.cand this patch share lots of similar code.ath_recv()andh4_recv()are exactly the same except for one line, theath->rx_count= 0; at caseHCIATH_W4_DATA. Does this line makes real difference?recv()is not the only function duplicating code here.
Let me try to anwer you here. I am also new to the driver world, so correct me if I am wrong.
Both drivers do the same job, expect that the ATH driver does something more on the data transmit path. So, the receive path does the same thing. That is the reason why both looks same. This could possibly change later as new feature will be added to the ATH protocol.
The function "hci_recv_fragment()" could potentially replace most of the code in the ath_recv() function. But, unfortunately this function require the caller to provide the HCI Packet type as parameter.
This defeats all the advantage of "hci_recv_fragment()" in a UART HCI transport driver as all types of packets are received through the same callback. So the caller will have to write the same messy code in ath_recv() to find out the packet type negating all the advantages of "hci_recv_fragment()".
Quoted 17 lines
Quoted 17 lines
drivers/bluetooth/hci_ath.c new file +16
-0+ +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err)
Quoted 8 lines
drivers/bluetooth/hci_ath.c line 373
Quoted 6 lines
drivers/bluetooth/hci_ath.c new file +6
-0+BT_INFO ("HCIATH protocol initialized" ); + else + BT_ERR("HCIATH protocol registration failed"); + +return err; +}BTW, we never check this return value on
hci_ldisc.c, why?
you, are correct. Just thought of keeping the same signature used by other protocol. moreover hci_ldisc.c being a common file used by all protocol it is possible that somebody want to check the return value at later point of time. So, kept it that way so that we do not have a problem then :-D
Your thoughts?
Quoted 70 lines
Quoted 60 lines
drivers/bluetooth/hci_ath.c new file +5
-0+ +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-2@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif --Quoted 6 lines
1.7.0
--
Gustavo F. Padovan
http://padovan.org
Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip
Hi Suraj,
Quoted 23 lines · Suraj Sumangala
Hi Gustavo,
Quoted 19 lines · Gustavo F. Padovan
Quoted 17 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Signed-off-by Suraj <[email protected]>---
drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-)create mode 100755
drivers/bluetooth/hci_ath.c
..snip..
Quoted 146 lines
Quoted 137 lines
Quoted 43 lines
drivers/bluetooth/hci_ath.c new file +43
-0+ +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ;drivers/bluetooth/hci_ath.c line 275
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh = (struct hci_event_hdr *)ath->rx_skb->data;Use
hci_event_hdr()here likehci_h4.cdoes.drivers/bluetooth/hci_ath.c line 284
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah = (struct hci_acl_hdr *)ath->rx_skb->data;And
hci_acl_hdr()here.drivers/bluetooth/hci_ath.c line 293
Quoted 9 lines
drivers/bluetooth/hci_ath.c new file +9
-0+ dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
hci_sco_hdr()here.Quoted 57 lines
drivers/bluetooth/hci_ath.c new file +57
-0+ +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count;Quoted 8 lines
Quoted 1 line
+}
Just out of curiosity. I never worked in the driver world, but is it ok to duplicate lots of code when working with drivers?
hci_h4.cand this patch share lots of similar code.ath_recv()andh4_recv()are exactly the same except for one line, theath->rx_count= 0; at caseHCIATH_W4_DATA. Does this line makes real difference?recv()is not the only function duplicating code here.
Quoted 8 lines
Let me try to anwer you here. I am also new to the driver world, so correct me if I am wrong.
Both drivers do the same job, expect that the ATH driver does something more on the data transmit path. So, the receive path does the same thing. That is the reason why both looks same. This could possibly change later as new feature will be added to the ATH protocol.
Ok. I'm thinking if it is not possible create a separated 'lib' with the common code. That's why I asked about the code duplication. I don't know how worth it is, since we have only 3 drivers using similar code.
Quoted 40 lines
The function "
hci_recv_fragment()" could potentially replace most of the code in theath_recv()function. But, unfortunately this function require the caller to provide the HCI Packet type as parameter.This defeats all the advantage of "
hci_recv_fragment()" in a UART HCI transport driver as all types of packets are received through the same callback. So the caller will have to write the same messy code inath_recv()to find out the packet type negating all the advantages of "hci_recv_fragment()".Quoted 17 lines
Quoted 17 lines
drivers/bluetooth/hci_ath.c new file +16
-0+ +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err)Quoted 8 lines
drivers/bluetooth/hci_ath.c line 373
Quoted 6 lines
drivers/bluetooth/hci_ath.c new file +6
-0+BT_INFO ("HCIATH protocol initialized" ); + else + BT_ERR("HCIATH protocol registration failed"); + +return err; +}BTW, we never check this return value on
hci_ldisc.c, why?
Quoted 7 lines
you, are correct. Just thought of keeping the same signature used by other protocol. moreover
hci_ldisc.cbeing a common file used by all protocol it is possible that somebody want to check the return value at later point of time. So, kept it that way so that we do not have a problem then :-DYour thoughts?
Yes, your code is right, the return value should be kept. The problem is that hci_uart_init() doesn't check any other protocol initialization (h4, bcsp and ll). My thought is: we really need to check?
Marcel, can you answer that?
Quoted 75 lines
Quoted 62 lines
Quoted 62 lines
drivers/bluetooth/hci_ath.c new file +5
-0+ +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +7
-2@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif --1.7.0
Quoted 8 lines
Quoted 4 lines
--
Gustavo F. Padovan
http://padovan.org--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 2 lines
Gustavo F. Padovan http://padovan.org
PATCH v5 1/1 Add support for the Atheros AR300x Bluetooth Chip
In reply to surajThis implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.
--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.c
drivers/bluetooth/Kconfig +14 -0
@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x serial Bluetooth support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets. it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enable this option + if you have an UART Atheros AR300x serial device. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUART
drivers/bluetooth/Makefile +1 -0
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)
drivers/bluetooth/hci_ath.c new file +378 -0
378 lines not on this page · raw message
drivers/bluetooth/hci_ldisc.c +6 -0
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))
drivers/bluetooth/hci_uart.h +7 -1
@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Signature · 1 line
1.7.0
Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
Hi marcel,
Quoted 482 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Reviewed-by Gustavo F. Padovan <[email protected]>Signed-off-by Suraj <[email protected]>--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cdrivers/bluetooth/Kconfig +14
-0@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP Say Y here to compile support for HCI BCSP protocol. +config BT_HCIUART_ATH + bool "Atheros AR300x serial Bluetooth support" + depends on BT_HCIUART + help + HCIATH (HCI Atheros) is a serial protocol for communication + between the host and Atheros AR300x Bluetooth devices. The + protocol implements enhaned power management features for the + the AR300x chipsets. it lets the controller chip go to sleep + mode if there is no Bluetooth activity for some time and wakes + up the chip in case of a Bluetooth activity. Enable this option + if you have an UART Atheros AR300x serial device. + + Say Y here to compile support for HCIATH protocol. + config BT_HCIUART_LL bool "HCILL protocol support" depends on BT_HCIUARTdrivers/bluetooth/Makefile +1
-0@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o hci_uart-objs := $(hci_uart-y)drivers/bluetooth/hci_ath.c new file +378
-0@@ -0,0 +1,378 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + +/* HCIATH receiver States */ +#define HCIATH_W4_PACKET_TYPE 0 +#define HCIATH_W4_EVENT_HDR 1 +#define HCIATH_W4_ACL_HDR 2 +#define HCIATH_W4_SCO_HDR 3 +#define HCIATH_W4_DATA 4 + +struct ath_struct { +struct hci_uart *hu; +unsigned int rx_state; +unsigned int rx_count; +unsigned int cur_sleep; + +spinlock_t hciath_lock; +struct sk_buff *rx_skb; +struct sk_buff_head txq; +wait_queue_head_t wqevt; +struct work_struct ctxtsw; +}; + +static int ath_wakeup_ar3001 (struct tty_struct *tty) +{ +struct termios settings; +int status = tty->driver->ops->tiocmget (tty,NULL ); + +if (status &TIOCM_CTS ) +return status; + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + +/* Disable Automatic RTSCTS */ + settings.c_cflag &= ~CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Clear RTS first */ + tty->driver->ops->tiocmset (tty,NULL ,0x00 ,TIOCM_RTS ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +/* Set RTS, wake up board */ + tty->driver->ops->tiocmset (tty,NULL ,TIOCM_RTS ,0x00 ); +mdelay (20 ); + + status = tty->driver->ops->tiocmget (tty,NULL ); + +n_tty_ioctl_helper (tty,NULL ,TCGETS , (unsigned long )&settings); + + settings.c_cflag |=CRTSCTS ; +n_tty_ioctl_helper (tty,NULL ,TCSETS , (unsigned long )&settings); + +return status; +} + +static void ath_hci_uart_work (struct work_struct *work) +{ +int status; +struct ath_struct *ath; +struct hci_uart *hu; +struct tty_struct *tty; + + ath = container_of(work, struct ath_struct, ctxtsw); + + hu = ath->hu; + tty = hu->tty; + +/* verify and wake up controller */ +if (ath->cur_sleep) { + status =ath_wakeup_ar3001 (tty); + +if (!(status &TIOCM_CTS )) +return ; + } + +/* Ready to send Data */ +clear_bit (HCI_UART_SENDING , &hu->tx_state); +hci_uart_tx_wakeup (hu); +} + +/* Initialize protocol */ +static int ath_open (struct hci_uart *hu) +{ +struct ath_struct *ath; + +BT_DBG ("hu %p" , hu); + + ath =kzalloc (sizeof (*ath),GFP_ATOMIC ); +if (!ath) +return -ENOMEM ; + +skb_queue_head_init (&ath->txq); +spin_lock_init (&ath->hciath_lock); + + hu->priv = ath; + ath->hu = hu; + +init_waitqueue_head (&ath->wqevt); +INIT_WORK (&ath->ctxtsw, ath_hci_uart_work); + +return 0 ; +} + +/* Flush protocol data */ +static int ath_flush (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +return 0 ; +} + +/* Close protocol */ +static int ath_close (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; + +BT_DBG ("hu %p" , hu); + +skb_queue_purge (&ath->txq); + +kfree_skb (ath->rx_skb); + +cancel_work_sync (&ath->ctxtsw); + + hu->priv =NULL ; +kfree (ath); + +return 0 ; +} + +/* Enqueue frame for transmittion */ +static int ath_enqueue (struct hci_uart *hu,struct sk_buff *skb) +{ +struct ath_struct *ath = hu->priv; + +if (bt_cb (skb)->pkt_type ==HCI_SCODATA_PKT ) { + +/* Discard SCO packet. AR300x does not support SCO over HCI */ +BT_DBG ("SCO Packet over HCI received Dropping" ); + +kfree (skb); + +return 0 ; + } + +BT_DBG ("hu %p skb %p" , hu, skb); + +/* Prepend skb with frame type */ +memcpy (skb_push (skb,1 ), &bt_cb (skb)->pkt_type,1 ); + +skb_queue_tail (&ath->txq, skb); +set_bit (HCI_UART_SENDING , &hu->tx_state); + +schedule_work (&ath->ctxtsw); + +return 0 ; +} + +static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + +/* +* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later +* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && + skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ]; + +return skbuf; +} + +static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh =hci_event_hdr (ath->rx_skb); + +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah =hci_acl_hdr (ath->rx_skb); + dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh =hci_sco_hdr (ath->rx_skb); + +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +} + +static struct hci_uart_proto athp = { + .id =HCI_UART_ATH , + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, +}; + +int ath_init (void ) +{ +int err =hci_uart_register_proto (&athp); + +if (!err) +BT_INFO ("HCIATH protocol initialized" ); +else +BT_ERR ("HCIATH protocol registration failed" ); + +return err; +} + +int ath_deinit (void ) +{ +return hci_uart_unregister_proto (&athp); +}drivers/bluetooth/hci_ldisc.c +6
-0@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)#ifdef CONFIG_BT_HCIUART_LL ll_init ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_init (); +#endif return 0 ; }@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)#ifdef CONFIG_BT_HCIUART_LL ll_deinit ();#endif +#ifdef CONFIG_BT_HCIUART_ATH +ath_deinit (); +#endif /* Release tty registration of line discipline */ if ((err =tty_unregister_ldisc (N_HCI )))drivers/bluetooth/hci_uart.h +2
-1@@ -33,13 +33,14 @@#define HCIUARTGETDEVICE _IOR('U', 202, int)/* UART protocols */ -#define HCI_UART_MAX_PROTO 5 +#define HCI_UART_MAX_PROTO 6#define HCI_UART_H4 0#define HCI_UART_BCSP 1#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5struct hci_uart ;
drivers/bluetooth/hci_uart.h int bcsp_deinit(void); · line 99
Quoted 8 lines
drivers/bluetooth/hci_uart.h +5
-0@@ -91,3 +92,8 @@ int bcsp_deinit(void);int ll_init (void );int ll_deinit (void );#endif + +#ifdef CONFIG_BT_HCIUART_ATH +int ath_init (void ); +int ath_deinit (void ); +#endif
Can you verify the patch let me know your comments?
Regards
Suraj
PATCH 1/1 New Firmware for Atheros bluetooth chipset AR3011
--- WHENCE | 9 +++++++++ ath3k-2.fw | Bin 0 -> 246804 bytes 2 files changed, 9 insertions(+), 0 deletions(-) create mode 100644 ath3k-2.fw
WHENCE +9 -0
@@ -1229,3 +1229,12 @@ Licence: Redistributable, provided by Realtek in their driver source download. -------------------------------------------------------------------------- + +Driver: DFU Driver for Atheros bluetooth chipset AR3011 + +File: ath3k-2.fw +Info: v2.0 + +Licence: Redistributable. See LICENCE.atheros_firmware for details + +--------------------------------------------------------------------------
ath3k-2.fw new file binary +0 -0
Signature · 1 line
1.6.3.3
PATCH 1/1 patch to request new firmware for AR3011 Chip
--- drivers/bluetooth/ath3k.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)
drivers/bluetooth/ath3k.c +6 -3
@@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf, data->udev = udev; -if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { -kfree (data); -return -EIO ; +if (request_firmware (&firmware,"ath3k-2.fw" , &udev->dev) <0 ) { +BT_DBG ("requesting old firmware" ); +if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { +kfree (data); +return -EIO ; + } } size =max_t (uint, firmware->size,4096 );
Signature · 1 line
1.7.0
Re: [PATCH] patch to request new firmware for AR3011 Chip
Quoted 17 lines · Suraj Sumangala
Signed-off-by Vikram Kandukuri <[email protected]>--- drivers/bluetooth/ath3k.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)drivers/bluetooth/ath3k.c +0
-2@@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf, data->udev = udev; -if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { -kfree (data);
drivers/bluetooth/ath3k.c static int ath3k_probe(struct usb_interface *intf, · line 133
Quoted 10 lines
drivers/bluetooth/ath3k.c +6
-1-return -EIO ; +if (request_firmware (&firmware,"ath3k-2.fw" , &udev->dev) <0 ) { +BT_DBG ("requesting old firmware" ); +if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { +kfree (data); +return -EIO ; + } } size =max_t (uint, firmware->size,4096 );
Looks OK but your subject should be something like:
[PATCH] ath3k: add support for new firmware
And your commit log is empty, other than your subject, please be a little more descriptive. Describe what are the shiny new bells and whistles added onto the new firmware. The more description you can provide, the better.
Luis
PATCH v2 1/1 ath3k: add support for new firmware
In reply to surajNew firmware has few critical bug fixes and shared antenna support.
--- drivers/bluetooth/ath3k.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)
drivers/bluetooth/ath3k.c +6 -3
@@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf, data->udev = udev; -if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { -kfree (data); -return -EIO ; +if (request_firmware (&firmware,"ath3k-2.fw" , &udev->dev) <0 ) { +BT_DBG ("requesting old firmware" ); +if (request_firmware (&firmware,"ath3k-1.fw" , &udev->dev) <0 ) { +kfree (data); +return -EIO ; + } } size =max_t (uint, firmware->size,4096 );
Signature · 1 line
1.7.0
Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
In reply to surajHi Marcel,
Can you take a look at the patch? Your review has been pending for sometime.
Quoted 26 lines · suraj
Hi marcel,
Quoted 9 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Reviewed-by Gustavo F. Padovan <[email protected]>Signed-off-by Suraj <[email protected]>Quoted 9 lines
--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cCan you verify the patch let me know your comments?
Regards
Suraj
buffer starvation with multiple ACL link
Hi,
I am seeing a strange issue with multiple ACL connection with CSR chip.
I am having 2 ACL link, one with FTP going on and another streaming A2DP.
The moment the A2DP link goes out of range ,I see that the FTP also stops. It resumes as soon as A2DP comes back in range.
On further analysis I could verify that since the A2DP link is blocked( due to remote being OoR) the controller's ACL buffers with A2DP data are stuck.
But at the host level this is not considered and Bluez keeps sending A2DP data until it blocks all the ACL buffers which in turns blocks FTP also.
I was expecting controller to flush these packets sometime and free the A2DP buffers. Not sure, what is the default Flush timeout value.
Do we have any patch for this issue?
Regards
Suraj
Marcel Holtmann
maintainerRe: buffer starvation with multiple ACL link
Hi Suraj,
please never start a new thread that hangs of an existing thread. I do will miss these and ignore. You need to fix your mailer setup.
Quoted 14 lines
I am seeing a strange issue with multiple ACL connection with CSR chip.
I am having 2 ACL link, one with FTP going on and another streaming A2DP.
The moment the A2DP link goes out of range ,I see that the FTP also stops. It resumes as soon as A2DP comes back in range.On further analysis I could verify that since the A2DP link is blocked( due to remote being OoR) the controller's ACL buffers with A2DP data are stuck.
But at the host level this is not considered and Bluez keeps sending A2DP data until it blocks all the ACL buffers which in turns blocks FTP also.
Quoted 2 lines
I was expecting controller to flush these packets sometime and free the A2DP buffers. Not sure, what is the default Flush timeout value.
We don't have anything as of now that could fix this. I would need more details on this since it might be some outdated firmware or known bug in the controller. Please start a proper new thread with details about the hardware you are using and which software versions.
Regards
Marcel
Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
In reply to surajQuoted 4 lines · Suraj Sumangala
Hi Marcel,
Can you take a look at the patch? Your review has been pending for sometime.
Marcel, new timeline:
----------
02-22-2010 - Marcel responded to your first patch version for UART bluetooth 02-22-2010 - Suarj posted resplies to Marcel's questions 03-01-2010 - Suraj poked Marcel for feedback based on Suraj's comments
----------
03-11-2010 - Suraj posts new V2 patch but its sent busted with tabs/space mixup 03-11-2010 - Marcel asks for a resend
----------
03-14-2010 - Suaraj posts V3 patch with tabs/spaces fixed 03-23-2010 - First poke to Marcel and list
03-29-2010 - Second poke to Marcel and list
03-31-2010 - Patch for userspace hciattach.c changes posted
----------
04-20-2010 - v3 patch posted
04-21-2010 - v4 patch posted
04-22-2010 - v5 patch posted
04-26-2010 - v5 first poke
05-05-2010 - v5 second poke
----------
What else can our team do?
:(
Luis
Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
In reply to surajHi marcel,
Quoted 34 lines · suraj
Hi Marcel,
Can you take a look at the patch? Your review has been pending for sometime.
Quoted 26 lines · suraj
Hi marcel,
Quoted 9 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Reviewed-by Gustavo F. Padovan <[email protected]>Signed-off-by Suraj <[email protected]>Quoted 9 lines
--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cCan you verify the patch let me know your comments?
Regards
Suraj
your review has been pending for a long time. Please let me know what should be done regarding this.
Regards
Suraj
Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
Hi Marcel,
Quoted 38 lines · suraj
Hi marcel,
Quoted 34 lines · suraj
Hi Marcel,
Can you take a look at the patch? Your review has been pending for sometime.
Quoted 26 lines · suraj
Hi marcel,
Quoted 9 lines · suraj
This implements the Atheros Bluetooth serial protocol to support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management features for the AR300x chipsets.Reviewed-by Luis R. Rodriguez <[email protected]>Reviewed-by Gustavo F. Padovan <[email protected]>Signed-off-by Suraj <[email protected]>Quoted 9 lines
--- drivers/bluetooth/Kconfig | 14 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 406 insertions(+), 1 deletions(-) create mode 100755 drivers/bluetooth/hci_ath.cCan you verify the patch let me know your comments?
Regards
Suraj
Quoted 7 lines
your review has been pending for a long time. Please let me know what should be done regarding this.
Regards
Suraj
This patch has been pending your approval/disapproval for so much time that it runs the risk of being obsolete. Please do let me know if you have any plans of doing something about it.
Regards
Suraj
PATCH v3 1/1 hciattach application support for Atheros AR300x Bluetooth Chip
In reply to surajImplements support for Atheros AR300x Bluetooth chip in hciattach. Adds feature to bring up AR300x Bluetooth chip
with and without enhanced power management enabled.
--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 111 +++++ tools/hciattach.h | 3 + tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1344 insertions(+), 0 deletions(-) create mode 100755 tools/hciattach_ar3k.c
Makefile.tools +1 -0
@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ tools/hciattach_st.c \ tools/hciattach_ti.c \ + tools/hciattach_ar3k.c \ tools/hciattach_tialt.c tools_hciattach_LDADD = lib/libbluetooth.la
tools/hciattach.8 +6 -0
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are .B any Unspecified HCI_UART interface, no vendor specific options .TP +.B ar3kalt +Atheros AR300x based serial bluetooth device with power management disabled +.TP +.B ar3k +Atheros AR300x based serial bluetooth device +.TP .B ericsson Ericsson based modules .TP
tools/hciattach.c +111 -0
123 lines not on this page · raw message
tools/hciattach.h +3 -0
@@ -36,6 +36,7 @@#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5int read_hci_event (int fd,unsigned char * buf,int size);int set_speed (int fd,struct termios *ti,int speed);
@@ -45,3 +46,5 @@ int texas_post(int fd, struct termios *ti);int texasalt_init (int fd,int speed,struct termios *ti);int stlc2500_init (int fd,bdaddr_t *bdaddr);int bgb2xx_init (int dd,bdaddr_t *bdaddr); +int ath_configure_sleep (int fd,int sleep_stat); +int ath_ps_download (int fd);
tools/hciattach_ar3k.c new file +1223 -0
1,223 lines not on this page · raw message
Signature · 1 line
1.7.0
Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip
Hi,
Quoted 1,410 lines · suraj
Implements support for Atheros AR300x Bluetooth chip in hciattach. Adds feature to bring up AR300x Bluetooth chip
with and without enhanced power management enabled.Signed-off-by Suraj <[email protected]>--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 111 +++++ tools/hciattach.h | 3 + tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1344 insertions(+), 0 deletions(-) create mode 100755 tools/hciattach_ar3k.cMakefile.tools +1
-0@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ tools/hciattach_st.c \ tools/hciattach_ti.c \ + tools/hciattach_ar3k.c \ tools/hciattach_tialt.c tools_hciattach_LDADD = lib/libbluetooth.latools/hciattach.8 +6
-0@@ -49,6 +49,12 @@ specific identifier. Currently supported types are .B any Unspecified HCI_UART interface, no vendor specific options .TP +.B ar3kalt +Atheros AR300x based serial bluetooth device with power management disabled +.TP +.B ar3k +Atheros AR300x based serial bluetooth device +.TP .B ericsson Ericsson based modules .TPtools/hciattach.c +111
-0@@ -653,6 +653,110 @@ static int csr(int fd, struct uart_t *u, struct termios *ti) }/* +* Atheros AR300x specific initialization post callback +* with power management dsiabled +* Suraj Sumangala <[email protected]> +*/ +static int ar3kpost (int fd,struct uart_t *u,struct termios *ti) +{ +return ath_configure_sleep (fd,0 ); +} + +/* +* Atheros AR300x specific initialization post callback +* with power management enabled +* Suraj Sumangala <[email protected]> +*/ +static int ar3kpmpost (int fd,struct uart_t *u,struct termios *ti) +{ +return ath_configure_sleep (fd,1 ); +} +/* +* Atheros AR300x specific initialization +* Suraj Sumangala <[email protected]> +*/ +static int ar3kinit (int fd,struct uart_t *u,struct termios *ti) +{ +struct timespec tm = {0 ,500000 }; +unsigned char cmd[14 ], rsp[100 ]; +int r; +int baud; + +/* Download PS and patch */ + r =ath_ps_download (fd); + +if (r <0 ) { +perror ("Failed to Download configuration" ); +return -1 ; + } + +/* Write BDADDR if user has provided any */ +if (u->bdaddr !=NULL ) { +/* Set BD_ADDR */ +memset (cmd,0 ,sizeof (cmd)); +memset (rsp,0 ,sizeof (rsp)); + cmd[0 ] =HCI_COMMAND_PKT ; + cmd[1 ] =0x0B ; + cmd[2 ] =0xfc ; + cmd[3 ] =0x0A ; + cmd[4 ] =0x01 ; + cmd[5 ] =0x01 ; + cmd[6 ] =0x00 ; + cmd[7 ] =0x06 ; +str2ba (u->bdaddr, (bdaddr_t *) (cmd +8 )); + +/* Send command */ +if (write (fd, cmd,14 ) !=14 ) { +fprintf (stderr,"Failed to write BD_ADDR command\n" ); +return -1 ; + } + +/* Read reply */ +if (read_hci_event (fd, rsp,10 ) <0 ) { +fprintf (stderr,"Failed to set BD_ADDR\n" ); +return -1 ; + } + } + +/* Send HCI Reset to write the configuration */ + cmd[0 ] =HCI_COMMAND_PKT ; + cmd[1 ] =0x03 ; + cmd[2 ] =0x0C ; + cmd[3 ] =0x00 ; + + r =write (fd, cmd,4 ); + +if (r !=4 ) +return -1 ; + +nanosleep (&tm,NULL ); +if (read_hci_event (fd, rsp,sizeof (rsp)) <0 ) +return -1 ; + +/* Set baud rate command, +* set controller baud rate to user specified value */ + cmd[0 ] =HCI_COMMAND_PKT ; + cmd[1 ] =0x0C ; + cmd[2 ] =0xfc ; + cmd[3 ] =0x02 ; + baud = u->speed/100 ; + cmd[4 ] = (char )baud; + cmd[5 ] = (char )(baud >>8 ); + +if (write (fd, cmd,6 ) !=6 ) { +perror ("Failed to write init command" ); +return -1 ; + } + +/* Wait for the command complete event for Baud rate change Command */ +nanosleep (&tm,NULL ); + +if (read_hci_event (fd, rsp,sizeof (rsp)) <0 ) +return -1 ; + +return 0 ; +} +/* * Silicon Wave specific initialization * Thomas Moser <[email protected]> */ @@ -1071,6 +1175,13 @@ struct uart_t uart[] = {/* Broadcom BCM2035 */ { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 }, +/* ATHEROS AR300x */ + { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200, + FLOW_CTL, NULL, ar3kinit, ar3kpost }, + + { "ar3k", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200, + FLOW_CTL, NULL, ar3kinit, ar3kpmpost }, + { NULL, 0 } };tools/hciattach.h +3
-0@@ -36,6 +36,7 @@#define HCI_UART_3WIRE 2#define HCI_UART_H4DS 3#define HCI_UART_LL 4 +#define HCI_UART_ATH 5int read_hci_event (int fd,unsigned char * buf,int size);int set_speed (int fd,struct termios *ti,int speed);@@ -45,3 +46,5 @@ int texas_post(int fd, struct termios *ti);int texasalt_init (int fd,int speed,struct termios *ti);int stlc2500_init (int fd,bdaddr_t *bdaddr);int bgb2xx_init (int dd,bdaddr_t *bdaddr); +int ath_configure_sleep (int fd,int sleep_stat); +int ath_ps_download (int fd);tools/hciattach_ar3k.c new file +1213
-0@@ -0,0 +1,1223 @@ +/* +* Copyright (c) 2009-2010 Atheros Communications Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> + +#include "hciattach.h" + +/* The maximum number of bytes possible in a patch entry */ +#define MAX_PATCH_SIZE 20000 + +#define MAX_BYTE_LENGTH 244 + +/* Maximum HCI packets that will be formed from the Patch file */ +#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1) + +#define DEV_REGISTER 0x4FFC + +#define FW_PATH "/lib/firmware/ar3k/" + +#define PS_ASIC_FILE "PS_ASIC.pst" +#define PS_FPGA_FILE "PS_FPGA.pst" +#define PATCH_FILE "RamPatch.txt" +#define BDADDR_FILE "ar3kbdaddr.pst" + +#define HCI_CMD_HEADER_LEN 7 + +/* PS command types */ +#define PS_RESET 2 +#define PS_WRITE 1 +#define WRITE_PATCH 8 +#define PS_VERIFY_CRC 9 +#define ENABLE_PATCH 11 + +#define EXTRA_PATCH_SIZE 500 + +/* PS configuration entry time */ +#define PS_TYPE_HEX 0 +#define PS_TYPE_DEC 1 + +#define PS_RESET_PARAM_LEN 6 +#define PS_RESET_CMD_LEN (PS_RESET_PARAM_LEN +\ + HCI_CMD_HEADER_LEN) + +#define RAM_PS_REGION (1<<0) +#define RAM_PATCH_REGION (1<<1) + +#define RAMPS_MAX_PS_TAGS_PER_FILE 50 +#define PS_MAX_LEN 500 +#define LINE_SIZE_MAX (PS_MAX_LEN * 2) + +#define BYTES_OF_PS_DATA_PER_LINE 16 + +#define skip_space (str) while (*(str) == (' ')) ((str)++) + +#define is_between (x, lower, upper) (((lower) <= (x)) && ((x) <= (upper))) + +#define tohexval (c) (isdigit((c)) ? ((c) - '0') : \ + (is_between((c), 'A', 'Z') ? \ + ((c) - 'A' + 10) : ((c) - 'a' + 10))) + +#define stringtohex (str) (((uint8_t)(tohexval((str)[0]) << 4)) |\ + ((uint8_t)tohexval((str)[1]))) + +#define set_pst_format (pst, type, array_val) ((pst)->data_type = (type),\ + (pst)->is_array = (array_val)) + +struct ps_tag_entry { +uint32_t tag_id; +uint32_t tag_len; +uint8_t *tag_data; +}; + +struct ps_ram_patch { +int16_t Len; +uint8_t *Data; +}; + +struct ps_data_format { +unsigned char data_type; +unsigned char is_array; +}; + +struct ps_cmd_packet { +uint8_t *Hcipacket; +int packetLen; +}; + +struct st_read_status { +unsigned section; +unsigned line_count; +unsigned char_cnt; +unsigned byte_count; +}; + +struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE ]; +struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY ]; + +static void load_hci_header (uint8_t *hci_ps_cmd, +uint8_t opcode, +int length, +int index) +{ + hci_ps_cmd[0 ] =0x0B ; + hci_ps_cmd[1 ] =0xFC ; + hci_ps_cmd[2 ] = length +4 ; + hci_ps_cmd[3 ] = opcode; + hci_ps_cmd[4 ] = (index &0xFF ); + hci_ps_cmd[5 ] = ((index >>8 ) &0xFF ); + hci_ps_cmd[6 ] = length; + +} + +/* +*Create PS download commands from parsed data +*/ +static int ath_create_ps_command (uint8_t opcode, +uint32_t param_1, +struct ps_cmd_packet *ps_patch_packet, +uint32_t *index) +{ +uint8_t *hci_ps_cmd; +int i; + +switch (opcode) { + +case WRITE_PATCH : + +for (i =0 ; i < param_1; i++) { + +/* Allocate command buffer */ + hci_ps_cmd = (uint8_t *)malloc (ram_patch[i].Len + +HCI_CMD_HEADER_LEN ); + +if (!hci_ps_cmd) +return -ENOMEM ; + +/* Update commands to buffer */ +load_hci_header (hci_ps_cmd, + opcode, + ram_patch[i].Len, + i); +memcpy (&hci_ps_cmd[HCI_CMD_HEADER_LEN ], + ram_patch[i].Data, + ram_patch[i].Len); + + ps_patch_packet[*index].Hcipacket = hci_ps_cmd; + ps_patch_packet[*index].packetLen = ram_patch[i].Len + +HCI_CMD_HEADER_LEN ; + + (*index)++; + } + +break ; +case ENABLE_PATCH : + + hci_ps_cmd = (uint8_t *)malloc (HCI_CMD_HEADER_LEN ); + +if (!hci_ps_cmd) +return -ENOMEM ; + +load_hci_header (hci_ps_cmd, opcode,0 ,0x00 ); + ps_patch_packet[*index].Hcipacket = hci_ps_cmd; + ps_patch_packet[*index].packetLen =HCI_CMD_HEADER_LEN ; + + (*index)++; + +break ; +case PS_RESET : + + hci_ps_cmd = (uint8_t *)malloc (PS_RESET_CMD_LEN ); + +if (!hci_ps_cmd) +return -ENOMEM ; + +load_hci_header (hci_ps_cmd, opcode,PS_RESET_PARAM_LEN ,0x00 ); + + hci_ps_cmd[7 ] =0x00 ; + hci_ps_cmd[PS_RESET_CMD_LEN -2 ] = (param_1 &0xFF ); + hci_ps_cmd[PS_RESET_CMD_LEN -1 ] = ((param_1 >>8 ) &0xFF ); + + ps_patch_packet[*index].Hcipacket = hci_ps_cmd; + ps_patch_packet[*index].packetLen =PS_RESET_CMD_LEN ; + + (*index)++; + +break ; +case PS_WRITE : + +for (i =0 ; i < param_1; i++) { + + hci_ps_cmd = + (uint8_t *)malloc (ps_tag_entry[i].tag_len + +HCI_CMD_HEADER_LEN ); +if (!hci_ps_cmd) +return -ENOMEM ; + +load_hci_header (hci_ps_cmd, + opcode, + ps_tag_entry[i].tag_len, + ps_tag_entry[i].tag_id); + +memcpy (&hci_ps_cmd[HCI_CMD_HEADER_LEN ], + ps_tag_entry[i].tag_data, + ps_tag_entry[i].tag_len); + + ps_patch_packet[*index].Hcipacket = hci_ps_cmd; + + ps_patch_packet[*index].packetLen = + ps_tag_entry[i].tag_len +HCI_CMD_HEADER_LEN ; + + (*index)++; + } + +break ; +default : +break ; + } + +return 0 ; +} + +static int get_ps_type (char *line, +int eol_index, +unsigned char *type, +unsigned char *sub_type) +{ + +switch (eol_index) { +case 1 : +return 0 ; +case 2 : + (*type) =toupper (line[1 ]); +break ; +case 3 : +if (line[2 ] ==':' ) + (*type) =toupper (line[1 ]); +else if (line[1 ] ==':' ) + (*sub_type) =toupper (line[2 ]); +else +return -1 ; + +break ; +case 4 : +if (line[2 ] !=':' ) +return -1 ; + + (*type) =toupper (line[1 ]); + (*sub_type) =toupper (line[3 ]); + +break ; +case -1 : +return -1 ; + } + +return 0 ; +} + +static int get_input_data_format (char *line,struct ps_data_format *pst_format) +{ +unsigned char type ='\0' ; +unsigned char sub_type ='\0' ; +int eol_index =-1 ; +int i; + +/* The default values */ +set_pst_format (pst_format,PS_TYPE_HEX ,1 ); + +if (line[0 ] !='[' ) { +set_pst_format (pst_format,PS_TYPE_HEX ,1 ); +return 0 ; + } + +for (i =1 ; i <5 ; i++) { +if (line[i] ==']' ) { + eol_index = i; +break ; + } + } + +if (get_ps_type (line, eol_index, &type, &sub_type) <0 ) +return -1 ; + +/* By default Hex array type is assumed */ +if (type =='\0' && sub_type =='\0' ) +set_pst_format (pst_format,PS_TYPE_HEX ,1 ); + +/* Check is data type is of array */ +if (type =='A' || sub_type =='A' ) + pst_format->is_array =1 ; + +if (type =='S' || sub_type =='S' ) + pst_format->is_array =0 ; + +switch (type) { + +case 'D' : +case 'B' : + + pst_format->data_type =PS_TYPE_DEC ; +break ; +default : + + pst_format->data_type =PS_TYPE_HEX ; +break ; + + } + + line += (eol_index +1 ); + +return 0 ; + +} + +static unsigned int read_data_in_section (char *line, +struct ps_data_format format_info) +{ +char *token_ptr = line; + +if (!token_ptr) +return 0x0FFF ; + +if (token_ptr[0 ] =='[' ) { + +while (token_ptr[0 ] !=']' && token_ptr[0 ] !='\0' ) + token_ptr++; + +if (token_ptr[0 ] =='\0' ) +return 0x0FFF ; + + token_ptr++; + } + +if (format_info.data_type ==PS_TYPE_HEX ) { + +if (format_info.is_array ==1 ) +return 0x0FFF ; +else +return strtol (token_ptr,NULL ,16 ); + + }else +return 0x0FFF ; + +return 0x0FFF ; + +} +static int ath_parse_file (FILE *stream) +{ +char *buffer; +char *line; +uint8_t tag_cnt =0 ; +int16_t byte_count =0 ; +int read_count; +int num_ps_entry; +struct ps_data_format stps_data_format; +struct st_read_status read_status = {0 ,0 ,0 ,0 }; + +if (!stream) { +perror ("Could not open config file .\n" ); +return -1 ; + } + + buffer =malloc (LINE_SIZE_MAX +1 ); + +if (!buffer) +return -ENOMEM ; + +do { + line =fgets (buffer,LINE_SIZE_MAX , stream); + +if (!line) +break ; + +skip_space (line); + +if ((line[0 ] =='/' ) && (line[1 ] =='/' )) +continue ; + +if ((line[0 ] =='#' )) { + +if (read_status.section !=0 ) { + +if (buffer) +free (buffer); +return -1 ; + + }else { + read_status.section =1 ; +continue ; + } + } + +if ((line[0 ] =='/' ) && (line[1 ] =='*' )) { + + read_status.section =0 ; +continue ; + } + +if (read_status.section ==1 ) { +skip_space (line); + +if (get_input_data_format ( + line, &stps_data_format) <0 ) { + +if (buffer) +free (buffer); +return -1 ; + + } + + ps_tag_entry[tag_cnt].tag_id =read_data_in_section ( + line, + stps_data_format); + read_status.section =2 ; + + }else if (read_status.section ==2 ) { + +if (get_input_data_format ( + line, &stps_data_format) <0 ) { + +if (buffer) +free (buffer); +return -1 ; + } + + byte_count = +read_data_in_section (line, stps_data_format); + + read_status.section =2 ; +if (byte_count >LINE_SIZE_MAX /2 ) { +if (buffer) +free (buffer); + +return -1 ; + } + + ps_tag_entry[tag_cnt].tag_len = byte_count; + ps_tag_entry[tag_cnt].tag_data = (uint8_t *) +malloc (byte_count); + + read_status.section =3 ; + read_status.line_count =0 ; + + }else if (read_status.section ==3 ) { + +if (read_status.line_count ==0 ) { +if (get_input_data_format ( + line, &stps_data_format) <0 ) { +if (buffer) +free (buffer); +return -1 ; + } + } + +skip_space (line); + read_status.char_cnt =0 ; + +if (line[read_status.char_cnt] =='[' ) { + +while (line[read_status.char_cnt] !=']' && + line[read_status.char_cnt] !='\0' ) + read_status.char_cnt++; + +if (line[read_status.char_cnt] ==']' ) + read_status.char_cnt++; +else + read_status.char_cnt =0 ; + + } + + read_count = (byte_count >BYTES_OF_PS_DATA_PER_LINE ) + ?BYTES_OF_PS_DATA_PER_LINE : byte_count; + +if (stps_data_format.data_type ==PS_TYPE_HEX && + stps_data_format.is_array ==1 ) { + +while (read_count >0 ) { + + ps_tag_entry[tag_cnt].tag_data + [read_status.byte_count] = +stringtohex ( + &line[read_status.char_cnt]); + + ps_tag_entry[tag_cnt].tag_data + [read_status.byte_count +1 ] = +stringtohex ( + &line[read_status.char_cnt +3 ]); + + read_status.char_cnt +=6 ; + read_status.byte_count +=2 ; + read_count -=2 ; + + } + +if (byte_count >BYTES_OF_PS_DATA_PER_LINE ) + byte_count -= +BYTES_OF_PS_DATA_PER_LINE ; +else + byte_count =0 ; + } + + read_status.line_count++; + +if (byte_count ==0 ) { + read_status.section =0 ; + read_status.char_cnt =0 ; + read_status.line_count =0 ; + read_status.byte_count =0 ; + }else + read_status.char_cnt =0 ; + +if (read_status.section ==0 ) { + tag_cnt++; + +if (tag_cnt ==RAMPS_MAX_PS_TAGS_PER_FILE ) { +if (buffer) +free (buffer); +return -1 ; + } + } + + } + + }while (line); + + num_ps_entry = tag_cnt; + +if (tag_cnt >RAMPS_MAX_PS_TAGS_PER_FILE ) { +if (buffer) +free (buffer); +return -1 ; + } + +if (buffer) +free (buffer); + +return num_ps_entry; +} + +static int parse_patch_file (FILE *stream) +{ +char byte[3 ]; +char line[MAX_BYTE_LENGTH +1 ]; +int byte_cnt, byte_cnt_org; +int patch_index; +int i, k; +int data; +int patch_count =0 ; + + byte[2 ] ='\0' ; + +while (fgets (line,MAX_BYTE_LENGTH , stream)) { +if (strlen (line) <=1 || !isxdigit (line[0 ])) +continue ; +else +break ; + } + + byte_cnt =strtol (line,NULL ,16 ); + byte_cnt_org = byte_cnt; + +while (byte_cnt >MAX_BYTE_LENGTH ) { + +/* Handle case when the number of patch buffer is +* more than the 20K */ +if (MAX_NUM_PATCH_ENTRY == patch_count) { +for (i =0 ; i < patch_count; i++) +free (ram_patch[i].Data); +return -ENOMEM ; + } + + ram_patch[patch_count].Len =MAX_BYTE_LENGTH ; + ram_patch[patch_count].Data = + (uint8_t *)malloc (MAX_BYTE_LENGTH ); + +if (!ram_patch[patch_count].Data) +return -ENOMEM ; + + patch_count++; + byte_cnt = byte_cnt -MAX_BYTE_LENGTH ; + } + + ram_patch[patch_count].Len = (byte_cnt &0xFF ); + +if (byte_cnt !=0 ) { + ram_patch[patch_count].Data = (uint8_t *)malloc (byte_cnt); + +if (!ram_patch[patch_count].Data) +return -ENOMEM ; + patch_count++; + } + +while (byte_cnt_org >MAX_BYTE_LENGTH ) { + + k =0 ; +for (i =0 ; i <MAX_BYTE_LENGTH *2 ; i +=2 ) { +if (!fgets (byte,3 , stream)) +return -1 ; + data =strtoul (&byte[0 ],NULL ,16 ); + ram_patch[patch_index].Data[k] = (data &0xFF ); + + k++; + } + + patch_index++; + + byte_cnt_org = byte_cnt_org -MAX_BYTE_LENGTH ; + } + +if (patch_index ==0 ) + patch_index++; + +for (k =0 ; k < byte_cnt_org; k++) { + +if (!fgets (byte,3 , stream)) +return -1 ; + + data =strtoul (byte,NULL ,16 ); + ram_patch[patch_index].Data[k] = (data &0xFF ); + } + +return patch_count; +} + +static int ath_parse_ps (FILE *stream,int *total_tag_len) +{ +int num_ps_tags; +int i; +unsigned char bdaddr_present =0 ; + +if (stream) + num_ps_tags =ath_parse_file (stream); + +if (num_ps_tags <0 ) +return -1 ; + +if (num_ps_tags ==0 ) + *total_tag_len =10 ; +else { + +for (i =0 ; i < num_ps_tags; i++) { + +if (ps_tag_entry[i].tag_id ==1 ) + bdaddr_present =1 ; +if (ps_tag_entry[i].tag_len %2 ==1 ) + *total_tag_len = *total_tag_len + + ps_tag_entry[i].tag_len +1 ; +else + *total_tag_len = + *total_tag_len + ps_tag_entry[i].tag_len; + + } + } + +if (num_ps_tags >0 && !bdaddr_present) + *total_tag_len = *total_tag_len +10 ; + + *total_tag_len = *total_tag_len +10 + (num_ps_tags *4 ); + +return num_ps_tags; +} + +static int ath_create_cmd_list (struct ps_cmd_packet **hci_packet_list, +uint32_t *num_packets, +int tag_count, +int patch_count, +int total_tag_len) +{ +uint8_t count; +uint32_t num_cmd_entry =0 ; + + *num_packets =0 ; + +if (patch_count || tag_count) { + +/* PS Reset Packet + Patch List + PS List */ + num_cmd_entry += (1 + patch_count + tag_count); +if (patch_count >0 ) + num_cmd_entry++;/* Patch Enable Command */ + + (*hci_packet_list) = +malloc (sizeof (struct ps_cmd_packet ) * num_cmd_entry); + +if (!(*hci_packet_list)) +return -ENOMEM ; + +if (patch_count >0 ) { + +if (ath_create_ps_command (WRITE_PATCH , patch_count, + *hci_packet_list, num_packets) <0 ) +return -1 ; +if (ath_create_ps_command (ENABLE_PATCH ,0 , + *hci_packet_list, num_packets) <0 ) +return -1 ; +if (ath_create_ps_command (PS_RESET , + total_tag_len +EXTRA_PATCH_SIZE , + *hci_packet_list, num_packets) <0 ) +return -1 ; + + }else { + +if (ath_create_ps_command (PS_RESET , total_tag_len, + *hci_packet_list, num_packets) <0 ) +return -1 ; + } + +if (tag_count >0 ) +ath_create_ps_command (PS_WRITE , tag_count, + *hci_packet_list, num_packets); + } + +for (count =0 ; count < patch_count; count++) +free (ram_patch[patch_count].Data); + +for (count =0 ; count < tag_count; count++) +free (ps_tag_entry[count].tag_data); + +return *num_packets; +} + +static int ath_free_command_list (struct ps_cmd_packet **hci_packet_list, +uint32_t num_packets) +{ +int i; + +if (!(*hci_packet_list)) +return -1 ; + +for (i =0 ; i < num_packets; i++) +free ((*hci_packet_list)[i].Hcipacket); + +free (*hci_packet_list); + +return 0 ; +} + +/* +* This API is used to send the HCI command to controller and return +* with a HCI Command Complete event. +*/ +static int send_hci_cmd_wait_event (int dev, +uint8_t *hci_command, +int cmd_length, +uint8_t **event,uint8_t **buffer_to_free) +{ +int r; +uint8_t *hci_event; +uint8_t pkt_type =0x01 ; + +if (cmd_length ==0 ) +return -1 ; + +if (write (dev, &pkt_type,1 ) !=1 ) +return -1 ; + +if (write (dev, (unsigned char *)hci_command, cmd_length) != cmd_length) +return -1 ; + + hci_event = (uint8_t *)malloc (100 ); + +if (!hci_event) +return -ENOMEM ; + + r =read_hci_event (dev, (unsigned char *)hci_event,100 ); + +if (r >0 ) { + *event = hci_event; + *buffer_to_free = hci_event; + }else { + +/* Did not get an event from controller. return error */ +free (hci_event); + *buffer_to_free =NULL ; +return -1 ; + } + +return 0 ; +} + +static int read_ps_event (uint8_t *data) +{ + +if (data[5 ] ==0xFC && data[6 ] ==0x00 ) { + +switch (data[4 ]) { + +case 0x0B :/* CRC Check */ +case 0x0C :/* Change Baudrate */ +case 0x04 :/* Enable sleep */ +return 0 ; +break ; +default : +return -1 ; +break ; + + } + } + +return -1 ; +} + +static int get_ps_file_name (int devtype,int rom_version,char *path) +{ +char *filename; +int status =0 ; + +if (devtype ==0xdeadc0de ) { + filename =PS_ASIC_FILE ; + status =1 ; + }else { + filename =PS_FPGA_FILE ; + status =0 ; + } + +sprintf (path,"%s%x/%s" ,FW_PATH , rom_version, filename); + +return status; +} + +static int get_patch_file_name (int dev_type,int rom_version, +int build_version,char *path) +{ + +if ((dev_type !=0 ) && + (dev_type !=0xdeadc0de ) && + (rom_version ==0x99999999 ) && + (build_version ==1 )) + path[0 ] ='\0' ; +else +sprintf (path,"%s%x/%s" ,FW_PATH , rom_version,PATCH_FILE ); + +return 0 ; +} +static int get_ar3k_crc (int dev,int tag_count,int patch_count) +{ +uint8_t hci_cmd[7 ]; +uint8_t *event; +uint8_t *buffer_to_free =NULL ; +int retval =1 ; +int crc; + +if (patch_count >0 ) + crc |=RAM_PATCH_REGION ; +if (tag_count >0 ) + crc |=RAM_PS_REGION ; + +load_hci_header (hci_cmd,PS_VERIFY_CRC ,0 , crc); + +if (send_hci_cmd_wait_event (dev, + hci_cmd, +sizeof (hci_cmd), + &event, + &buffer_to_free) ==0 ) { + +if (read_ps_event (event) ==0 ) + retval =-1 ; + +if (buffer_to_free !=NULL ) +free (buffer_to_free); + } + +return retval; +} +static int get_device_type (int dev,uint32_t *code) +{ +uint8_t hci_cmd[] = {0x05 ,0xfc ,0x05 ,0x00 ,0x00 ,0x00 ,0x00 ,0x04 }; +uint8_t *event; +uint8_t *buffer_to_free =NULL ; +uint32_t reg; +int result =-1 ; + + *code =0 ; + + hci_cmd[3 ] = (uint8_t ) (DEV_REGISTER &0xFF ); + hci_cmd[4 ] = (uint8_t ) ((DEV_REGISTER >>8 ) &0xFF ); + hci_cmd[5 ] = (uint8_t ) ((DEV_REGISTER >>16 ) &0xFF ); + hci_cmd[6 ] = (uint8_t ) ((DEV_REGISTER >>24 ) &0xFF ); + +if (send_hci_cmd_wait_event (dev, + hci_cmd, +sizeof (hci_cmd), + &event, + &buffer_to_free) ==0 ) { + +if (event[5 ] ==0xFC && event[6 ] ==0x00 ) { + +switch (event[4 ]) { +case 0x05 : + reg = event[10 ]; + reg = ((reg <<8 ) | event[9 ]); + reg = ((reg <<8 ) | event[8 ]); + reg = ((reg <<8 ) | event[7 ]); + *code = reg; + result =0 ; + +break ; + +case 0x06 : +break ; + } + } + } + +if (buffer_to_free) +free (buffer_to_free); + +return result; +} + +static int read_ar3k_version (int pConfig,int *rom_version,int *build_version) +{ +uint8_t hci_cmd[] = {0x1E ,0xfc ,0x00 }; +uint8_t *event; +uint8_t *buffer_to_free =NULL ; +int result =-1 ; + +if (send_hci_cmd_wait_event (pConfig, + hci_cmd, +sizeof (hci_cmd), + &event, + &buffer_to_free) ==0 ) { + +if (event[5 ] ==0xFC && + event[6 ] ==0x00 && + event[4 ] ==0x1E ) { + + (*rom_version) = event[10 ]; + (*rom_version) = (((*rom_version) <<8 ) | event[9 ]); + (*rom_version) = (((*rom_version) <<8 ) | event[8 ]); + (*rom_version) = (((*rom_version) <<8 ) | event[7 ]); + + (*build_version) = event[14 ]; + (*build_version) = (((*build_version) <<8 ) | + event[13 ]); + (*build_version) = (((*build_version) <<8 ) | + event[12 ]); + (*build_version) = (((*build_version) <<8 ) | + event[11 ]); + + result =1 ; + + } + +if (buffer_to_free) +free (buffer_to_free); + } + +return result; +} + +static int str2bdaddr (char *str_bdaddr,char *bdaddr) +{ +char bdbyte[3 ]; +char *str_byte = str_bdaddr; +int i, j; +unsigned char colon_present =0 ; + +if (strstr (str_bdaddr,":" )) + colon_present =1 ; + + bdbyte[2 ] ='\0' ; + +for (i =0 , j =5 ; i <6 ; i++, j--) { + + bdbyte[0 ] = str_byte[0 ]; + bdbyte[1 ] = str_byte[1 ]; + bdaddr[j] =strtol (bdbyte,NULL ,16 ); + +if (colon_present ==1 ) + str_byte +=3 ; +else + str_byte +=2 ; + } +return 0 ; +} + +static int write_bdaddr (int pConfig,char *bdaddr) +{ +uint8_t bdaddr_cmd[] = {0x0B ,0xFC ,0x0A , +0x01 ,0x01 ,0x00 , +0x06 ,0x00 ,0x00 , +0x00 ,0x00 ,0x00 , +0x00 }; +uint8_t *event; +uint8_t *buffer_to_free =NULL ; +int result =-1 ; + +str2bdaddr (bdaddr, (char *)&bdaddr_cmd[7 ]); + +if (send_hci_cmd_wait_event (pConfig, + bdaddr_cmd, +sizeof (bdaddr_cmd), + &event, + &buffer_to_free) ==0 ) { + +if (event[5 ] ==0xFC && event[6 ] ==0x00 ) { +if (event[4 ] ==0x0B ) + result =0 ; + } + + } + +if (buffer_to_free) +free (buffer_to_free); + +return result; +} + +int ath_configure_sleep (int fd,int sleep_stat) +{ +int dev_id, dd; +struct timespec tm = {0 ,50000 }; + + dev_id =ioctl (fd,HCIUARTGETDEVICE ,0 ); + +if (dev_id <0 ) { +perror ("cannot get device id" ); +return -1 ; + } + + dd =hci_open_dev (dev_id); + +if (dd <0 ) { +perror ("HCI device open failed" ); +return -1 ; + } + +sleep (2 ); + +/* send vendor specific command with Sleep feature Enabled */ +if (hci_send_cmd (dd,OGF_VENDOR_CMD ,0x04 ,1 , &sleep_stat) <0 ) +perror ("Power management Disabled" ); + +nanosleep (&tm,NULL ); +hci_close_dev (dd); + +return 0 ; +} + +int ath_ps_download (int hdev) +{ +int i; +int status =0 ; +int tag_count; +int patch_count; +int total_tag_len =0 ; +int rom_version =0 , build_version =0 ; + +struct ps_cmd_packet *hci_cmd_list;/* List storing the commands */ +uint32_t num_cmds; +uint8_t *event; +uint8_t *buffer_to_free; +uint32_t dev_type; + +char patch_file[PATH_MAX ]; +char ps_file[PATH_MAX ]; +char bdaddr_file[PATH_MAX ]; + +FILE *stream; +char bdaddr[21 ]; + + hci_cmd_list =NULL ; + +/* +* Verfiy firmware version. depending on it select the PS +* config file to download. +*/ +if (get_device_type (hdev, &dev_type) ==-1 ) { + status =-1 ; + goto download_cmplete; + } +if (read_ar3k_version (hdev, &rom_version, &build_version) ==-1 ) { + status =-1 ; + goto download_cmplete; + } + +get_ps_file_name (dev_type, rom_version, ps_file); + +get_patch_file_name (dev_type, rom_version, build_version, patch_file); + +/* Read the PS file to a dynamically allocated buffer */ + stream =fopen (ps_file,"r" ); + +if (!stream) { +perror ("firmware file open error\n" ); + status =-1 ; + goto download_cmplete; + } + + tag_count =ath_parse_ps (stream, &total_tag_len); + +fclose (stream); + +if (tag_count ==-1 ) { + status =-1 ; + goto download_cmplete; + } + +/* +* It is not necessary that Patch file be available, +* continue with PS Operations if. +* failed. +*/ +if (patch_file[0 ] =='\0' ) + status =0 ; + + stream =fopen (patch_file,"r" ); + +if (!stream) { + patch_count =0 ; + status =0 ; + }else { +/* parse and store the Patch file contents to +* a global variables +*/ + patch_count =parse_patch_file (stream); + +fclose (stream); + +if (patch_count <0 ) { + status =-1 ; + goto download_cmplete; + } + } + +/* +* Send the CRC packet, +* Continue with the PS operations +* only if the CRC check failed +*/ +if (get_ar3k_crc (hdev, tag_count, patch_count) <0 ) { + status =0 ; + goto download_cmplete; + } + +/* Create an HCI command list +* from the parsed PS and patch information +*/ +ath_create_cmd_list (&hci_cmd_list, + &num_cmds, + tag_count, + patch_count, + total_tag_len); + +for (i =0 ; i < num_cmds; i++) { + +if (send_hci_cmd_wait_event + (hdev, + hci_cmd_list[i].Hcipacket, + hci_cmd_list[i].packetLen, + &event, + &buffer_to_free) ==0 ) { + +if (read_ps_event (event) <0 ) { + +/* Exit if the status is not success */ +if (buffer_to_free) +free (buffer_to_free); + + status =-1 ; + goto download_cmplete; + } +if (buffer_to_free) +free (buffer_to_free); + }else { + status =0 ; + goto download_cmplete; + } + } +/* Read the PS file to a dynamically allocated buffer */ +sprintf (bdaddr_file,"%s%x/%s" ,FW_PATH , rom_version,BDADDR_FILE ); + + stream =fopen (bdaddr_file,"r" ); + +if (!stream) { + status =0 ; + goto download_cmplete; + } + +if (fgets (bdaddr,20 , stream)) + status =write_bdaddr (hdev, bdaddr);
tools/hciattach_ar3k.c line 1223
Quoted 10 lines
tools/hciattach_ar3k.c new file +10
-0+ +fclose (stream); + +download_cmplete: + +if (hci_cmd_list) +ath_free_command_list (&hci_cmd_list, num_cmds); + +return status; +}
Please spend some time to verify the patch so that I can take it to the next level.
Regards
Suraj
Marcel Holtmann
maintainerRe: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip
In reply to surajHi Suraj,
Quoted 5 lines
Implements support for Atheros AR300x Bluetooth chip in hciattach. Adds feature to bring up AR300x Bluetooth chip
with and without enhanced power management enabled.Signed-off-by Suraj <[email protected]>
not SOBs for BlueZ userspace. That is kernel only.
Quoted 8 lines
--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 111 +++++ tools/hciattach.h | 3 + tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1344 insertions(+), 0 deletions(-) create mode 100755 tools/hciattach_ar3k.c
While hciattach is kinda the bad sheep inside BlueZ, I will enforce the general coding style for it for all new contributions. So could you please fix that one first. Otherwise it makes no sense for me to go through such a big patch if I have to complain about the coding style breakage for every second line. A general rule is if it fails check-patch.pl from the kernel, then you are doing something wrong.
Regards
Marcel
Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip
Hi Marcel,
Quoted 25 lines · Marcel Holtmann
Hi Suraj,
Quoted 4 lines
Implements support for Atheros AR300x Bluetooth chip in hciattach. Adds feature to bring up AR300x Bluetooth chip with and without enhanced power management enabled.
Signed-off-by Suraj <[email protected]>not SOBs for BlueZ userspace. That is kernel only.
Quoted 8 lines
--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 111 +++++ tools/hciattach.h | 3 + tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1344 insertions(+), 0 deletions(-) create mode 100755 tools/hciattach_ar3k.cWhile hciattach is kinda the bad sheep inside BlueZ, I will enforce the general coding style for it for all new contributions. So could you please fix that one first. Otherwise it makes no sense for me to go through such a big patch if I have to complain about the coding style breakage for every second line. A general rule is if it fails check-patch.pl from the kernel, then you are doing something wrong.
Quoted 5 lines
Regards
Marcel
I had verified this patch using checkpatch and it did not complain. I had also verified it manually according to the comments others have given previously for different patches.
If you still see issues, then we can add that check too to checkpatch if possible.
Being a big patch, there are bound to be problems.But I would appreciate if you could review atleast part of it and give your comments. I can do the changes for the full patch.
Also I would request others in the community to pitch in.
Regards
Suraj
Marcel Holtmann
maintainerRe: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip
Hi Suraj,
Quoted 24 lines
Quoted 17 lines
Quoted 5 lines
Implements support for Atheros AR300x Bluetooth chip in hciattach. Adds feature to bring up AR300x Bluetooth chip
with and without enhanced power management enabled.Signed-off-by Suraj <[email protected]>not SOBs for BlueZ userspace. That is kernel only.
Quoted 8 lines
--- Makefile.tools | 1 + tools/hciattach.8 | 6 + tools/hciattach.c | 111 +++++ tools/hciattach.h | 3 + tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1344 insertions(+), 0 deletions(-) create mode 100755 tools/hciattach_ar3k.cQuoted 6 lines
While hciattach is kinda the bad sheep inside BlueZ, I will enforce the general coding style for it for all new contributions. So could you please fix that one first. Otherwise it makes no sense for me to go through such a big patch if I have to complain about the coding style breakage for every second line. A general rule is if it fails check-patch.pl from the kernel, then you are doing something wrong.
Quoted 6 lines
I had verified this patch using checkpatch and it did not complain. I had also verified it manually according to the comments others have given previously for different patches.
If you still see issues, then we can add that check too to checkpatch if possible.
then maybe checkpatch.pl is not good enough for this. I see way too many empty lines, weird if breakages, and many more. So as I said, this needs cleanup first.
Regards
Marcel
Marcel Holtmann
maintainerRe: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip
In reply to surajHi Suraj,
for every new patch version, please start a new thread. If you re-use an old thread, I will most likely ignore it.
Quoted 15 lines
drivers/bluetooth/hci_ath.c new file +15
-0+static struct sk_buff *ath_dequeue (struct hci_uart *hu) +{ +struct ath_struct *ath = hu->priv; +struct sk_buff *skbuf; + + skbuf =skb_dequeue (&ath->txq); + +if (!skbuf) +return NULL ; + +/* +* Check if the HCI command is HCI sleep enable and +* update the sleep enable flag with command parameter. +* +* Value of sleep enable flag will be used later
drivers/bluetooth/hci_ath.c line 222
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+* to verify if controller has to be woken up before +* sending any packet. +*/ +if (skbuf->data[0 ] ==0x01 && + skbuf->data[1 ] ==0x04 && + skbuf->data[2 ] ==0xFC ) + ath->cur_sleep = skbuf->data[4 ]; + +return skbuf; +}
I don't really like this. I know we don't have any infrastructure to forward vendor commands back to the driver. And we might need to change that actually.
However at least for now use the headers and constants and not magic numbers here.
Quoted 118 lines
drivers/bluetooth/hci_ath.c new file +118
-0+static void ath_check_data_len (struct ath_struct *ath,int len) +{ +int room =skb_tailroom (ath->rx_skb); + +BT_DBG ("len %d room %d" , len, room); + +if (len > room) { +BT_ERR ("Data length is too large" ); +kfree_skb (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; + }else { + ath->rx_state =HCIATH_W4_DATA ; + ath->rx_count = len; + } +} + +/* Recv data */ +static int ath_recv (struct hci_uart *hu,void *data,int count) +{ +struct ath_struct *ath = hu->priv; +char *ptr = data; +struct hci_event_hdr *eh; +struct hci_acl_hdr *ah; +struct hci_sco_hdr *sh; +int len, type, dlen; + +BT_DBG ("hu %p count %d rx_state %d rx_count %d" , hu, count, + ath->rx_state, ath->rx_count); + +while (count) { +if (ath->rx_count) { + + len = min_t(unsigned int, ath->rx_count, count); +memcpy (skb_put (ath->rx_skb, len), ptr, len); + ath->rx_count -= len; + count -= len; + ptr += len; + +if (ath->rx_count) +continue ; +switch (ath->rx_state) { +case HCIATH_W4_DATA : +hci_recv_frame (ath->rx_skb); + ath->rx_state =HCIATH_W4_PACKET_TYPE ; + ath->rx_skb =NULL ; + ath->rx_count =0 ; +continue ; + +case HCIATH_W4_EVENT_HDR : + eh =hci_event_hdr (ath->rx_skb); + +BT_DBG ("Event header: evt 0x%2.2x plen %d" , + eh->evt, eh->plen); + +ath_check_data_len (ath, eh->plen); +continue ; + +case HCIATH_W4_ACL_HDR : + ah =hci_acl_hdr (ath->rx_skb); + dlen =__le16_to_cpu (ah->dlen); + +BT_DBG ("ACL header: dlen %d" , dlen); + +ath_check_data_len (ath, dlen); +continue ; + +case HCIATH_W4_SCO_HDR : + sh =hci_sco_hdr (ath->rx_skb); + +BT_DBG ("SCO header: dlen %d" , sh->dlen); + +ath_check_data_len (ath, sh->dlen); +continue ; + + } + } + +/* HCIATH_W4_PACKET_TYPE */ +switch (*ptr) { +case HCI_EVENT_PKT : +BT_DBG ("Event packet" ); + ath->rx_state =HCIATH_W4_EVENT_HDR ; + ath->rx_count =HCI_EVENT_HDR_SIZE ; + type =HCI_EVENT_PKT ; +break ; + +case HCI_ACLDATA_PKT : +BT_DBG ("ACL packet" ); + ath->rx_state =HCIATH_W4_ACL_HDR ; + ath->rx_count =HCI_ACL_HDR_SIZE ; + type =HCI_ACLDATA_PKT ; +break ; + +case HCI_SCODATA_PKT : +BT_DBG ("SCO packet" ); + ath->rx_state =HCIATH_W4_SCO_HDR ; + ath->rx_count =HCI_SCO_HDR_SIZE ; + type =HCI_SCODATA_PKT ; +break ; + +default : +BT_ERR ("Unknown HCI packet type %2.2x" , (__u8) *ptr); + hu->hdev->stat.err_rx++; + ptr++; + count--; +continue ; + + }; + ptr++; + count--; + +/* Allocate packet */ + ath->rx_skb =bt_skb_alloc (HCI_MAX_FRAME_SIZE ,GFP_ATOMIC ); +if (!ath->rx_skb) { +BT_ERR ("Can't allocate mem for new packet" ); + ath->rx_state =HCIATH_W4_PACKET_TYPE ;
drivers/bluetooth/hci_ath.c line 351
Quoted 10 lines
drivers/bluetooth/hci_ath.c new file +10
-0+ ath->rx_count =0 ; + +return -ENOMEM ; + } + ath->rx_skb->dev = (void *)hu->hdev; +bt_cb (ath->rx_skb)->pkt_type = type; + } + +return count; +}
What was the reason that hci_recv_fragment is not good enough here and can not made work for this case. I really wanna avoid have multiple implementation of this reassembly support all over the places.
Regards
Marcel