Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] Added support for Atheros AR300x UART Bluetooth Chip
From: Vikram Kandukuri @ 2010-02-17  9:55 UTC (permalink / raw)
  To: linux-bluetooth@vger.kernel.org; +Cc: marcel
In-Reply-To: <20100209114231.GA6587@ATH-LT-538>

Hi Marcel,
Please send your comments

Thanks

> 
>  Signed-off-by: Suraj <suraj@atheros.com>
> 
> ---
>  drivers/bluetooth/Kconfig     |   10 +
>  drivers/bluetooth/Makefile    |    1 +
>  drivers/bluetooth/hci_ath.c   |  545 +++++++++++++++++++++++++++++++++++++++++
>  drivers/bluetooth/hci_ath.h   |   72 ++++++
>  drivers/bluetooth/hci_ldisc.c |    6 +
>  drivers/bluetooth/hci_uart.h  |    8 +-
>  6 files changed, 641 insertions(+), 1 deletions(-)
>  create mode 100755 drivers/bluetooth/hci_ath.c
>  create mode 100755 drivers/bluetooth/hci_ath.h
> 
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..32b98a4 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,16 @@ config BT_HCIUART_BCSP
> 
>           Say Y here to compile support for HCI BCSP protocol.
> 
> +config BT_HCIUART_ATH
> +       bool "Atheros AR3001 Board support"
> +       depends on BT_HCIUART
> +       help
> +         HCIATH (HCI Atheros) is a serial protocol for communication
> +         between Bluetooth device and host. This protocol is required for
> +         serial Bluetooth devices that are based on Atheros AR3001 chips.
> +
> +         Say Y here to compile support for HCIATH protocol.
> +
>  config BT_HCIUART_LL
>         bool "HCILL protocol support"
>         depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -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)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..abacc09
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,545 @@
> +/*
> + * 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/sched.h>
> +#include <linux/types.h>
> +#include <linux/fcntl.h>
> +#include <linux/interrupt.h>
> +#include <linux/ptrace.h>
> +#include <linux/poll.h>
> +
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/signal.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +#include <linux/firmware.h>
> +#include <linux/wait.h>
> +#include <linux/timer.h>
> +#include <linux/tty.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci.h>
> +
> +#include "hci_uart.h"
> +#include "hci_ath.h"
> +static void ath_context_switch(struct work_struct *work)
> +{
> +       int status;
> +       struct ath_struct *ath;
> +       struct hci_uart *hu;
> +       struct tty_struct *tty;
> +       struct sk_buff *skbuf;
> +       ath = container_of(work, struct ath_struct, ctxtsw);
> +       hu = ath->hu;
> +       tty = hu->tty;
> +       status = ath_wakeup_ar3001(tty);
> +       if ((status & TIOCM_CTS)) {
> +               while ((skbuf = skb_dequeue(&ath->tx_wait_q)))
> +                       skb_queue_tail(&ath->txq, skbuf);
> +
> +               /* 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);
> +       skb_queue_head_init(&ath->tx_wait_q);
> +       skb_queue_head_init(&ath->tx_cmd_wait_q);
> +       spin_lock_init(&ath->hciath_lock);
> +       ath->cur_sleep = 0;
> +       ath->num_cmds_complete = 1;
> +       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->tx_wait_q);
> +       skb_queue_purge(&ath->txq);
> +       skb_queue_purge(&ath->tx_cmd_wait_q);
> +       return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> +       struct ath_struct *ath;
> +       ath = hu->priv;
> +       BT_DBG("hu %p", hu);
> +       skb_queue_purge(&ath->tx_wait_q);
> +       skb_queue_purge(&ath->txq);
> +       skb_queue_purge(&ath->tx_cmd_wait_q);
> +       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 (padding, crc, etc) */
> +/* may be called from two simultaneous tasklets */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> +       struct ath_struct *ath;
> +       ath = hu->priv;
> +       if (HCI_SCODATA_PKT == bt_cb(skb)->pkt_type) {
> +
> +               /* Discard SCO packet as 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);
> +       if (ath->num_cmds_complete <= 0
> +           && HCI_COMMAND_PKT == bt_cb(skb)->pkt_type) {
> +               skb_queue_tail(&ath->tx_cmd_wait_q, skb);
> +               return 0;
> +       }
> +
> +       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;
> +       struct sk_buff *skbuff;
> +       ath = hu->priv;
> +       skbuff = skb_dequeue(&ath->txq);
> +       if (NULL != skbuff) {
> +               ath_handle_host_data(ath, bt_cb(skbuff)->pkt_type,
> +                                    &skbuff->data[1], skbuff->len - 1);
> +       }
> +       return skbuff;
> +}
> +
> +static inline int ath_check_data_len(struct ath_struct *ath, int len)
> +{
> +       register int room = skb_tailroom(ath->rx_skb);
> +       BT_DBG("len %d room %d", len, room);
> +       if (!len) {
> +               hci_recv_frame(ath->rx_skb);
> +       } else if (len > room) {
> +               BT_ERR("Data length is too large");
> +               kfree_skb(ath->rx_skb);
> +       } else {
> +               ath->rx_state = HCIATH_W4_DATA;
> +               ath->rx_count = len;
> +               return len;
> +       }
> +       ath->rx_state = HCIATH_W4_PACKET_TYPE;
> +       ath->rx_skb = NULL;
> +       ath->rx_count = 0;
> +       return 0;
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> +       struct ath_struct *ath = hu->priv;
> +       register char *ptr;
> +       struct hci_event_hdr *eh;
> +       struct hci_acl_hdr *ah;
> +       struct hci_sco_hdr *sh;
> +       struct sk_buff *skbuff;
> +       register int len, type, dlen;
> +       skbuff = 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:
> +                               ath_handle_data_from_controller(ath,
> +                                                               bt_cb
> +                                                               (ath->rx_skb)->
> +                                                               pkt_type,
> +                                                               ath->rx_skb->
> +                                                               data,
> +                                                               ath->rx_skb->
> +                                                               len);
> +                               if (HCI_EVENT_PKT ==
> +                                   bt_cb(ath->rx_skb)->pkt_type
> +                                   && ath->num_cmds_complete > 0) {
> +
> +                                       skbuff =
> +                                           skb_dequeue(&ath->tx_cmd_wait_q);
> +                                       if (skbuff != NULL) {
> +                                               skb_queue_tail(&ath->txq,
> +                                                              skbuff);
> +                                               schedule_work(&ath->ctxtsw);
> +                                       }
> +                               }
> +                               if (ath_verify_event_discardable
> +                                   (hu, bt_cb(ath->rx_skb)->pkt_type,
> +                                    ath->rx_skb->data)) {
> +                                       kfree(ath->rx_skb);
> +                                       ath->rx_skb = NULL;
> +                               } else {
> +                                       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 0;
> +               }
> +               ath->rx_skb->dev = (void *)hu->hdev;
> +               bt_cb(ath->rx_skb)->pkt_type = type;
> +       } return count;
> +}
> +
> +static void ath_controller_sleep_mode(struct hci_uart *hu, bool enable)
> +{
> +       unsigned char sleepcmd[] = { 0x01, 0x04, 0xFC, 0x01, 0x00 };
> +       sleepcmd[4] = enable;
> +       ath_write_data_to_cntrlr(hu->hdev, sleepcmd, sizeof(sleepcmd));
> +}
> +
> +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);
> +
> +       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;
> +}
> +
> +int ath_fullboot_config(struct hci_uart *hu, int current_event)
> +{
> +       struct sk_buff *skbuf;
> +       struct ath_struct *ath = hu->priv;
> +       static int autosleep;
> +       unsigned char rstevt[] = { 0x1, 0x3, 0xc, 0x0 };
> +       if (current_event == HCI_RESET) {
> +
> +               if (ath->cur_sleep) {
> +                       autosleep = 1;
> +                       ath_controller_sleep_mode(hu, 1);
> +                       return 1;
> +               } else {
> +                       return 0;
> +               }
> +       }
> +
> +       if (current_event == HCI_SET_SLEEP_MODE) {
> +
> +               if (autosleep == 0)
> +                       return 1;
> +
> +               while ((skbuf = skb_dequeue(&ath->tx_wait_q)))
> +                       skb_queue_tail(&ath->txq, skbuf);
> +
> +               ath_write_data_to_host(hu->hdev, rstevt, sizeof(rstevt));
> +               autosleep = 0;
> +               return 1;
> +       }
> +       return 0;
> +}
> +
> +int ath_write_data_to_host(void *dev, unsigned char *data, u8 length)
> +{
> +       struct sk_buff *skbuf;
> +       struct hci_dev *hdev;
> +       hdev = (struct hci_dev *)dev;
> +       skbuf = bt_skb_alloc(length, GFP_ATOMIC);
> +       if (!skbuf) {
> +               BT_ERR("Memory allocation failed");
> +               return -1;
> +       }
> +       skb_orphan(skbuf);
> +
> +       /* First byte will be added as packet type */
> +       bt_cb(skbuf)->pkt_type = data[0];
> +       skbuf->dev = (void *)hdev;
> +       memcpy(skb_put(skbuf, length - 1), &data[1], length - 1);
> +       hci_recv_frame(skbuf);
> +       return length;
> +}
> +
> +int ath_write_data_to_cntrlr(void *dev, unsigned char *Data, u8 len)
> +{
> +       struct sk_buff *skbuff;
> +       struct ath_struct *ath;
> +       struct hci_uart *hu;
> +       struct hci_dev *hdev;
> +       if (NULL == dev) {
> +               BT_DBG("NULL handle received %p  \n", dev);
> +               return 0;
> +       }
> +       hdev = (struct hci_dev *)dev;
> +       hu = (struct hci_uart *)hdev->driver_data;
> +       if (hu == NULL) {
> +               BT_DBG("NULL handle received %p  \n", hdev);
> +               return 0;
> +       }
> +       ath = hu->priv;
> +       if (ath == NULL) {
> +               BT_DBG("NULL handle received  \n");
> +               return 0;
> +       }
> +       skbuff = bt_skb_alloc(len, GFP_ATOMIC);
> +       if (skbuff == NULL) {
> +               BT_DBG("Malloc Fail memory %p   \n", skbuff);
> +               return 0;
> +       }
> +       skb_orphan(skbuff);
> +
> +       if (len != 0)
> +               memcpy(skb_put(skbuff, len), Data, len);
> +
> +       bt_cb(skbuff)->pkt_type = HCI_COMMAND_PKT;
> +       skbuff->dev = dev;
> +       if (ath->num_cmds_complete > 0) {
> +               skb_queue_tail(&ath->txq, skbuff);
> +               schedule_work(&ath->ctxtsw);
> +       } else {
> +               skb_queue_tail(&ath->tx_cmd_wait_q, skbuff);
> +       }
> +       return len;
> +}
> +
> +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
> +{
> +       if (packet[0] == HCI_EVENT_PKT && packet[1] == 0xFC)
> +               ath->cur_sleep = packet[3];
> +
> +       return 0;
> +}
> +
> +int ath_verify_event_discardable(struct hci_uart *hu, unsigned char pkt_type,
> +                                unsigned char *packet)
> +{
> +       if (pkt_type != HCI_EVENT_PKT)
> +               return 0;
> +
> +       switch (packet[0]) {
> +       case 0x0E:              /* Command Complete Event */
> +               if (packet[3] == 0x03 && packet[4] == 0x0C) {
> +
> +                       /* Command complete for HCI Reset Received */
> +                       return ath_fullboot_config(hu, HCI_RESET);
> +               } else if (packet[3] == 0x04 && packet[4] == 0xFC) {
> +                       return ath_fullboot_config(hu, HCI_SET_SLEEP_MODE);
> +               }
> +               break;
> +       }
> +       return 0;
> +}
> +
> +/* Update the number of commands that can be sent to controller */
> +void ath_handle_hci_cmd(struct ath_struct *ath, u8 * packet)
> +{
> +       spin_lock(&ath->hciath_lock);
> +       ath->num_cmds_complete--;
> +       spin_unlock(&ath->hciath_lock);
> +}
> +
> +void ath_handle_hci_event(struct ath_struct *ath, u8 * packet)
> +{
> +       switch (packet[0]) {
> +       case 0x05:              /* ACL Disconnection Complete Event */
> +               break;
> +       case 0x03:              /* ACL Connection Complete Event */
> +               break;
> +       case 0x0E:              /* Command Complete Event */
> +               spin_lock(&ath->hciath_lock);
> +               ath->num_cmds_complete = packet[2];
> +               spin_unlock(&ath->hciath_lock);
> +               break;
> +       case 0x0F:              /* Command Status Event */
> +               spin_lock(&ath->hciath_lock);
> +               ath->num_cmds_complete = packet[3];
> +               spin_unlock(&ath->hciath_lock);
> +               break;
> +       }
> +}
> +
> +void ath_handle_host_data(struct ath_struct *ath, u8 pktType, u8 * packet,
> +                         unsigned int len)
> +{
> +       switch (pktType) {
> +       case HCI_ACLDATA_PKT:   /* ACL packets */
> +               break;
> +       case HCI_COMMAND_PKT:   /* HCI Commands */
> +               ath_handle_hci_cmd(ath, packet);
> +               ath_check_sleep_cmd(ath, packet);
> +               break;
> +       }
> +}
> +
> +void ath_handle_data_from_controller(struct ath_struct *ath, u8 pktType,
> +                                    u8 *packet, unsigned int len)
> +{
> +       switch (pktType) {
> +       case HCI_ACLDATA_PKT:   /* ACL packets */
> +               break;
> +       case HCI_EVENT_PKT:     /* HCI Events */
> +               ath_handle_hci_event(ath, packet);
> +               break;
> +       }
> +}
> +
> +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);
> +}
> diff --git a/drivers/bluetooth/hci_ath.h b/drivers/bluetooth/hci_ath.h
> new file mode 100755
> index 0000000..7513a89
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.h
> @@ -0,0 +1,72 @@
> +/*
> + * 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
> + *
> + */
> +
> +#ifndef __HCI_ATH_H_
> +#define __HCI_ATH_H_
> +
> +#include <linux/fs.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/signal.h>
> +#include <linux/timer.h>
> +
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +#include <linux/firmware.h>
> +#include <linux/wait.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.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
> +
> +#define HCI_SET_SLEEP_MODE                     0xFC04
> +#define HCI_RESET                                      0x030C
> +    struct ath_struct {
> +       struct hci_uart *hu;
> +       unsigned int rx_state;
> +       unsigned int rx_count;
> +       unsigned int cur_sleep;
> +       int num_cmds_complete;
> +       spinlock_t hciath_lock;
> +       struct sk_buff *rx_skb;
> +       struct sk_buff_head txq;
> +       struct sk_buff_head tx_wait_q;
> +       struct sk_buff_head tx_cmd_wait_q;
> +       wait_queue_head_t wqevt;
> +       struct work_struct ctxtsw;
> +};
> +int ath_write_data_to_cntrlr(void *dev, unsigned char *Data, u8 len);
> +int ath_write_data_to_host(void *dev, unsigned char *data, u8 length);
> +int ath_wakeup_ar3001(struct tty_struct *tty);
> +int ath_verify_event_discardable(struct hci_uart *hu, unsigned char pkt_type,
> +                                unsigned char *packet);
> +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet);
> +void ath_handle_host_data(struct ath_struct *ath, u8 pktType, u8 *packet,
> +                         unsigned int len);
> +void ath_handle_data_from_controller(struct ath_struct *ath, u8 pktType,
> +                                    u8 *packet, unsigned int len);
> +
> +
> +#endif /* __HCI_ATH_H_ */
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index aa09193..bd16130 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -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)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -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   5
> 
>  struct 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.6.3.3
> 

^ permalink raw reply

* [PATCH] Fix possible crash while verifying avdtp version
From: Luiz Augusto von Dentz @ 2010-02-17  9:39 UTC (permalink / raw)
  To: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 340 bytes --]

Hi,

Codenomicon a2dp tests makes bluetoothd to crash due to a malformed
sdp record (BlueZ 4.60):

Signal 11 (SIGSEGV)
0		avdtp_get_internal () at audio/avdtp.c:2073
1	0x00022f18	avdtp_confirm_cb (chan=0x6c0e0) at audio/avdtp.c:2266
2	0x0003a7dc	server_cb (user_data=0x6d380) at src/btio.c:193

-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0001-Fix-possible-crash-while-verifying-avdtp-version.patch --]
[-- Type: text/x-patch, Size: 824 bytes --]

From 9fa60aa616ed1e6c7278f0cb265c881c80e628f3 Mon Sep 17 00:00:00 2001
From: Luiz Augusto Von Dentz <luiz.dentz-von@nokia.com>
Date: Wed, 17 Feb 2010 11:22:16 +0200
Subject: [PATCH] Fix possible crash while verifying avdtp version

Reproducible with Codenomicon A2DP testsuite 1.4.2.
---
 audio/avdtp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/audio/avdtp.c b/audio/avdtp.c
index 3b9c6c1..efed9b6 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -2125,7 +2125,7 @@ static uint16_t get_version(struct avdtp *session)
 		goto done;
 
 	proto_desc = sdp_get_proto_desc(protos, AVDTP_UUID);
-	if (proto_desc->dtd == SDP_UINT16)
+	if (proto_desc && proto_desc->dtd == SDP_UINT16)
 		ver = proto_desc->val.uint16;
 
 	sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH] Bluetooth: Allow SCO/eSCO packet type selection for outgoing SCO connections.
From: Ville Tervo @ 2010-02-17  9:30 UTC (permalink / raw)
  To: ext Nick Pelly; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <35c90d961002151315i5fc0f5b9y36aaba4415987a2f@mail.gmail.com>

ext Nick Pelly wrote:
> On Thu, Feb 11, 2010 at 11:59 AM, Nick Pelly <npelly@google.com> wrote:
>> On Thu, Feb 11, 2010 at 11:54 AM, Nick Pelly <npelly@google.com> wrote:
>>> __u16 sco_pkt_type is introduced to struct sockaddr_sco. It allows bitwise
>>> selection of SCO/eSCO packet types as per the Packet_Type parameter in
>>> HCI Setup Synchrnous Connection Command.
>>>
>>> 0x0001 HV1 may be used.
>>> 0x0002 HV2 may be used.
>>> 0x0004 HV3 may be used.
>>> 0x0008 EV3 may be used.
>>> 0x0010 EV4 may be used.
>>> 0x0020 EV5 may be used.
>>> 0x0040 2-EV3 may not be used.
>>> 0x0080 3-EV3 may not be used.
>>> 0x0100 2-EV5 may not be used.
>>> 0x0200 3-EV5 may not be used.
>>>
>>> We've followed the Bluetooth SIG convention of reversing the logic on the
>>> EDR bits.
>>>
>>> Packet type selection is just a request made to the Bluetooth chipset, and
>>> it is up to the link manager on the chipset to negiotiate and decide on the
>>> actual packet types used. Furthermore, when a SCO/eSCO connection is eventually
>>> made there is no way for the host stack to determine which packet type was used
>>> (however it is possible to get the link type of SCO or eSCO).
>>>
>>> sco_pkt_type is ignored for incoming SCO connections. It is possible
>>> to add this in the future as a parameter to the Accept Synchronous Connection
>>> Command, however its a little trickier because the kernel does not
>>> currently preserve sockaddr_sco data between userspace calls to accept().
>>>
>>> Typically userspace just wants to select eSCO or SCO packet types, which can be
>>> done with the new constants ALL_SCO_PKTS or ALL_ESCO_PKTS. If sco_pkt_type is
>>> zero, or userspace uses the old sockaddr_sco structure size, then ALL_ESCO_PKTS
>>> will be selected as default.
>>>
>>> This patch is motivated by broken Bluetooth carkits such as the Motorolo
>>> HF850 (it claims to support eSCO, but will actually reject eSCO connections
>>> after 5 seconds) and the 2007/2008 Infiniti G35/37 (fails to route audio
>>> if a 2-EV5 packet type is negiotiated). With this patch userspace can maintain
>>> a blacklist of packet types to workaround broken remote devices such as these.
>>>
>>> Signed-off-by: Nick Pelly <npelly@google.com>
>>> ---
>>>  include/net/bluetooth/hci.h      |    7 +++-
>>>  include/net/bluetooth/hci_core.h |    7 +++-
>>>  include/net/bluetooth/sco.h      |    4 ++-
>>>  net/bluetooth/hci_conn.c         |   25 +++++++++------
>>>  net/bluetooth/hci_event.c        |    6 ++-
>>>  net/bluetooth/l2cap.c            |    2 +-
>>>  net/bluetooth/sco.c              |   61 +++++++++++++++++++++++++------------
>>>  7 files changed, 74 insertions(+), 38 deletions(-)
>>>
>>> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
>>> index 4f7795f..72efc94 100644
>>> --- a/include/net/bluetooth/hci.h
>>> +++ b/include/net/bluetooth/hci.h
>>> @@ -139,8 +139,11 @@ enum {
>>>  #define ESCO_2EV5      0x0100
>>>  #define ESCO_3EV5      0x0200
>>>
>>> -#define SCO_ESCO_MASK  (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
>>> -#define EDR_ESCO_MASK  (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
>>> +#define SCO_ESCO_MASK  (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
>>> +#define EDR_ESCO_MASK  (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
>>> +
>>> +#define ALL_SCO_PKTS   (SCO_ESCO_MASK | EDR_ESCO_MASK)
>>> +#define ALL_ESCO_PKTS  (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5)
>>>
>>>  /* ACL flags */
>>>  #define ACL_START              0x00
>>> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
>>> index b6d36cb..cbcc5b1 100644
>>> --- a/include/net/bluetooth/hci_core.h
>>> +++ b/include/net/bluetooth/hci_core.h
>>> @@ -326,12 +326,15 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
>>>  void hci_add_sco(struct hci_conn *conn, __u16 handle);
>>>  void hci_setup_sync(struct hci_conn *conn, __u16 handle);
>>>
>>> -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
>>> +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
>>> +                                       __u16 pkt_type, bdaddr_t *dst);
>>>  int hci_conn_del(struct hci_conn *conn);
>>>  void hci_conn_hash_flush(struct hci_dev *hdev);
>>>  void hci_conn_check_pending(struct hci_dev *hdev);
>>>
>>> -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
>>> +struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
>>> +                                       __u16 pkt_type, bdaddr_t *dst,
>>> +                                       __u8 sec_level, __u8 auth_type);
>>>  int hci_conn_check_link_mode(struct hci_conn *conn);
>>>  int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
>>>  int hci_conn_change_link_key(struct hci_conn *conn);
>>> diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
>>> index e28a2a7..924338a 100644
>>> --- a/include/net/bluetooth/sco.h
>>> +++ b/include/net/bluetooth/sco.h
>>> @@ -37,6 +37,7 @@
>>>  struct sockaddr_sco {
>>>        sa_family_t     sco_family;
>>>        bdaddr_t        sco_bdaddr;
>>> +       __u16           sco_pkt_type;
>>>  };
>>>
>>>  /* SCO socket options */
>>> @@ -72,7 +73,8 @@ struct sco_conn {
>>>
>>>  struct sco_pinfo {
>>>        struct bt_sock  bt;
>>> -       __u32           flags;
>>> +       __u16           pkt_type;
>>> +
>>>        struct sco_conn *conn;
>>>  };
>>>
>>> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
>>> index fa8b412..8ced057 100644
>>> --- a/net/bluetooth/hci_conn.c
>>> +++ b/net/bluetooth/hci_conn.c
>>> @@ -196,7 +196,8 @@ static void hci_conn_idle(unsigned long arg)
>>>        hci_conn_enter_sniff_mode(conn);
>>>  }
>>>
>>> -struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
>>> +struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
>>> +                                       __u16 pkt_type, bdaddr_t *dst)
>>>  {
>>>        struct hci_conn *conn;
>>>
>>> @@ -221,14 +222,16 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
>>>                conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
>>>                break;
>>>        case SCO_LINK:
>>> +               if (!pkt_type)
>>> +                       pkt_type = ALL_SCO_PKTS;
>>> +       case ESCO_LINK:
>>> +               if (!pkt_type)
>>> +                       pkt_type = ALL_ESCO_PKTS;
>>>                if (lmp_esco_capable(hdev))
>>> -                       conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
>>> -                                       (hdev->esco_type & EDR_ESCO_MASK);
>>> +                       conn->pkt_type = pkt_type & hdev->esco_type;
>>>                else
>>> -                       conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
>>> -               break;
>>> -       case ESCO_LINK:
>>> -               conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
>>> +                       conn->pkt_type = (pkt_type << 5) & hdev->pkt_type &
>>> +                                       SCO_PTYPE_MASK;
>>>                break;
>>>        }
>>>
>>> @@ -340,7 +343,9 @@ EXPORT_SYMBOL(hci_get_route);
>>>
>>>  /* Create SCO or ACL connection.
>>>  * Device _must_ be locked */
>>> -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
>>> +struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
>>> +                                       __u16 pkt_type, bdaddr_t *dst,
>>> +                                       __u8 sec_level, __u8 auth_type)
>>>  {
>>>        struct hci_conn *acl;
>>>        struct hci_conn *sco;
>>> @@ -348,7 +353,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>>>        BT_DBG("%s dst %s", hdev->name, batostr(dst));
>>>
>>>        if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
>>> -               if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
>>> +               if (!(acl = hci_conn_add(hdev, ACL_LINK, 0, dst)))
>>>                        return NULL;
>>>        }
>>>
>>> @@ -364,7 +369,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>>>                return acl;
>>>
>>>        if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
>>> -               if (!(sco = hci_conn_add(hdev, type, dst))) {
>>> +               if (!(sco = hci_conn_add(hdev, type, pkt_type, dst))) {
>>>                        hci_conn_put(acl);
>>>                        return NULL;
>>>                }
>>> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
>>> index 10edd1a..5343e0f 100644
>>> --- a/net/bluetooth/hci_event.c
>>> +++ b/net/bluetooth/hci_event.c
>>> @@ -579,7 +579,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
>>>                }
>>>        } else {
>>>                if (!conn) {
>>> -                       conn = hci_conn_add(hdev, ACL_LINK, &cp->bdaddr);
>>> +                       conn = hci_conn_add(hdev, ACL_LINK, 0, &cp->bdaddr);
>>>                        if (conn) {
>>>                                conn->out = 1;
>>>                                conn->link_mode |= HCI_LM_MASTER;
>>> @@ -964,7 +964,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
>>>
>>>                conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
>>>                if (!conn) {
>>> -                       if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
>>> +                       /* pkt_type not yet used for incoming connections */
>>> +                       if (!(conn = hci_conn_add(hdev, ev->link_type, 0,
>>> +                                                       &ev->bdaddr))) {
>>>                                BT_ERR("No memmory for new connection");
>>>                                hci_dev_unlock(hdev);
>>>                                return;
>>> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
>>> index d056886..b342f06 100644
>>> --- a/net/bluetooth/l2cap.c
>>> +++ b/net/bluetooth/l2cap.c
>>> @@ -955,7 +955,7 @@ static int l2cap_do_connect(struct sock *sk)
>>>                }
>>>        }
>>>
>>> -       hcon = hci_connect(hdev, ACL_LINK, dst,
>>> +       hcon = hci_connect(hdev, ACL_LINK, 0, dst,
>>>                                        l2cap_pi(sk)->sec_level, auth_type);
>>>        if (!hcon)
>>>                goto done;
>>> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
>>> index 77f4153..4976ad5 100644
>>> --- a/net/bluetooth/sco.c
>>> +++ b/net/bluetooth/sco.c
>>> @@ -176,6 +176,7 @@ static int sco_connect(struct sock *sk)
>>>  {
>>>        bdaddr_t *src = &bt_sk(sk)->src;
>>>        bdaddr_t *dst = &bt_sk(sk)->dst;
>>> +       __u16 pkt_type = sco_pi(sk)->pkt_type;
>>>        struct sco_conn *conn;
>>>        struct hci_conn *hcon;
>>>        struct hci_dev  *hdev;
>>> @@ -192,10 +193,14 @@ static int sco_connect(struct sock *sk)
>>>
>>>        if (lmp_esco_capable(hdev) && !disable_esco)
>>>                type = ESCO_LINK;
>>> -       else
>>> +       else {
>>>                type = SCO_LINK;
>>> +               pkt_type &= SCO_ESCO_MASK;
>>> +               pkt_type |= EDR_ESCO_MASK;
>>> +       }
>>>
>>> -       hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
>>> +       hcon = hci_connect(hdev, type, pkt_type, dst,
>>> +                                       BT_SECURITY_LOW, HCI_AT_NO_BONDING);
>>>        if (!hcon)
>>>                goto done;
>>>
>>> @@ -451,18 +456,22 @@ static int sco_sock_create(struct net *net, struct socket *sock, int protocol)
>>>        return 0;
>>>  }
>>>
>>> -static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
>>> +static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
>>>  {
>>> -       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
>>> +       struct sockaddr_sco sa;
>>>        struct sock *sk = sock->sk;
>>> -       bdaddr_t *src = &sa->sco_bdaddr;
>>> -       int err = 0;
>>> +       bdaddr_t *src = &sa.sco_bdaddr;
>>> +       int len, err = 0;
>>>
>>> -       BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
>>> +       BT_DBG("sk %p %s", sk, batostr(&sa.sco_bdaddr));
>>>
>>>        if (!addr || addr->sa_family != AF_BLUETOOTH)
>>>                return -EINVAL;
>>>
>>> +       memset(&sa, 0, sizeof(sa));
>>> +       len = min_t(unsigned int, sizeof(sa), alen);
>>> +       memcpy(&sa, addr, len);
>>> +
>>>        lock_sock(sk);
>>>
>>>        if (sk->sk_state != BT_OPEN) {
>>> @@ -476,7 +485,8 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
>>>                err = -EADDRINUSE;
>>>        } else {
>>>                /* Save source address */
>>> -               bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
>>> +               bacpy(&bt_sk(sk)->src, &sa.sco_bdaddr);
>>> +               sco_pi(sk)->pkt_type = sa.sco_pkt_type;
>>>                sk->sk_state = BT_BOUND;
>>>        }
>>>
>>> @@ -489,26 +499,34 @@ done:
>>>
>>>  static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
>>>  {
>>> -       struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
>>>        struct sock *sk = sock->sk;
>>> -       int err = 0;
>>> -
>>> +       struct sockaddr_sco sa;
>>> +       int len, err = 0;
>>>
>>>        BT_DBG("sk %p", sk);
>>>
>>> -       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
>>> +       if (!addr || addr->sa_family != AF_BLUETOOTH)
>>>                return -EINVAL;
>>>
>>> -       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
>>> -               return -EBADFD;
>>> -
>>> -       if (sk->sk_type != SOCK_SEQPACKET)
>>> -               return -EINVAL;
>>> +       memset(&sa, 0, sizeof(sa));
>>> +       len = min_t(unsigned int, sizeof(sa), alen);
>>> +       memcpy(&sa, addr, len);
>>>
>>>        lock_sock(sk);
>>>
>>> +       if (sk->sk_type != SOCK_SEQPACKET) {
>>> +               err = -EINVAL;
>>> +               goto done;
>>> +       }
>>> +
>>> +       if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
>>> +               err = -EBADFD;
>>> +               goto done;
>>> +       }
>>> +
>>>        /* Set destination address and psm */
>>> -       bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
>>> +       bacpy(&bt_sk(sk)->dst, &sa.sco_bdaddr);
>>> +       sco_pi(sk)->pkt_type = sa.sco_pkt_type;
>>>
>>>        if ((err = sco_connect(sk)))
>>>                goto done;
>>> @@ -610,10 +628,13 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len
>>>        addr->sa_family = AF_BLUETOOTH;
>>>        *len = sizeof(struct sockaddr_sco);
>>>
>>> -       if (peer)
>>> +       if (peer) {
>>>                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
>>> -       else
>>> +               sa->sco_pkt_type = sco_pi(sk)->pkt_type;
>>> +       } else {
>>>                bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
>>> +               sa->sco_pkt_type = sco_pi(sk)->pkt_type;
>>> +       }
>>>
>>>        return 0;
>>>  }
>>> --
>>> 1.6.5.3
>>>
>>>
>> BTW i'm happy to switch the logic on the EDR bits, such that 1 is
>> always 'allow this packet type'. I stuck with the Bluetooth SIG
>> convention in this patch because the logic actually came out cleanly.
>>
>> Either way, its confusing for userspace, and we should document it
>> carefully in the patch to userspace headers.
> 
> Ping.
> 
> As a first step, can we get consensus on the userspace API:
> 
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -139,8 +139,11 @@ enum {
> +#define ALL_SCO_PKTS   (SCO_ESCO_MASK | EDR_ESCO_MASK)
> +#define ALL_ESCO_PKTS  (SCO_ESCO_MASK | ESCO_EV3 | ESCO_EV4 | ESCO_EV5)
> 
> --- a/include/net/bluetooth/sco.h
> +++ b/include/net/bluetooth/sco.h
> @@ -37,6 +37,7 @@
> struct sockaddr_sco {
>        sa_family_t     sco_family;
>        bdaddr_t        sco_bdaddr;
> +       __u16           sco_pkt_type;
> };
> 
> This will at least unblock my work.

Would it be better to add new sockopt for sco socket?

-- 
Ville



^ permalink raw reply

* Re: [PATCH] Fix signal watch when a service name is given
From: Luiz Augusto von Dentz @ 2010-02-17  9:06 UTC (permalink / raw)
  To: Vinicius Gomes; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <2a9506371002161634h71ef3517pdc8be4f4e400c82e@mail.gmail.com>

Hi Vinicius,

On Wed, Feb 17, 2010 at 2:34 AM, Vinicius Gomes
<vinicius.gomes@openbossa.org> wrote:
> Hi Luiz,
>
> On Tue, Feb 16, 2010 at 12:58 PM, Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> Hi Marcel,
>>
>> On Tue, Feb 16, 2010 at 5:37 PM, Marcel Holtmann <marcel@holtmann.org> w=
rote:
>>> Hi Luiz,
>>>
>>>> > This should fix g_dbus_add_signal_watch when a service like org.blue=
z is given.
>>>>
>>>>
>>>> Updating since the last one was broken.
>>>
>>> I also think that in check_service() we actually have a missing call to
>>> dbus_pending_unref(). That would cause a memory leak.
>>
>> There is a call to =A0dbus_pending_call_unref on check_service after
>> dbus_pending_call_set_notify, which I took a look and seems correct
>> but we have another problem there since we never cancel the pending
>> call if the filter is unregister. Anyway there is a leak on
>> service_reply where I don't call dbus_message_unref, so I will come up
>> with another update soon.
>>
>
> This is fixed on obexd, but as far as I could see it is not (yet?)
> applied on the other users
> of gdbus.

Hmm, that why I see it, I used obexd to test this not bluetoothd as
(probably) Marcel did, anyway we still need to store and cancel the
pending call if we really want the watches to be truly cancelable.

> And, from what I tested the greater problem is that the timeout of the
> pending call would still
> trigger. This would cause libdbus to terminate the application, if
> libdbus was built with debug enabled,
> because one assert would fail (the message is "trying to remove an
> nonexistent timeout" or
> =A0something like it). The timeout still triggering is the reason we
> don't see the pending call leaking.

@Marcel: So before you apply this you should really apply Vinicius
patch to the rest of projects: bluez, ofono, connman...

--=20
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply

* Re: Unable to change HS speaker and microphone gain
From: nirav rabara @ 2010-02-17  4:32 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

It would be very appreciable if somebody just put some light on this.



On Tue, Feb 16, 2010 at 6:15 PM, nirav rabara <niravrabara@gmail.com> wrote:
> Hi,
> Using D-Bus API (SetSpeakerGain() & SetMicrophoneGain()) I am changing
> the speaker & microphone gain of Headset.
> Whenever I use this API to change the gain value , Signal
> SpeakerGainChanged & MicrophoneGainChanged emitted by bluetoothd, It
> shows me the same value as I have set.
> i.e if I set speakergain to 10, signal SpeakerGainChanged shows me 10.
> But it doesn't affect the HS actual gain(i.e. on impact on actual
> voice on HS ) it remains as it is.
>
> Can somebody suggest me what I am missing??
>
> --
> With Regards,
> Nirav Rabara
>



-- 
With Regards,
Nirav Rabara

^ permalink raw reply

* Re: [PATCH] Fix signal watch when a service name is given
From: Vinicius Gomes @ 2010-02-17  0:34 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <2d5a2c101002160758k131bd0f1y3477958780d11a02@mail.gmail.com>

Hi Luiz,

On Tue, Feb 16, 2010 at 12:58 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi Marcel,
>
> On Tue, Feb 16, 2010 at 5:37 PM, Marcel Holtmann <marcel@holtmann.org> wr=
ote:
>> Hi Luiz,
>>
>>> > This should fix g_dbus_add_signal_watch when a service like org.bluez=
 is given.
>>>
>>>
>>> Updating since the last one was broken.
>>
>> I also think that in check_service() we actually have a missing call to
>> dbus_pending_unref(). That would cause a memory leak.
>
> There is a call to =C2=A0dbus_pending_call_unref on check_service after
> dbus_pending_call_set_notify, which I took a look and seems correct
> but we have another problem there since we never cancel the pending
> call if the filter is unregister. Anyway there is a leak on
> service_reply where I don't call dbus_message_unref, so I will come up
> with another update soon.
>

This is fixed on obexd, but as far as I could see it is not (yet?)
applied on the other users
of gdbus.

And, from what I tested the greater problem is that the timeout of the
pending call would still
trigger. This would cause libdbus to terminate the application, if
libdbus was built with debug enabled,
because one assert would fail (the message is "trying to remove an
nonexistent timeout" or
 something like it). The timeout still triggering is the reason we
don't see the pending call leaking.

> --
> Luiz Augusto von Dentz
> Computer Engineer
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth=
" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at =C2=A0http://vger.kernel.org/majordomo-info.html
>


Cheers,
--=20
Vinicius Gomes
INdT - Instituto Nokia de Tecnologia

^ permalink raw reply

* Re: [PATCH] bluez-hcidump fix SDP universal attributes
From: Iain Hibbert @ 2010-02-16 22:55 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1266334962.8849.8.camel@localhost.localdomain>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1177 bytes --]

On Tue, 16 Feb 2010, Marcel Holtmann wrote:

> > > > hcidump shows SDP universal attribute 0x000d as IconURL but in fact it is
> > > > defined as "Additional Protocol Descriptor Lists". IconURL is 0x000c and I
> > > > don't know what Icon_10 was, perhaps an older name?
> > > >
> > > > Eg, from an SDP probe of a mouse:
> > > >
> > > >       aid 0x000d (IconURL)
> > > >          < < < uuid-16 0x0100 (L2CAP) uint 0x13 > < uuid-16 0x0011 (HIDP) > > >
> > >
> > > Reposting because there was no response to this, patch is attached..
> > >
> > > See "5.1.6 AdditionalProtocolDescriptorList attribute" and "5.1.14 IconURL
> > > Attribute" sections in the core specification for reference..
> > >
> > > (they sometimes call it AdditionalProtocolDescriptorLists and that is more
> > > accurate as more than one protocol descriptor list may be included)
> >
> > posting this simple (and easily verified) patch for hcidump for the third
> > time..
>
> sorry for having missed it. For some reason it got sorted away. Can you
> create a proper patch with git format-patch. That makes it way easier
> for me to apply them.

I am not a git user but perhaps this is correct?

regards,
iain

[-- Attachment #2: git format-patch --]
[-- Type: TEXT/PLAIN, Size: 2087 bytes --]

From 5615f136fb57a97da15a29c8b27cef1a707efaa3 Mon Sep 17 00:00:00 2001
From: Iain Hibbert <plunky@galant.(none)>
Date: Tue, 16 Feb 2010 22:47:19 +0000
Subject: [PATCH] correct SDP Universal Attribute name printing

    0x000c = IconURL
    0x000d = AttributeProtocolDescriptorLists
---
 parser/sdp.c |    2 +-
 parser/sdp.h |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/parser/sdp.c b/parser/sdp.c
index 5f2c1c6..b9f990e 100644
--- a/parser/sdp.c
+++ b/parser/sdp.c
@@ -194,8 +194,8 @@ static sdp_attr_id_nam_lookup_table_t sdp_attr_id_nam_lookup_table[] = {
 	{ SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, "BTProfileDescList"  },
 	{ SDP_ATTR_ID_DOCUMENTATION_URL,                 "DocURL"             },
 	{ SDP_ATTR_ID_CLIENT_EXECUTABLE_URL,             "ClientExeURL"       },
-	{ SDP_ATTR_ID_ICON_10,                           "Icon10"             },
 	{ SDP_ATTR_ID_ICON_URL,                          "IconURL"            },
+	{ SDP_ATTR_ID_ADDITIONAL_PROTOCOL_DESC_LISTS,    "AdditionalProtocolDescLists" },
 	{ SDP_ATTR_ID_SERVICE_NAME,                      "SrvName"            },
 	{ SDP_ATTR_ID_SERVICE_DESCRIPTION,               "SrvDesc"            },
 	{ SDP_ATTR_ID_PROVIDER_NAME,                     "ProviderName"       },
diff --git a/parser/sdp.h b/parser/sdp.h
index 09e4432..4769fd0 100644
--- a/parser/sdp.h
+++ b/parser/sdp.h
@@ -129,8 +129,8 @@
 #define SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST  0x0009
 #define SDP_ATTR_ID_DOCUMENTATION_URL                  0x000A
 #define SDP_ATTR_ID_CLIENT_EXECUTABLE_URL              0x000B
-#define SDP_ATTR_ID_ICON_10                            0x000C
-#define SDP_ATTR_ID_ICON_URL                           0x000D
+#define SDP_ATTR_ID_ICON_URL                           0x000C
+#define SDP_ATTR_ID_ADDITIONAL_PROTOCOL_DESC_LISTS     0x000D
 #define SDP_ATTR_ID_SERVICE_NAME                       0x0100
 #define SDP_ATTR_ID_SERVICE_DESCRIPTION                0x0101
 #define SDP_ATTR_ID_PROVIDER_NAME                      0x0102
-- 
1.6.6


^ permalink raw reply related

* Re: [PATCH] eSCO fallback to SCO on Error: Unsupported Feature or Parameter Value
From: Marcel Holtmann @ 2010-02-16 18:05 UTC (permalink / raw)
  To: smcoe; +Cc: linux-bluetooth, Stephen Coe
In-Reply-To: <1266337784-7898-1-git-send-email-smcoe@gmail.com>

Hi Stephen,

> The Bluetooth SIG PTS test case: TC_AG_ACS_BV_10_I, rejects eSCO with
> "Unsupported Feature or Parameter Value" (0x11).  This patch adds case
> for SCO fall back.
> 
> 2007-09-20 12:20:37.787747 > HCI Event: Number of Completed Packets
> (0x13) plen 5
>    handle 38 packets 1
> 2007-09-20 12:20:37.842154 < HCI Command: Setup Synchronous Connection
> (0x01|0x0028) plen 17
>    handle 38 voice setting 0x0060
> 2007-09-20 12:20:37.847037 > HCI Event: Command Status (0x0f) plen 4
>    Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1
> 2007-09-20 12:20:37.855233 > HCI Event: Max Slots Change (0x1b) plen 3
>    handle 38 slots 1
> 2007-09-20 12:20:39.913354 > HCI Event: Synchronous Connect Complete
> (0x2c) plen 17
>    status 0x11 handle 38 bdaddr 00:16:93:01:01:7A type eSCO
>    Error: Unsupported Feature or Parameter Value
> 2007-09-20 12:20:39.922629 > HCI Event: Max Slots Change (0x1b) plen 3
>    handle 38 slots 5
> 2007-09-20 12:20:58.126886 < ACL data: handle 38 flags 0x02 dlen 8
>    L2CAP(d): cid 0x0041 len 4 [psm 0]
>      0000: 0b 53 01 b8                                       .S..
> 2007-09-20 12:20:58.130138 > HCI Event: Number of Completed Packets
> (0x13) plen 5
>    handle 38 packets 1
> 
> Signed-off-by: Stephen Coe <smcoe1@gmail.com>
> ---
>  net/bluetooth/hci_event.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)

patch has been applied to bluetooth-2.6 tree.

Regards

Marcel



^ permalink raw reply

* [PATCH] eSCO fallback to SCO on Error: Unsupported Feature or Parameter Value
From: smcoe @ 2010-02-16 16:29 UTC (permalink / raw)
  To: marcel; +Cc: linux-bluetooth, Stephen Coe

The Bluetooth SIG PTS test case: TC_AG_ACS_BV_10_I, rejects eSCO with
"Unsupported Feature or Parameter Value" (0x11).  This patch adds case
for SCO fall back.

2007-09-20 12:20:37.787747 > HCI Event: Number of Completed Packets
(0x13) plen 5
   handle 38 packets 1
2007-09-20 12:20:37.842154 < HCI Command: Setup Synchronous Connection
(0x01|0x0028) plen 17
   handle 38 voice setting 0x0060
2007-09-20 12:20:37.847037 > HCI Event: Command Status (0x0f) plen 4
   Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1
2007-09-20 12:20:37.855233 > HCI Event: Max Slots Change (0x1b) plen 3
   handle 38 slots 1
2007-09-20 12:20:39.913354 > HCI Event: Synchronous Connect Complete
(0x2c) plen 17
   status 0x11 handle 38 bdaddr 00:16:93:01:01:7A type eSCO
   Error: Unsupported Feature or Parameter Value
2007-09-20 12:20:39.922629 > HCI Event: Max Slots Change (0x1b) plen 3
   handle 38 slots 5
2007-09-20 12:20:58.126886 < ACL data: handle 38 flags 0x02 dlen 8
   L2CAP(d): cid 0x0041 len 4 [psm 0]
     0000: 0b 53 01 b8                                       .S..
2007-09-20 12:20:58.130138 > HCI Event: Number of Completed Packets
(0x13) plen 5
   handle 38 packets 1

Signed-off-by: Stephen Coe <smcoe1@gmail.com>
---
 net/bluetooth/hci_event.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 592da5c..6c57fc7 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1698,6 +1698,7 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
 		hci_conn_add_sysfs(conn);
 		break;
 
+	case 0x11:	/* Unsupported Feature or Parameter Value */
 	case 0x1c:	/* SCO interval rejected */
 	case 0x1a:	/* Unsupported Remote Feature */
 	case 0x1f:	/* Unspecified error */

^ permalink raw reply related

* Re: [PATCH] Fix signal watch when a service name is given
From: Luiz Augusto von Dentz @ 2010-02-16 16:25 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <2d5a2c101002160758k131bd0f1y3477958780d11a02@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 957 bytes --]

Hi,

On Tue, Feb 16, 2010 at 5:58 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi Marcel,
>
> On Tue, Feb 16, 2010 at 5:37 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>> Hi Luiz,
>>
>>> > This should fix g_dbus_add_signal_watch when a service like org.bluez is given.
>>>
>>>
>>> Updating since the last one was broken.
>>
>> I also think that in check_service() we actually have a missing call to
>> dbus_pending_unref(). That would cause a memory leak.
>
> There is a call to  dbus_pending_call_unref on check_service after
> dbus_pending_call_set_notify, which I took a look and seems correct
> but we have another problem there since we never cancel the pending
> call if the filter is unregister. Anyway there is a leak on
> service_reply where I don't call dbus_message_unref, so I will come up
> with another update soon.

Now with the memory leaks fixed.

-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0001-Fix-signal-watch-when-a-service-name-is-given.patch --]
[-- Type: text/x-patch, Size: 9243 bytes --]

From ae57b44fe1aa0203797d0838c27a91fef24fa83f Mon Sep 17 00:00:00 2001
From: Luiz Augusto Von Dentz <luiz.dentz-von@nokia.com>
Date: Tue, 16 Feb 2010 18:20:22 +0200
Subject: [PATCH] Fix signal watch when a service name is given

The bus name should be resolved when adding a watch by service name since
messages do always come with sender set to owner's bus name, also it
should listen to owner updates since it can change without invalidating
the watch.
---
 gdbus/watch.c |  138 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 116 insertions(+), 22 deletions(-)

diff --git a/gdbus/watch.c b/gdbus/watch.c
index 1d479fa..fae53e6 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -55,19 +55,22 @@ struct filter_callback {
 struct filter_data {
 	DBusConnection *connection;
 	DBusHandleMessageFunction handle_func;
-	char *sender;
+	char *name;
+	char *owner;
 	char *path;
 	char *interface;
 	char *member;
 	char *argument;
 	GSList *callbacks;
 	GSList *processed;
+	guint name_watch;
 	gboolean lock;
 	gboolean registered;
 };
 
 static struct filter_data *filter_data_find(DBusConnection *connection,
-							const char *sender,
+							const char *name,
+							const char *owner,
 							const char *path,
 							const char *interface,
 							const char *member,
@@ -82,8 +85,12 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 		if (connection != data->connection)
 			continue;
 
-		if (sender && data->sender &&
-				g_str_equal(sender, data->sender) == FALSE)
+		if (name && data->name &&
+				g_str_equal(name, data->name) == FALSE)
+			continue;
+
+		if (owner && data->owner &&
+				g_str_equal(owner, data->owner) == FALSE)
 			continue;
 
 		if (path && data->path &&
@@ -110,13 +117,15 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 
 static void format_rule(struct filter_data *data, char *rule, size_t size)
 {
+	const char *sender;
 	int offset;
 
 	offset = snprintf(rule, size, "type='signal'");
+	sender = data->name ? : data->owner;
 
-	if (data->sender)
+	if (sender)
 		offset += snprintf(rule + offset, size - offset,
-				",sender='%s'", data->sender);
+				",sender='%s'", sender);
 	if (data->path)
 		offset += snprintf(rule + offset, size - offset,
 				",path='%s'", data->path);
@@ -183,8 +192,10 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 					const char *argument)
 {
 	struct filter_data *data;
+	const char *name = NULL, *owner = NULL;
 
-	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL)) {
+	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+				NULL)) {
 		if (!dbus_connection_add_filter(connection,
 					message_filter, NULL, NULL)) {
 			error("dbus_connection_add_filter() failed");
@@ -192,15 +203,25 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 		}
 	}
 
-	data = filter_data_find(connection, sender, path, interface, member,
-					argument);
+	if (sender == NULL)
+		goto proceed;
+
+	if (sender[0] == ':')
+		owner = sender;
+	else
+		name = sender;
+
+proceed:
+	data = filter_data_find(connection, name, owner, path, interface,
+					member, argument);
 	if (data)
 		return data;
 
 	data = g_new0(struct filter_data, 1);
 
 	data->connection = dbus_connection_ref(connection);
-	data->sender = g_strdup(sender);
+	data->name = name ? g_strdup(name) : NULL;
+	data->owner = owner ? g_strdup(owner) : NULL;
 	data->path = g_strdup(path);
 	data->interface = g_strdup(interface);
 	data->member = g_strdup(member);
@@ -244,7 +265,9 @@ static void filter_data_free(struct filter_data *data)
 		g_free(l->data);
 
 	g_slist_free(data->callbacks);
-	g_free(data->sender);
+	g_dbus_remove_watch(data->connection, data->name_watch);
+	g_free(data->name);
+	g_free(data->owner);
 	g_free(data->path);
 	g_free(data->interface);
 	g_free(data->member);
@@ -322,7 +345,8 @@ static gboolean filter_data_remove_callback(struct filter_data *data,
 	filter_data_free(data);
 
 	/* Remove filter if there are no listeners left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -359,6 +383,37 @@ static DBusHandlerResult signal_filter(DBusConnection *connection,
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+static void update_name_cache(const char *name, const char *owner)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		g_free(data->owner);
+		data->owner = g_strdup(owner);
+	}
+}
+
+static const char *check_name_cache(const char *name)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		return data->owner;
+	}
+
+	return NULL;
+}
+
 static DBusHandlerResult service_filter(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -375,6 +430,8 @@ static DBusHandlerResult service_filter(DBusConnection *connection,
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
+	update_name_cache(name, new);
+
 	while (data->callbacks) {
 		cb = data->callbacks->data;
 
@@ -421,7 +478,9 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	member = dbus_message_get_member(message);
 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-	data = filter_data_find(connection, sender, path, iface, member, arg);
+	/* Sender is always bus name */
+	data = filter_data_find(connection, NULL, sender, path, iface, member,
+					arg);
 	if (!data) {
 		error("Got %s.%s signal which has no listeners", iface, member);
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -446,7 +505,8 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	filter_data_free(data);
 
 	/* Remove filter if there no listener left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -456,16 +516,37 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 
 struct service_data {
 	DBusConnection *conn;
+	char *name;
+	const char *owner;
 	GDBusWatchFunction conn_func;
 	void *user_data;
 };
 
+static void service_data_free(struct service_data *data)
+{
+	dbus_connection_unref(data->conn);
+	g_free(data->name);
+	g_free(data);
+}
+
+static gboolean update_service(void *user_data)
+{
+	struct service_data *data = user_data;
+
+	update_name_cache(data->name, data->owner);
+	if (data->conn_func)
+		data->conn_func(data->conn, data->user_data);
+
+	service_data_free(data);
+
+	return FALSE;
+}
+
 static void service_reply(DBusPendingCall *call, void *user_data)
 {
 	struct service_data *data = user_data;
 	DBusMessage *reply;
 	DBusError error;
-	dbus_bool_t has_owner;
 
 	reply = dbus_pending_call_steal_reply(call);
 	if (reply == NULL)
@@ -474,19 +555,19 @@ static void service_reply(DBusPendingCall *call, void *user_data)
 	dbus_error_init(&error);
 
 	if (dbus_message_get_args(reply, &error,
-					DBUS_TYPE_BOOLEAN, &has_owner,
+					DBUS_TYPE_STRING, &data->owner,
 						DBUS_TYPE_INVALID) == FALSE) {
 		if (dbus_error_is_set(&error) == TRUE) {
 			error("%s", error.message);
 			dbus_error_free(&error);
 		} else {
-			error("Wrong arguments for NameHasOwner reply");
+			error("Wrong arguments for GetNameOwner reply");
 		}
+		service_data_free(data);
 		goto done;
 	}
 
-	if (has_owner && data->conn_func)
-		data->conn_func(data->conn, data->user_data);
+	update_service(data);
 
 done:
 	dbus_message_unref(reply);
@@ -505,12 +586,19 @@ static void check_service(DBusConnection *connection, const char *name,
 		return;
 	}
 
-	data->conn = connection;
+	data->conn = dbus_connection_ref(connection);
+	data->name = g_strdup(name);
 	data->conn_func = connect;
 	data->user_data = user_data;
 
+	data->owner = check_name_cache(name);
+	if (data->owner != NULL) {
+		g_idle_add(update_service, data);
+		return;
+	}
+
 	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
+			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
 	if (message == NULL) {
 		error("Can't allocate new message");
 		g_free(data);
@@ -596,6 +684,11 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
 	if (!cb)
 		return 0;
 
+	if (data->name != NULL && data->name_watch == 0)
+		data->name_watch = g_dbus_add_service_watch(connection,
+							data->name, NULL,
+							NULL, NULL, NULL);
+
 	return cb->id;
 }
 
@@ -625,7 +718,8 @@ void g_dbus_remove_all_watches(DBusConnection *connection)
 {
 	struct filter_data *data;
 
-	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL))) {
+	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
+					NULL, NULL))) {
 		listeners = g_slist_remove(listeners, data);
 		filter_data_call_and_free(data);
 	}
-- 
1.6.3.3


^ permalink raw reply related

* a2dp with mouse input device - skipping,pitch change in stream
From: Pal Z. Illes @ 2010-02-16 16:07 UTC (permalink / raw)
  To: linux-bluetooth

Hello,

I wanted to ask if you are aware of the following issue:

Using a2dp and BT mouse together with bluez it very frequently results
in pitch changes and skipping in the audio stream.

I am using 2 notebooks with my Sony dr-bt21g  stereo headset and a
gigabyte BT mouse. One notebook is with 2.0 and the other with 2.1
profile. (The thing is not reproducible under Windows.) A bunch of
ubuntu users opened a bug on the launchpad (
http://bugs.launchpad.net/ubuntu/+source/bluez/+bug/424215 )

I'm using arch linux amd64. kernel 2.6.32 + bluez-git. Tried 4.60 too.
Tried with simple ALSA bluetooth, and with pulseaudio too. I have
hcidump and am running 'bluetoothd -dn'. Couldn't spot any special
hints in the dump or logs. I can possibly try kernel 2.6.33-rc* too if
there's something related (i have checked changelog of the kernel,
couldnt spot anything related, but you will know it better).

If this is new to you, or even old, anyway how can I help you to
discover the cause of it?

Or is there a configuration option I'm missing here? (I have tried
hciconfig parameters lm,lp, different settings, modifying mtu size and
whatever i could, no avail.)

Regards,
Pal Zoltan Illes


-----

The 2.0 device:

hciconfig -a

hci0:   Type: BR/EDR  Bus: USB
        BD Address: 00:1D:92:1E:13:01  ACL MTU: 310:10  SCO MTU: 64:8
        UP RUNNING PSCAN ISCAN
        RX bytes:3293882 acl:115129 sco:0 events:188738 errors:0
        TX bytes:56340728 acl:196228 sco:0 commands:352 errors:8
        Features: 0xff 0xff 0x8f 0xfe 0x9b 0xf9 0x00 0x80
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
        Link policy: HOLD SNIFF PARK
        Link mode: SLAVE ACCEPT
        Name: 'CSR - bc4'
        Class: 0x1a010c
        Service Classes: Networking, Capturing, Object Transfer
        Device Class: Computer, Laptop
        HCI Ver: 2.0 (0x3)  HCI Rev: 0xc5c
        LMP Ver: 2.0 (0x3)  LMP Subver: 0xc5c
        Manufacturer: Cambridge Silicon Radio (10)

(link policies already tried: with or without RSWITCH, lm
master,accept / slave / etc etc...)

^ permalink raw reply

* Re: [PATCH] Fix signal watch when a service name is given
From: Luiz Augusto von Dentz @ 2010-02-16 15:58 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1266334628.8849.5.camel@localhost.localdomain>

Hi Marcel,

On Tue, Feb 16, 2010 at 5:37 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Luiz,
>
>> > This should fix g_dbus_add_signal_watch when a service like org.bluez is given.
>>
>>
>> Updating since the last one was broken.
>
> I also think that in check_service() we actually have a missing call to
> dbus_pending_unref(). That would cause a memory leak.

There is a call to  dbus_pending_call_unref on check_service after
dbus_pending_call_set_notify, which I took a look and seems correct
but we have another problem there since we never cancel the pending
call if the filter is unregister. Anyway there is a leak on
service_reply where I don't call dbus_message_unref, so I will come up
with another update soon.

-- 
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply

* Re: [PATCH] bluez-hcidump fix SDP universal attributes
From: Marcel Holtmann @ 2010-02-16 15:42 UTC (permalink / raw)
  To: Iain Hibbert; +Cc: linux-bluetooth
In-Reply-To: <1266312330.230253.2026.nullmailer@galant.ukfsn.org>

Hi Iain,

> > > hcidump shows SDP universal attribute 0x000d as IconURL but in fact it is
> > > defined as "Additional Protocol Descriptor Lists". IconURL is 0x000c and I
> > > don't know what Icon_10 was, perhaps an older name?
> > >
> > > Eg, from an SDP probe of a mouse:
> > >
> > >       aid 0x000d (IconURL)
> > >          < < < uuid-16 0x0100 (L2CAP) uint 0x13 > < uuid-16 0x0011 (HIDP) > > >
> >
> > Reposting because there was no response to this, patch is attached..
> >
> > See "5.1.6 AdditionalProtocolDescriptorList attribute" and "5.1.14 IconURL
> > Attribute" sections in the core specification for reference..
> >
> > (they sometimes call it AdditionalProtocolDescriptorLists and that is more
> > accurate as more than one protocol descriptor list may be included)
> 
> posting this simple (and easily verified) patch for hcidump for the third
> time..

sorry for having missed it. For some reason it got sorted away. Can you
create a proper patch with git format-patch. That makes it way easier
for me to apply them.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH] eSCO fallback to SCO on Error: Connection Failed to Complete
From: Marcel Holtmann @ 2010-02-16 15:40 UTC (permalink / raw)
  To: smcoe1; +Cc: Nick Pelly, linux-bluetooth
In-Reply-To: <9c9ad6a31002160721j38fc388u99e35234f28270ed@mail.gmail.com>

Hi Stephen,

> The Bluetooth SIG PTS test case: TC_AG_ACS_BV_10_I, rejects eSCO with
> "Unsupported Feature or Parameter Value" (0x11).  This patch adds case
> for SCO fall back.
> 
> 2007-09-20 12:20:37.787747 > HCI Event: Number of Completed Packets
> (0x13) plen 5
>     handle 38 packets 1
> 2007-09-20 12:20:37.842154 < HCI Command: Setup Synchronous Connection
> (0x01|0x0028) plen 17
>     handle 38 voice setting 0x0060
> 2007-09-20 12:20:37.847037 > HCI Event: Command Status (0x0f) plen 4
>     Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1
> 2007-09-20 12:20:37.855233 > HCI Event: Max Slots Change (0x1b) plen 3
>     handle 38 slots 1
> 2007-09-20 12:20:39.913354 > HCI Event: Synchronous Connect Complete
> (0x2c) plen 17
>     status 0x11 handle 38 bdaddr 00:16:93:01:01:7A type eSCO
>     Error: Unsupported Feature or Parameter Value
> 2007-09-20 12:20:39.922629 > HCI Event: Max Slots Change (0x1b) plen 3
>     handle 38 slots 5
> 2007-09-20 12:20:58.126886 < ACL data: handle 38 flags 0x02 dlen 8
>     L2CAP(d): cid 0x0041 len 4 [psm 0]
>       0000: 0b 53 01 b8                                       .S..
> 2007-09-20 12:20:58.130138 > HCI Event: Number of Completed Packets
> (0x13) plen 5
>     handle 38 packets 1
> 
> 
> 
> Signed-off-by: Stephen Coe <smcoe1@gmail.com>
>
> ---
>  net/bluetooth/hci_event.c |    1 +
>  1 files changed, 1 insertions(+), 0 deletions(-)
> 
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 592da5c..6c57fc7 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -1698,6 +1698,7 @@ static inline void
> hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
>         hci_conn_add_sysfs(conn);
>         break;
> 

your mailer seem to have corrupted the patch. Make sure it doesn't
introduce any line break. Or better just use git send-email.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH] Fix signal watch when a service name is given
From: Marcel Holtmann @ 2010-02-16 15:37 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <2d5a2c101002160715l7f9a2f07y4a40b19e31fa98b3@mail.gmail.com>

Hi Luiz,

> > This should fix g_dbus_add_signal_watch when a service like org.bluez is given.
> 
> 
> Updating since the last one was broken.

I also think that in check_service() we actually have a missing call to
dbus_pending_unref(). That would cause a memory leak.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH] Fix bug on ftp plugin when mimetype exists but is unknown
From: Marcel Holtmann @ 2010-02-16 15:33 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <2d5a2c101002160637k59f9cb0fx963d3b489ee37df3@mail.gmail.com>

Hi Luiz,

> The code was returning FALSE (0) when it should return a posix error thus
> causing a unkown mimetype to not be handle by mimetype drivers as it
> should.

patch has been applied. Thanks.

Regards

Marcel



^ permalink raw reply

* Re: [PATCH] eSCO fallback to SCO on Error: Connection Failed to Complete
From: smcoe1 @ 2010-02-16 15:21 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Nick Pelly, linux-bluetooth
In-Reply-To: <1265997402.21559.0.camel@localhost.localdomain>

The Bluetooth SIG PTS test case: TC_AG_ACS_BV_10_I, rejects eSCO with
"Unsupported Feature or Parameter Value" (0x11).  This patch adds case
for SCO fall back.

2007-09-20 12:20:37.787747 > HCI Event: Number of Completed Packets
(0x13) plen 5
    handle 38 packets 1
2007-09-20 12:20:37.842154 < HCI Command: Setup Synchronous Connection
(0x01|0x0028) plen 17
    handle 38 voice setting 0x0060
2007-09-20 12:20:37.847037 > HCI Event: Command Status (0x0f) plen 4
    Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1
2007-09-20 12:20:37.855233 > HCI Event: Max Slots Change (0x1b) plen 3
    handle 38 slots 1
2007-09-20 12:20:39.913354 > HCI Event: Synchronous Connect Complete
(0x2c) plen 17
    status 0x11 handle 38 bdaddr 00:16:93:01:01:7A type eSCO
    Error: Unsupported Feature or Parameter Value
2007-09-20 12:20:39.922629 > HCI Event: Max Slots Change (0x1b) plen 3
    handle 38 slots 5
2007-09-20 12:20:58.126886 < ACL data: handle 38 flags 0x02 dlen 8
    L2CAP(d): cid 0x0041 len 4 [psm 0]
      0000: 0b 53 01 b8                                       .S..
2007-09-20 12:20:58.130138 > HCI Event: Number of Completed Packets
(0x13) plen 5
    handle 38 packets 1



Signed-off-by: Stephen Coe <smcoe1@gmail.com>
---
 net/bluetooth/hci_event.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 592da5c..6c57fc7 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1698,6 +1698,7 @@ static inline void
hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
        hci_conn_add_sysfs(conn);
        break;

+   case 0x11:  /* Unsupported Feature or Parameter Value */
    case 0x1c:  /* SCO interval rejected */
    case 0x1a:  /* Unsupported Remote Feature */
    case 0x1f:  /* Unspecified error */

^ permalink raw reply related

* Re: [PATCH] Fix signal watch when a service name is given
From: Luiz Augusto von Dentz @ 2010-02-16 15:15 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <2d5a2c101002160659j1fd3fff8hc5418ddb7481b25d@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 270 bytes --]

Hi,

On Tue, Feb 16, 2010 at 4:59 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> Hi,
>
> This should fix g_dbus_add_signal_watch when a service like org.bluez is given.


Updating since the last one was broken.


-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0002-Fix-signal-watch-when-a-service-name-is-given.patch --]
[-- Type: text/x-patch, Size: 9334 bytes --]

From 00d9fe7a749130d51f7d70cb0469005ef7445441 Mon Sep 17 00:00:00 2001
From: Luiz Augusto Von Dentz <luiz.dentz-von@nokia.com>
Date: Tue, 16 Feb 2010 17:11:27 +0200
Subject: [PATCH 2/2] Fix signal watch when a service name is given

The bus name should be resolved when adding a watch by service name since
messages do always come with sender set to owner's bus name, also it
should listen to owner updates since it can change without invalidating
the watch.
---
 gdbus/watch.c |  139 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 117 insertions(+), 22 deletions(-)

diff --git a/gdbus/watch.c b/gdbus/watch.c
index 1d479fa..864b4a3 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -55,19 +55,22 @@ struct filter_callback {
 struct filter_data {
 	DBusConnection *connection;
 	DBusHandleMessageFunction handle_func;
-	char *sender;
+	char *name;
+	char *owner;
 	char *path;
 	char *interface;
 	char *member;
 	char *argument;
 	GSList *callbacks;
 	GSList *processed;
+	guint name_watch;
 	gboolean lock;
 	gboolean registered;
 };
 
 static struct filter_data *filter_data_find(DBusConnection *connection,
-							const char *sender,
+							const char *name,
+							const char *owner,
 							const char *path,
 							const char *interface,
 							const char *member,
@@ -82,8 +85,12 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 		if (connection != data->connection)
 			continue;
 
-		if (sender && data->sender &&
-				g_str_equal(sender, data->sender) == FALSE)
+		if (name && data->name &&
+				g_str_equal(name, data->name) == FALSE)
+			continue;
+
+		if (owner && data->owner &&
+				g_str_equal(owner, data->owner) == FALSE)
 			continue;
 
 		if (path && data->path &&
@@ -110,13 +117,15 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 
 static void format_rule(struct filter_data *data, char *rule, size_t size)
 {
+	const char *sender;
 	int offset;
 
 	offset = snprintf(rule, size, "type='signal'");
+	sender = data->name ? : data->owner;
 
-	if (data->sender)
+	if (sender)
 		offset += snprintf(rule + offset, size - offset,
-				",sender='%s'", data->sender);
+				",sender='%s'", sender);
 	if (data->path)
 		offset += snprintf(rule + offset, size - offset,
 				",path='%s'", data->path);
@@ -183,8 +192,10 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 					const char *argument)
 {
 	struct filter_data *data;
+	const char *name = NULL, *owner = NULL;
 
-	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL)) {
+	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+				NULL)) {
 		if (!dbus_connection_add_filter(connection,
 					message_filter, NULL, NULL)) {
 			error("dbus_connection_add_filter() failed");
@@ -192,15 +203,25 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 		}
 	}
 
-	data = filter_data_find(connection, sender, path, interface, member,
-					argument);
+	if (sender == NULL)
+		goto proceed;
+
+	if (sender[0] == ':')
+		owner = sender;
+	else
+		name = sender;
+
+proceed:
+	data = filter_data_find(connection, name, owner, path, interface,
+					member, argument);
 	if (data)
 		return data;
 
 	data = g_new0(struct filter_data, 1);
 
 	data->connection = dbus_connection_ref(connection);
-	data->sender = g_strdup(sender);
+	data->name = name ? g_strdup(name) : NULL;
+	data->owner = owner ? g_strdup(owner) : NULL;
 	data->path = g_strdup(path);
 	data->interface = g_strdup(interface);
 	data->member = g_strdup(member);
@@ -244,7 +265,9 @@ static void filter_data_free(struct filter_data *data)
 		g_free(l->data);
 
 	g_slist_free(data->callbacks);
-	g_free(data->sender);
+	g_dbus_remove_watch(data->connection, data->name_watch);
+	g_free(data->name);
+	g_free(data->owner);
 	g_free(data->path);
 	g_free(data->interface);
 	g_free(data->member);
@@ -322,7 +345,8 @@ static gboolean filter_data_remove_callback(struct filter_data *data,
 	filter_data_free(data);
 
 	/* Remove filter if there are no listeners left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -359,6 +383,37 @@ static DBusHandlerResult signal_filter(DBusConnection *connection,
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+static void update_name_cache(const char *name, const char *owner)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		g_free(data->owner);
+		data->owner = g_strdup(owner);
+	}
+}
+
+static const char *check_name_cache(const char *name)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, name) != 0)
+			continue;
+
+		return data->owner;
+	}
+
+	return NULL;
+}
+
 static DBusHandlerResult service_filter(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -375,6 +430,8 @@ static DBusHandlerResult service_filter(DBusConnection *connection,
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
+	update_name_cache(name, new);
+
 	while (data->callbacks) {
 		cb = data->callbacks->data;
 
@@ -421,7 +478,9 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	member = dbus_message_get_member(message);
 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-	data = filter_data_find(connection, sender, path, iface, member, arg);
+	/* Sender is always bus name */
+	data = filter_data_find(connection, NULL, sender, path, iface, member,
+					arg);
 	if (!data) {
 		error("Got %s.%s signal which has no listeners", iface, member);
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -446,7 +505,8 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	filter_data_free(data);
 
 	/* Remove filter if there no listener left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -456,16 +516,37 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 
 struct service_data {
 	DBusConnection *conn;
+	char *name;
+	const char *owner;
 	GDBusWatchFunction conn_func;
 	void *user_data;
 };
 
+static void service_data_free(struct service_data *data)
+{
+	dbus_connection_unref(data->conn);
+	g_free(data->name);
+	g_free(data);
+}
+
+static gboolean update_service(void *user_data)
+{
+	struct service_data *data = user_data;
+
+	update_name_cache(data->name, data->owner);
+	if (data->conn_func)
+		data->conn_func(data->conn, data->user_data);
+
+	service_data_free(data);
+
+	return FALSE;
+}
+
 static void service_reply(DBusPendingCall *call, void *user_data)
 {
 	struct service_data *data = user_data;
 	DBusMessage *reply;
 	DBusError error;
-	dbus_bool_t has_owner;
 
 	reply = dbus_pending_call_steal_reply(call);
 	if (reply == NULL)
@@ -474,22 +555,23 @@ static void service_reply(DBusPendingCall *call, void *user_data)
 	dbus_error_init(&error);
 
 	if (dbus_message_get_args(reply, &error,
-					DBUS_TYPE_BOOLEAN, &has_owner,
+					DBUS_TYPE_STRING, &data->owner,
 						DBUS_TYPE_INVALID) == FALSE) {
 		if (dbus_error_is_set(&error) == TRUE) {
 			error("%s", error.message);
 			dbus_error_free(&error);
 		} else {
-			error("Wrong arguments for NameHasOwner reply");
+			error("Wrong arguments for GetNameOwner reply");
 		}
 		goto done;
 	}
 
-	if (has_owner && data->conn_func)
-		data->conn_func(data->conn, data->user_data);
+	update_service(data);
 
+	return;
 done:
 	dbus_message_unref(reply);
+	service_data_free(data);
 }
 
 static void check_service(DBusConnection *connection, const char *name,
@@ -505,12 +587,19 @@ static void check_service(DBusConnection *connection, const char *name,
 		return;
 	}
 
-	data->conn = connection;
+	data->conn = dbus_connection_ref(connection);
+	data->name = g_strdup(name);
 	data->conn_func = connect;
 	data->user_data = user_data;
 
+	data->owner = check_name_cache(name);
+	if (data->owner != NULL) {
+		g_idle_add(update_service, data);
+		return;
+	}
+
 	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
+			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
 	if (message == NULL) {
 		error("Can't allocate new message");
 		g_free(data);
@@ -596,6 +685,11 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
 	if (!cb)
 		return 0;
 
+	if (data->name != NULL && data->name_watch == 0)
+		data->name_watch = g_dbus_add_service_watch(connection,
+							data->name, NULL,
+							NULL, NULL, NULL);
+
 	return cb->id;
 }
 
@@ -625,7 +719,8 @@ void g_dbus_remove_all_watches(DBusConnection *connection)
 {
 	struct filter_data *data;
 
-	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL))) {
+	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
+					NULL, NULL))) {
 		listeners = g_slist_remove(listeners, data);
 		filter_data_call_and_free(data);
 	}
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH] Fix signal watch when a service name is given
From: Luiz Augusto von Dentz @ 2010-02-16 14:59 UTC (permalink / raw)
  To: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 131 bytes --]

Hi,

This should fix g_dbus_add_signal_watch when a service like org.bluez is given.

-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0002-Fix-signal-watch-when-a-service-name-is-given.patch --]
[-- Type: text/x-patch, Size: 9342 bytes --]

From dfceaaa8e068f4703dcad27db71bec9d649c7267 Mon Sep 17 00:00:00 2001
From: Luiz Augusto Von Dentz <luiz.dentz-von@nokia.com>
Date: Tue, 16 Feb 2010 16:55:35 +0200
Subject: [PATCH 2/2] Fix signal watch when a service name is given

The bus name should be resolved when adding a watch by service name since
messages do always come with sender set to owner's bus name, also it
should listen to owner updates since it can change without invalidating
the watch.
---
 gdbus/watch.c |  139 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 117 insertions(+), 22 deletions(-)

diff --git a/gdbus/watch.c b/gdbus/watch.c
index 1d479fa..23c2b55 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -55,19 +55,22 @@ struct filter_callback {
 struct filter_data {
 	DBusConnection *connection;
 	DBusHandleMessageFunction handle_func;
-	char *sender;
+	char *name;
+	char *owner;
 	char *path;
 	char *interface;
 	char *member;
 	char *argument;
 	GSList *callbacks;
 	GSList *processed;
+	guint name_watch;
 	gboolean lock;
 	gboolean registered;
 };
 
 static struct filter_data *filter_data_find(DBusConnection *connection,
-							const char *sender,
+							const char *name,
+							const char *owner,
 							const char *path,
 							const char *interface,
 							const char *member,
@@ -82,8 +85,12 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 		if (connection != data->connection)
 			continue;
 
-		if (sender && data->sender &&
-				g_str_equal(sender, data->sender) == FALSE)
+		if (name && data->name &&
+				g_str_equal(name, data->name) == FALSE)
+			continue;
+
+		if (owner && data->owner &&
+				g_str_equal(owner, data->owner) == FALSE)
 			continue;
 
 		if (path && data->path &&
@@ -110,13 +117,15 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
 
 static void format_rule(struct filter_data *data, char *rule, size_t size)
 {
+	const char *sender;
 	int offset;
 
 	offset = snprintf(rule, size, "type='signal'");
+	sender = data->name ? : data->owner;
 
-	if (data->sender)
+	if (sender)
 		offset += snprintf(rule + offset, size - offset,
-				",sender='%s'", data->sender);
+				",sender='%s'", sender);
 	if (data->path)
 		offset += snprintf(rule + offset, size - offset,
 				",path='%s'", data->path);
@@ -183,8 +192,10 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 					const char *argument)
 {
 	struct filter_data *data;
+	const char *name = NULL, *owner = NULL;
 
-	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL)) {
+	if (!filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+				NULL)) {
 		if (!dbus_connection_add_filter(connection,
 					message_filter, NULL, NULL)) {
 			error("dbus_connection_add_filter() failed");
@@ -192,15 +203,25 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 		}
 	}
 
-	data = filter_data_find(connection, sender, path, interface, member,
-					argument);
+	if (sender == NULL)
+		goto proceed;
+
+	if (sender[0] == ':')
+		owner = sender;
+	else
+		name = sender;
+
+proceed:
+	data = filter_data_find(connection, name, owner, path, interface,
+					member, argument);
 	if (data)
 		return data;
 
 	data = g_new0(struct filter_data, 1);
 
 	data->connection = dbus_connection_ref(connection);
-	data->sender = g_strdup(sender);
+	data->name = name ? g_strdup(name) : NULL;
+	data->owner = owner ? g_strdup(owner) : NULL;
 	data->path = g_strdup(path);
 	data->interface = g_strdup(interface);
 	data->member = g_strdup(member);
@@ -244,7 +265,9 @@ static void filter_data_free(struct filter_data *data)
 		g_free(l->data);
 
 	g_slist_free(data->callbacks);
-	g_free(data->sender);
+	g_dbus_remove_watch(data->connection, data->name_watch);
+	g_free(data->name);
+	g_free(data->owner);
 	g_free(data->path);
 	g_free(data->interface);
 	g_free(data->member);
@@ -322,7 +345,8 @@ static gboolean filter_data_remove_callback(struct filter_data *data,
 	filter_data_free(data);
 
 	/* Remove filter if there are no listeners left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -359,6 +383,37 @@ static DBusHandlerResult signal_filter(DBusConnection *connection,
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+static void update_name_cache(const char *service, const char *name)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, service) != 0)
+			continue;
+
+		g_free(data->name);
+		data->owner = g_strdup(name);
+	}
+}
+
+static const char *check_name_cache(const char *service)
+{
+	GSList *l;
+
+	for (l = listeners; l != NULL; l = l->next) {
+		struct filter_data *data = l->data;
+
+		if (g_strcmp0(data->name, service) != 0)
+			continue;
+
+		return data->name;
+	}
+
+	return NULL;
+}
+
 static DBusHandlerResult service_filter(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -375,6 +430,8 @@ static DBusHandlerResult service_filter(DBusConnection *connection,
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 	}
 
+	update_name_cache(name, new);
+
 	while (data->callbacks) {
 		cb = data->callbacks->data;
 
@@ -421,7 +478,9 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	member = dbus_message_get_member(message);
 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-	data = filter_data_find(connection, sender, path, iface, member, arg);
+	/* Sender is always bus name */
+	data = filter_data_find(connection, NULL, sender, path, iface, member,
+					arg);
 	if (!data) {
 		error("Got %s.%s signal which has no listeners", iface, member);
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -446,7 +505,8 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	filter_data_free(data);
 
 	/* Remove filter if there no listener left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL);
+	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
+					NULL);
 	if (!data)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
@@ -456,16 +516,37 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 
 struct service_data {
 	DBusConnection *conn;
+	char *name;
+	const char *owner;
 	GDBusWatchFunction conn_func;
 	void *user_data;
 };
 
+static void service_data_free(struct service_data *data)
+{
+	dbus_connection_unref(data->conn);
+	g_free(data->name);
+	g_free(data);
+}
+
+static gboolean update_service(void *user_data)
+{
+	struct service_data *data = user_data;
+
+	update_name_cache(data->name, data->owner);
+	if (data->conn_func)
+		data->conn_func(data->conn, data->user_data);
+
+	service_data_free(data);
+
+	return FALSE;
+}
+
 static void service_reply(DBusPendingCall *call, void *user_data)
 {
 	struct service_data *data = user_data;
 	DBusMessage *reply;
 	DBusError error;
-	dbus_bool_t has_owner;
 
 	reply = dbus_pending_call_steal_reply(call);
 	if (reply == NULL)
@@ -474,22 +555,23 @@ static void service_reply(DBusPendingCall *call, void *user_data)
 	dbus_error_init(&error);
 
 	if (dbus_message_get_args(reply, &error,
-					DBUS_TYPE_BOOLEAN, &has_owner,
+					DBUS_TYPE_STRING, &data->owner,
 						DBUS_TYPE_INVALID) == FALSE) {
 		if (dbus_error_is_set(&error) == TRUE) {
 			error("%s", error.message);
 			dbus_error_free(&error);
 		} else {
-			error("Wrong arguments for NameHasOwner reply");
+			error("Wrong arguments for GetNameOwner reply");
 		}
 		goto done;
 	}
 
-	if (has_owner && data->conn_func)
-		data->conn_func(data->conn, data->user_data);
+	update_service(data);
 
+	return;
 done:
 	dbus_message_unref(reply);
+	service_data_free(data);
 }
 
 static void check_service(DBusConnection *connection, const char *name,
@@ -505,12 +587,19 @@ static void check_service(DBusConnection *connection, const char *name,
 		return;
 	}
 
-	data->conn = connection;
+	data->conn = dbus_connection_ref(connection);
+	data->name = g_strdup(name);
 	data->conn_func = connect;
 	data->user_data = user_data;
 
+	data->owner = check_name_cache(name);
+	if (data->owner != NULL) {
+		g_idle_add(update_service, data);
+		return;
+	}
+
 	message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
-			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameHasOwner");
+			DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
 	if (message == NULL) {
 		error("Can't allocate new message");
 		g_free(data);
@@ -596,6 +685,11 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
 	if (!cb)
 		return 0;
 
+	if (data->name != NULL && data->name_watch == 0)
+		data->name_watch = g_dbus_add_service_watch(connection,
+							data->name, NULL,
+							NULL, NULL, NULL);
+
 	return cb->id;
 }
 
@@ -625,7 +719,8 @@ void g_dbus_remove_all_watches(DBusConnection *connection)
 {
 	struct filter_data *data;
 
-	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL))) {
+	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
+					NULL, NULL))) {
 		listeners = g_slist_remove(listeners, data);
 		filter_data_call_and_free(data);
 	}
-- 
1.6.3.3


^ permalink raw reply related

* [PATCH] Fix bug on ftp plugin when mimetype exists but is unknown
From: Luiz Augusto von Dentz @ 2010-02-16 14:37 UTC (permalink / raw)
  To: linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 229 bytes --]

Hi,

The code was returning FALSE (0) when it should return a posix error thus
causing a unkown mimetype to not be handle by mimetype drivers as it
should.

ps: obexd patch

Regards,

-- 
Luiz Augusto von Dentz
Computer Engineer

[-- Attachment #2: 0001-Fix-bug-on-ftp-plugin-when-mimetype-exists-but-is-un.patch --]
[-- Type: text/x-patch, Size: 893 bytes --]

From 74a67587e3f30788c714582cce8f2f790465261e Mon Sep 17 00:00:00 2001
From: Luiz Augusto Von Dentz <luiz.dentz-von@nokia.com>
Date: Mon, 15 Feb 2010 13:33:06 +0200
Subject: [PATCH] Fix bug on ftp plugin when mimetype exists but is unknown

The code was returning FALSE (0) when it should return a posix error thus
causing a unkown mimetype to not be handle by mimetype drivers as it
should.
---
 plugins/ftp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/plugins/ftp.c b/plugins/ftp.c
index f15597e..e0a3b97 100644
--- a/plugins/ftp.c
+++ b/plugins/ftp.c
@@ -155,7 +155,7 @@ static gint get_by_type(struct obex_session *os, gchar *type, size_t *size)
 	if (g_str_equal(type, LST_TYPE))
 		return os_prepare_get(os, os->current_folder, size);
 
-	return FALSE;
+	return -ENOENT;
 }
 
 static gint ftp_prepare_get(struct obex_session *os, gchar *file,
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH 0/2] Provide a driver for the Apple Magic Mouse - opps
From: Jiri Kosina @ 2010-02-16 12:57 UTC (permalink / raw)
  To: Ed Tomlinson
  Cc: Dmitry Torokhov, Michael Poole, linux-input, Marcel Holtmann,
	linux-bluetooth, linux-kernel
In-Reply-To: <201002150744.51730.edt@aei.ca>

On Mon, 15 Feb 2010, Ed Tomlinson wrote:

> > Almost... you need to do hid_hw_stop() first and only then unregister
> > input device, Otherwise if you unload the module while moving the mouse
> > it is likely to still oops.
> 
> How about this?  It applies on top of yesterdays patch.
> 
> Ed
> 
> ---
> diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
> index 7d252d2..46fdeee 100644
> --- a/drivers/hid/hid-magicmouse.c
> +++ b/drivers/hid/hid-magicmouse.c
> @@ -430,8 +430,8 @@ static void magicmouse_remove(struct hid_device *hdev)
>  {
>  	struct magicmouse_sc *msc;
>  	msc = hid_get_drvdata(hdev);
> -	input_unregister_device(msc->input);
>  	hid_hw_stop(hdev);
> +	input_unregister_device(msc->input);
>  	kfree(msc);
>  }

This looks OK.

Could you please send it altogether with short changelog entry and 
Signed-off-by line so that I could queue that up?

Thanks,

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply

* Re: [PATCH 0/2] Provide a driver for the Apple Magic Mouse - opps
From: Jiri Kosina @ 2010-02-16 12:55 UTC (permalink / raw)
  To: Ed Tomlinson
  Cc: Dmitry Torokhov, Michael Poole, linux-input, Marcel Holtmann,
	linux-bluetooth, linux-kernel
In-Reply-To: <201002160734.47588.edt@aei.ca>

On Tue, 16 Feb 2010, Ed Tomlinson wrote:

> > Almost... you need to do hid_hw_stop() first and only then unregister
> > input device, Otherwise if you unload the module while moving the mouse
> > it is likely to still oops.
> 
> The exit routing for the module also has a hid_hw_stop.  Is it going to cause
> problems when it gets called twice?

The routine wasn't probably meant/designed with re-entrancy in mind, but 
looking quickly at all the subsequent callpaths, I don't see why it should 
cause any problem, as skb_queue_purge(), usb_kill_urb() and usb_free_urb() 
should be safe.

Maybe we should even add test_bit() for HID_STARTED and HID_DISCONNECTED 
at the beginning of the low-level drivers' ->stop callbacks, so that we 
don't do all the magic when all the work has been already done.

-- 
Jiri Kosina
SUSE Labs, Novell Inc.

^ permalink raw reply

* Unable to change speaker and microphone gain
From: nirav rabara @ 2010-02-16 12:45 UTC (permalink / raw)
  To: linux-bluetooth

Hi,
Using D-Bus API (SetSpeakerGain() & SetMicrophoneGain()) I am changing
the speaker & microphone gain of Headset.
Whenever I use this API to change the gain value , Signal
SpeakerGainChanged & MicrophoneGainChanged emitted by bluetoothd, It
shows me the same value as I have set.
i.e if I set speakergain to 10, signal SpeakerGainChanged shows me 10.
But it doesn't affect the HS actual gain(i.e. on impact on actual
voice on HS ) it remains as it is.

Can somebody suggest me what I am missing??

-- 
With Regards,
Nirav Rabara

^ permalink raw reply

* Re: [PATCH 0/2] Provide a driver for the Apple Magic Mouse - opps
From: Ed Tomlinson @ 2010-02-16 12:34 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jiri Kosina, Michael Poole, linux-input, Marcel Holtmann,
	linux-bluetooth, linux-kernel
In-Reply-To: <20100215071145.GA9135@core.coreip.homeip.net>

On Monday 15 February 2010 02:11:46 Dmitry Torokhov wrote:
> Almost... you need to do hid_hw_stop() first and only then unregister
> input device, Otherwise if you unload the module while moving the mouse
> it is likely to still oops.

The exit routing for the module also has a hid_hw_stop.  Is it going to cause
problems when it gets called twice?

TIA
Ed

^ permalink raw reply

* Re: [PATCH] Bluetooth: Fix kernel crash on BT stress tests.
From: Andrei Emeltchenko @ 2010-02-16 12:16 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth
In-Reply-To: <508e92ca1002160358g1c6b599bo329f4f51cae18041@mail.gmail.com>

Hi Gustavo,

>> Are you using ERTM or Streaming mode? If yes, I have a guess about the
>> source of the problem. On l2cap_parse_conf_rsp we check for:
>>
>>        while (len >= L2CAP_CONF_OPT_SIZE) {
>>                len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
>>
>> But on case L2CAP_CONF_RFC olen is greater than L2CAP_CONF_OPT_SIZE we
>> can exceed the buffer size. So the right fix will be check if len >=
>> olen in that case.
>
> We use test tool which sends "Configure Response" packet with size 262
> bytes. So "req" buffer gets overwritten. But in the code nobody checks
> that "req" might be overwritten.

The packet we are sending is:

Bluetooth L2CAP Packet
    Length: 266
    CID: 0x0001
    Command: Configure Response
        Command Code: Configure Response (0x05)
        Command Identifier: 0x02
        Command Length: 262
        Source CID: 0x0040
        .... .... .... ...0 = Continuation Flag: False
        Result: Failure - unacceptable parameters (0x0001)
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
        Option: MTU
.............

We can check of course that parameter MTU is already exist. Still
there is possibility to overwrite 64 bytes of req buffer so some check
is needed.

-- Andrei

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox