Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 23 Oct 2007 02:22:33 +0000 (19:22 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 23 Oct 2007 02:22:33 +0000 (19:22 -0700)
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (30 commits)
  [IPSEC] IPV6: Fix to add tunnel mode SA correctly.
  [NET]: Cut off the queue_mapping field from sk_buff
  [NET]: Hide the queue_mapping field inside netif_subqueue_stopped
  [NET]: Make and use skb_get_queue_mapping
  [NET]: Use the skb_set_queue_mapping where appropriate
  [INET]: Use MODULE_ALIAS_NET_PF_PROTO_TYPE where possible.
  [INET]: Let inet_diag and friends autoload
  [NIU]: Cleanup PAGE_SIZE checks a bit
  [NET]: Fix SKB_WITH_OVERHEAD calculation
  [ATM]: Fix clip module reload crash.
  [TG3]: Update version to 3.85
  [TG3]: PCI command adjustment
  [TG3]: Add management FW version to ethtool report
  [TG3]: Add 5723 support
  [Bluetooth] Convert RFCOMM to use kthread API
  [Bluetooth] Add constant for Bluetooth socket options level
  [Bluetooth] Add support for handling simple eSCO links
  [Bluetooth] Add address and channel attribute to RFCOMM TTY device
  [Bluetooth] Fix wrong argument in debug code of HIDP
  [Bluetooth] Add generic driver for Bluetooth USB devices
  ...

47 files changed:
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btsdio.c [new file with mode: 0644]
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c [new file with mode: 0644]
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_bcsp.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_ll.c [new file with mode: 0644]
drivers/bluetooth/hci_uart.h
drivers/net/cpmac.c
drivers/net/niu.c
drivers/net/tg3.c
drivers/net/tg3.h
include/linux/net.h
include/linux/netdevice.h
include/linux/pci_ids.h
include/linux/skbuff.h
include/linux/socket.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/core/dev.c
net/core/neighbour.c
net/core/netpoll.c
net/core/pktgen.c
net/dccp/diag.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ipv4/inet_diag.c
net/ipv4/tcp_diag.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/sched/sch_teql.c

index b9fbe6e..075598e 100644 (file)
@@ -22,6 +22,30 @@ config BT_HCIUSB_SCO
 
          Say Y here to compile support for SCO over HCI USB.
 
+config BT_HCIBTUSB
+       tristate "HCI USB driver (alternate version)"
+       depends on USB && EXPERIMENTAL && BT_HCIUSB=n
+       help
+         Bluetooth HCI USB driver.
+         This driver is required if you want to use Bluetooth devices with
+         USB interface.
+
+          This driver is still experimental and has no SCO support.
+
+         Say Y here to compile support for Bluetooth USB devices into the
+         kernel or say M to compile it as module (btusb).
+
+config BT_HCIBTSDIO
+       tristate "HCI SDIO driver"
+       depends on MMC
+       help
+         Bluetooth HCI SDIO driver.
+         This driver is required if you want to use Bluetooth device with
+         SDIO interface.
+
+         Say Y here to compile support for Bluetooth SDIO devices into the
+         kernel or say M to compile it as module (btsdio).
+
 config BT_HCIUART
        tristate "HCI UART driver"
        help
@@ -55,6 +79,17 @@ config BT_HCIUART_BCSP
 
          Say Y here to compile support for HCI BCSP protocol.
 
+config BT_HCIUART_LL
+       bool "HCILL protocol support"
+       depends on BT_HCIUART
+       help
+         HCILL (HCI Low Level) is a serial protocol for communication
+         between Bluetooth device and host. This protocol is required for
+         serial Bluetooth devices that are based on Texas Instruments'
+         BRF chips.
+
+         Say Y here to compile support for HCILL protocol.
+
 config BT_HCIBCM203X
        tristate "HCI BCM203x USB driver"
        depends on USB
index 08c10e1..77444af 100644 (file)
@@ -13,7 +13,11 @@ obj-$(CONFIG_BT_HCIBT3C)     += bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)   += bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
 
+obj-$(CONFIG_BT_HCIBTUSB)      += btusb.o
+obj-$(CONFIG_BT_HCIBTSDIO)     += btsdio.o
+
 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-objs                          := $(hci_uart-y)
index 851de4d..bcf5792 100644 (file)
@@ -503,10 +503,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
        unsigned int iobase;
        unsigned char reg;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        if (!test_bit(CARD_READY, &(info->hw_state)))
                return IRQ_HANDLED;
index e8ebd5d..1375b53 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Digianswer Bluetooth USB driver
  *
- *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#include <linux/module.h>
-
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/types.h>
+#include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/skbuff.h>
 
 #include <linux/usb.h>
 
@@ -39,7 +40,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.8"
+#define VERSION "0.9"
 
 static int ignore = 0;
 
@@ -52,393 +53,285 @@ static struct usb_device_id bpa10x_table[] = {
 
 MODULE_DEVICE_TABLE(usb, bpa10x_table);
 
-#define BPA10X_CMD_EP          0x00
-#define BPA10X_EVT_EP          0x81
-#define BPA10X_TX_EP           0x02
-#define BPA10X_RX_EP           0x82
-
-#define BPA10X_CMD_BUF_SIZE    252
-#define BPA10X_EVT_BUF_SIZE    16
-#define BPA10X_TX_BUF_SIZE     384
-#define BPA10X_RX_BUF_SIZE     384
-
 struct bpa10x_data {
-       struct hci_dev          *hdev;
-       struct usb_device       *udev;
+       struct hci_dev    *hdev;
+       struct usb_device *udev;
 
-       rwlock_t                lock;
+       struct usb_anchor tx_anchor;
+       struct usb_anchor rx_anchor;
 
-       struct sk_buff_head     cmd_queue;
-       struct urb              *cmd_urb;
-       struct urb              *evt_urb;
-       struct sk_buff          *evt_skb;
-       unsigned int            evt_len;
-
-       struct sk_buff_head     tx_queue;
-       struct urb              *tx_urb;
-       struct urb              *rx_urb;
+       struct sk_buff *rx_skb[2];
 };
 
-#define HCI_VENDOR_HDR_SIZE    5
+#define HCI_VENDOR_HDR_SIZE 5
 
 struct hci_vendor_hdr {
-       __u8    type;
-       __le16  snum;
-       __le16  dlen;
+       __u8    type;
+       __le16  snum;
+       __le16  dlen;
 } __attribute__ ((packed));
 
-static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
+static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
 {
-       struct hci_acl_hdr *ah;
-       struct hci_sco_hdr *sh;
-       struct hci_vendor_hdr *vh;
-       struct sk_buff *skb;
-       int len;
+       struct bpa10x_data *data = hdev->driver_data;
+
+       BT_DBG("%s queue %d buffer %p count %d", hdev->name,
+                                                       queue, buf, count);
+
+       if (queue < 0 || queue > 1)
+               return -EILSEQ;
+
+       hdev->stat.byte_rx += count;
 
        while (count) {
-               switch (*buf++) {
-               case HCI_ACLDATA_PKT:
-                       ah = (struct hci_acl_hdr *) buf;
-                       len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
-                       skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-                               hci_recv_frame(skb);
-                       }
-                       break;
+               struct sk_buff *skb = data->rx_skb[queue];
+               struct { __u8 type; int expect; } *scb;
+               int type, len = 0;
 
-               case HCI_SCODATA_PKT:
-                       sh = (struct hci_sco_hdr *) buf;
-                       len = HCI_SCO_HDR_SIZE + sh->dlen;
-                       skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
-                               hci_recv_frame(skb);
+               if (!skb) {
+                       /* Start of the frame */
+
+                       type = *((__u8 *) buf);
+                       count--; buf++;
+
+                       switch (type) {
+                       case HCI_EVENT_PKT:
+                               if (count >= HCI_EVENT_HDR_SIZE) {
+                                       struct hci_event_hdr *h = buf;
+                                       len = HCI_EVENT_HDR_SIZE + h->plen;
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_ACLDATA_PKT:
+                               if (count >= HCI_ACL_HDR_SIZE) {
+                                       struct hci_acl_hdr *h = buf;
+                                       len = HCI_ACL_HDR_SIZE +
+                                                       __le16_to_cpu(h->dlen);
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_SCODATA_PKT:
+                               if (count >= HCI_SCO_HDR_SIZE) {
+                                       struct hci_sco_hdr *h = buf;
+                                       len = HCI_SCO_HDR_SIZE + h->dlen;
+                               } else
+                                       return -EILSEQ;
+                               break;
+
+                       case HCI_VENDOR_PKT:
+                               if (count >= HCI_VENDOR_HDR_SIZE) {
+                                       struct hci_vendor_hdr *h = buf;
+                                       len = HCI_VENDOR_HDR_SIZE +
+                                                       __le16_to_cpu(h->dlen);
+                               } else
+                                       return -EILSEQ;
+                               break;
                        }
-                       break;
 
-               case HCI_VENDOR_PKT:
-                       vh = (struct hci_vendor_hdr *) buf;
-                       len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
                        skb = bt_skb_alloc(len, GFP_ATOMIC);
-                       if (skb) {
-                               memcpy(skb_put(skb, len), buf, len);
-                               skb->dev = (void *) data->hdev;
-                               bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
-                               hci_recv_frame(skb);
+                       if (!skb) {
+                               BT_ERR("%s no memory for packet", hdev->name);
+                               return -ENOMEM;
                        }
-                       break;
-
-               default:
-                       len = count - 1;
-                       break;
-               }
 
-               buf   += len;
-               count -= (len + 1);
-       }
-}
-
-static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
-{
-       BT_DBG("data %p buf %p size %d", data, buf, size);
+                       skb->dev = (void *) hdev;
 
-       if (data->evt_skb) {
-               struct sk_buff *skb = data->evt_skb;
+                       data->rx_skb[queue] = skb;
 
-               memcpy(skb_put(skb, size), buf, size);
+                       scb = (void *) skb->cb;
+                       scb->type = type;
+                       scb->expect = len;
+               } else {
+                       /* Continuation */
 
-               if (skb->len == data->evt_len) {
-                       data->evt_skb = NULL;
-                       data->evt_len = 0;
-                       hci_recv_frame(skb);
-               }
-       } else {
-               struct sk_buff *skb;
-               struct hci_event_hdr *hdr;
-               unsigned char pkt_type;
-               int pkt_len = 0;
-
-               if (size < HCI_EVENT_HDR_SIZE + 1) {
-                       BT_ERR("%s event packet block with size %d is too short",
-                                                       data->hdev->name, size);
-                       return -EILSEQ;
+                       scb = (void *) skb->cb;
+                       len = scb->expect;
                }
 
-               pkt_type = *buf++;
-               size--;
-
-               if (pkt_type != HCI_EVENT_PKT) {
-                       BT_ERR("%s unexpected event packet start byte 0x%02x",
-                                                       data->hdev->name, pkt_type);
-                       return -EPROTO;
-               }
+               len = min(len, count);
 
-               hdr = (struct hci_event_hdr *) buf;
-               pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+               memcpy(skb_put(skb, len), buf, len);
 
-               skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
-               if (!skb) {
-                       BT_ERR("%s no memory for new event packet",
-                                                       data->hdev->name);
-                       return -ENOMEM;
-               }
+               scb->expect -= len;
 
-               skb->dev = (void *) data->hdev;
-               bt_cb(skb)->pkt_type = pkt_type;
+               if (scb->expect == 0) {
+                       /* Complete frame */
 
-               memcpy(skb_put(skb, size), buf, size);
+                       data->rx_skb[queue] = NULL;
 
-               if (pkt_len == size) {
+                       bt_cb(skb)->pkt_type = scb->type;
                        hci_recv_frame(skb);
-               } else {
-                       data->evt_skb = skb;
-                       data->evt_len = pkt_len;
                }
+
+               count -= len; buf += len;
        }
 
        return 0;
 }
 
-static void bpa10x_wakeup(struct bpa10x_data *data)
+static void bpa10x_tx_complete(struct urb *urb)
 {
-       struct urb *urb;
-       struct sk_buff *skb;
-       int err;
+       struct sk_buff *skb = urb->context;
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
 
-       BT_DBG("data %p", data);
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
 
-       urb = data->cmd_urb;
-       if (urb->status == -EINPROGRESS)
-               skb = NULL;
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               goto done;
+
+       if (!urb->status)
+               hdev->stat.byte_tx += urb->transfer_buffer_length;
        else
-               skb = skb_dequeue(&data->cmd_queue);
+               hdev->stat.err_tx++;
 
-       if (skb) {
-               struct usb_ctrlrequest *cr;
+done:
+       kfree(urb->setup_packet);
 
-               if (skb->len > BPA10X_CMD_BUF_SIZE) {
-                       BT_ERR("%s command packet with size %d is too big",
-                                                       data->hdev->name, skb->len);
-                       kfree_skb(skb);
-                       return;
-               }
+       kfree_skb(skb);
+}
+
+static void bpa10x_rx_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct bpa10x_data *data = hdev->driver_data;
+       int err;
 
-               cr = (struct usb_ctrlrequest *) urb->setup_packet;
-               cr->wLength = __cpu_to_le16(skb->len);
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
 
-               skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-               urb->transfer_buffer_length = skb->len;
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
 
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s submit failed for command urb %p with error %d",
-                                                       data->hdev->name, urb, err);
-                       skb_queue_head(&data->cmd_queue, skb);
-               } else
-                       kfree_skb(skb);
+       if (urb->status == 0) {
+               if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted event packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
        }
 
-       urb = data->tx_urb;
-       if (urb->status == -EINPROGRESS)
-               skb = NULL;
-       else
-               skb = skb_dequeue(&data->tx_queue);
-
-       if (skb) {
-               skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
-               urb->transfer_buffer_length = skb->len;
-
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s submit failed for command urb %p with error %d",
-                                                       data->hdev->name, urb, err);
-                       skb_queue_head(&data->tx_queue, skb);
-               } else
-                       kfree_skb(skb);
+       usb_anchor_urb(urb, &data->rx_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
        }
 }
 
-static void bpa10x_complete(struct urb *urb)
+static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
 {
-       struct bpa10x_data *data = urb->context;
-       unsigned char *buf = urb->transfer_buffer;
-       int err, count = urb->actual_length;
+       struct bpa10x_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size = 16;
 
-       BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
+       BT_DBG("%s", hdev->name);
 
-       read_lock(&data->lock);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return -ENOMEM;
 
-       if (!test_bit(HCI_RUNNING, &data->hdev->flags))
-               goto unlock;
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
 
-       if (urb->status < 0 || !count)
-               goto resubmit;
+       pipe = usb_rcvintpipe(data->udev, 0x81);
 
-       if (usb_pipein(urb->pipe)) {
-               data->hdev->stat.byte_rx += count;
+       usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+                                               bpa10x_rx_complete, hdev, 1);
 
-               if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
-                       bpa10x_recv_event(data, buf, count);
+       urb->transfer_flags |= URB_FREE_BUFFER;
 
-               if (usb_pipetype(urb->pipe) == PIPE_BULK)
-                       bpa10x_recv_bulk(data, buf, count);
-       } else {
-               data->hdev->stat.byte_tx += count;
+       usb_anchor_urb(urb, &data->rx_anchor);
 
-               bpa10x_wakeup(data);
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
        }
 
-resubmit:
-       if (usb_pipein(urb->pipe)) {
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err < 0 && err != -ENODEV) {
-                       BT_ERR("%s urb %p type %d resubmit status %d",
-                               data->hdev->name, urb, usb_pipetype(urb->pipe), err);
-               }
-       }
+       usb_free_urb(urb);
 
-unlock:
-       read_unlock(&data->lock);
+       return err;
 }
 
-static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
-                                       size_t size, gfp_t flags, void *data)
+static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
 {
+       struct bpa10x_data *data = hdev->driver_data;
        struct urb *urb;
-       struct usb_ctrlrequest *cr;
        unsigned char *buf;
+       unsigned int pipe;
+       int err, size = 64;
 
-       BT_DBG("udev %p data %p", udev, data);
+       BT_DBG("%s", hdev->name);
 
-       urb = usb_alloc_urb(0, flags);
+       urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!urb)
-               return NULL;
+               return -ENOMEM;
 
-       buf = kmalloc(size, flags);
+       buf = kmalloc(size, GFP_KERNEL);
        if (!buf) {
                usb_free_urb(urb);
-               return NULL;
+               return -ENOMEM;
        }
 
-       switch (usb_pipetype(pipe)) {
-       case PIPE_CONTROL:
-               cr = kmalloc(sizeof(*cr), flags);
-               if (!cr) {
-                       kfree(buf);
-                       usb_free_urb(urb);
-                       return NULL;
-               }
+       pipe = usb_rcvbulkpipe(data->udev, 0x82);
 
-               cr->bRequestType = USB_TYPE_VENDOR;
-               cr->bRequest     = 0;
-               cr->wIndex       = 0;
-               cr->wValue       = 0;
-               cr->wLength      = __cpu_to_le16(0);
+       usb_fill_bulk_urb(urb, data->udev, pipe,
+                                       buf, size, bpa10x_rx_complete, hdev);
 
-               usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
-               break;
+       urb->transfer_flags |= URB_FREE_BUFFER;
 
-       case PIPE_INTERRUPT:
-               usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
-               break;
+       usb_anchor_urb(urb, &data->rx_anchor);
 
-       case PIPE_BULK:
-               usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
-               break;
-
-       default:
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
                kfree(buf);
-               usb_free_urb(urb);
-               return NULL;
        }
 
-       return urb;
-}
-
-static inline void bpa10x_free_urb(struct urb *urb)
-{
-       BT_DBG("urb %p", urb);
-
-       if (!urb)
-               return;
-
-       kfree(urb->setup_packet);
-       kfree(urb->transfer_buffer);
-
        usb_free_urb(urb);
+
+       return err;
 }
 
 static int bpa10x_open(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
-       struct usb_device *udev = data->udev;
-       unsigned long flags;
        int err;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
        if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
-       data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
-                                       BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->cmd_urb) {
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
-                                       BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->evt_urb) {
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
-                                       BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->rx_urb) {
-               bpa10x_free_urb(data->evt_urb);
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
-
-       data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
-                                       BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
-       if (!data->rx_urb) {
-               bpa10x_free_urb(data->rx_urb);
-               bpa10x_free_urb(data->evt_urb);
-               bpa10x_free_urb(data->cmd_urb);
-               err = -ENOMEM;
-               goto done;
-       }
+       err = bpa10x_submit_intr_urb(hdev);
+       if (err < 0)
+               goto error;
 
-       write_lock_irqsave(&data->lock, flags);
+       err = bpa10x_submit_bulk_urb(hdev);
+       if (err < 0)
+               goto error;
 
-       err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
-       if (err < 0) {
-               BT_ERR("%s submit failed for event urb %p with error %d",
-                                       data->hdev->name, data->evt_urb, err);
-       } else {
-               err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
-               if (err < 0) {
-                       BT_ERR("%s submit failed for rx urb %p with error %d",
-                                       data->hdev->name, data->evt_urb, err);
-                       usb_kill_urb(data->evt_urb);
-               }
-       }
+       return 0;
 
-       write_unlock_irqrestore(&data->lock, flags);
+error:
+       usb_kill_anchored_urbs(&data->rx_anchor);
 
-done:
-       if (err < 0)
-               clear_bit(HCI_RUNNING, &hdev->flags);
+       clear_bit(HCI_RUNNING, &hdev->flags);
 
        return err;
 }
@@ -446,27 +339,13 @@ done:
 static int bpa10x_close(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
-       unsigned long flags;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
-       write_lock_irqsave(&data->lock, flags);
-
-       skb_queue_purge(&data->cmd_queue);
-       usb_kill_urb(data->cmd_urb);
-       usb_kill_urb(data->evt_urb);
-       usb_kill_urb(data->rx_urb);
-       usb_kill_urb(data->tx_urb);
-
-       write_unlock_irqrestore(&data->lock, flags);
-
-       bpa10x_free_urb(data->cmd_urb);
-       bpa10x_free_urb(data->evt_urb);
-       bpa10x_free_urb(data->rx_urb);
-       bpa10x_free_urb(data->tx_urb);
+       usb_kill_anchored_urbs(&data->rx_anchor);
 
        return 0;
 }
@@ -475,9 +354,9 @@ static int bpa10x_flush(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
-       skb_queue_purge(&data->cmd_queue);
+       usb_kill_anchored_urbs(&data->tx_anchor);
 
        return 0;
 }
@@ -485,45 +364,78 @@ static int bpa10x_flush(struct hci_dev *hdev)
 static int bpa10x_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-       struct bpa10x_data *data;
-
-       BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
+       struct bpa10x_data *data = hdev->driver_data;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       unsigned int pipe;
+       int err;
 
-       if (!hdev) {
-               BT_ERR("Frame for unknown HCI device");
-               return -ENODEV;
-       }
+       BT_DBG("%s", hdev->name);
 
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       data = hdev->driver_data;
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
 
        /* Prepend skb with frame type */
-       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+       *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
+               dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+               if (!dr) {
+                       usb_free_urb(urb);
+                       return -ENOMEM;
+               }
+
+               dr->bRequestType = USB_TYPE_VENDOR;
+               dr->bRequest     = 0;
+               dr->wIndex       = 0;
+               dr->wValue       = 0;
+               dr->wLength      = __cpu_to_le16(skb->len);
+
+               pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+               usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.cmd_tx++;
-               skb_queue_tail(&data->cmd_queue, skb);
                break;
 
        case HCI_ACLDATA_PKT:
+               pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.acl_tx++;
-               skb_queue_tail(&data->tx_queue, skb);
                break;
 
        case HCI_SCODATA_PKT:
+               pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, bpa10x_tx_complete, skb);
+
                hdev->stat.sco_tx++;
-               skb_queue_tail(&data->tx_queue, skb);
                break;
-       };
 
-       read_lock(&data->lock);
+       default:
+               return -EILSEQ;
+       }
+
+       usb_anchor_urb(urb, &data->tx_anchor);
 
-       bpa10x_wakeup(data);
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               kfree(urb->setup_packet);
+               usb_unanchor_urb(urb);
+       }
 
-       read_unlock(&data->lock);
+       usb_free_urb(urb);
 
        return 0;
 }
@@ -532,16 +444,17 @@ static void bpa10x_destruct(struct hci_dev *hdev)
 {
        struct bpa10x_data *data = hdev->driver_data;
 
-       BT_DBG("hdev %p data %p", hdev, data);
+       BT_DBG("%s", hdev->name);
 
+       kfree(data->rx_skb[0]);
+       kfree(data->rx_skb[1]);
        kfree(data);
 }
 
 static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct hci_dev *hdev;
        struct bpa10x_data *data;
+       struct hci_dev *hdev;
        int err;
 
        BT_DBG("intf %p id %p", intf, id);
@@ -549,48 +462,43 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        if (ignore)
                return -ENODEV;
 
-       if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               BT_ERR("Can't allocate data structure");
+       if (!data)
                return -ENOMEM;
-       }
-
-       data->udev = udev;
 
-       rwlock_init(&data->lock);
+       data->udev = interface_to_usbdev(intf);
 
-       skb_queue_head_init(&data->cmd_queue);
-       skb_queue_head_init(&data->tx_queue);
+       init_usb_anchor(&data->tx_anchor);
+       init_usb_anchor(&data->rx_anchor);
 
        hdev = hci_alloc_dev();
        if (!hdev) {
-               BT_ERR("Can't allocate HCI device");
                kfree(data);
                return -ENOMEM;
        }
 
-       data->hdev = hdev;
-
        hdev->type = HCI_USB;
        hdev->driver_data = data;
+
+       data->hdev = hdev;
+
        SET_HCIDEV_DEV(hdev, &intf->dev);
 
-       hdev->open      = bpa10x_open;
-       hdev->close     = bpa10x_close;
-       hdev->flush     = bpa10x_flush;
-       hdev->send      = bpa10x_send_frame;
-       hdev->destruct  = bpa10x_destruct;
+       hdev->open     = bpa10x_open;
+       hdev->close    = bpa10x_close;
+       hdev->flush    = bpa10x_flush;
+       hdev->send     = bpa10x_send_frame;
+       hdev->destruct = bpa10x_destruct;
 
        hdev->owner = THIS_MODULE;
 
        err = hci_register_dev(hdev);
        if (err < 0) {
-               BT_ERR("Can't register HCI device");
-               kfree(data);
                hci_free_dev(hdev);
+               kfree(data);
                return err;
        }
 
@@ -602,19 +510,17 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 static void bpa10x_disconnect(struct usb_interface *intf)
 {
        struct bpa10x_data *data = usb_get_intfdata(intf);
-       struct hci_dev *hdev = data->hdev;
 
        BT_DBG("intf %p", intf);
 
-       if (!hdev)
+       if (!data)
                return;
 
        usb_set_intfdata(intf, NULL);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
+       hci_unregister_dev(data->hdev);
 
-       hci_free_dev(hdev);
+       hci_free_dev(data->hdev);
 }
 
 static struct usb_driver bpa10x_driver = {
@@ -626,15 +532,9 @@ static struct usb_driver bpa10x_driver = {
 
 static int __init bpa10x_init(void)
 {
-       int err;
-
        BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
 
-       err = usb_register(&bpa10x_driver);
-       if (err < 0)
-               BT_ERR("Failed to register USB driver");
-
-       return err;
+       return usb_register(&bpa10x_driver);
 }
 
 static void __exit bpa10x_exit(void)
index 3951607..a18f9b8 100644 (file)
@@ -344,10 +344,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
        unsigned int iobase;
        int iir;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
new file mode 100644 (file)
index 0000000..b786f61
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ *
+ *  Generic Bluetooth SDIO driver
+ *
+ *  Copyright (C) 2007  Cambridge Silicon Radio Ltd.
+ *  Copyright (C) 2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static const struct sdio_device_id btsdio_table[] = {
+       /* Generic Bluetooth Type-A SDIO device */
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
+
+       /* Generic Bluetooth Type-B SDIO device */
+       { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
+
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btsdio_table);
+
+struct btsdio_data {
+       struct hci_dev   *hdev;
+       struct sdio_func *func;
+
+       struct work_struct work;
+
+       struct sk_buff_head txq;
+};
+
+#define REG_RDAT     0x00      /* Receiver Data */
+#define REG_TDAT     0x00      /* Transmitter Data */
+#define REG_PC_RRT   0x10      /* Read Packet Control */
+#define REG_PC_WRT   0x11      /* Write Packet Control */
+#define REG_RTC_STAT 0x12      /* Retry Control Status */
+#define REG_RTC_SET  0x12      /* Retry Control Set */
+#define REG_INTRD    0x13      /* Interrupt Indication */
+#define REG_CL_INTRD 0x13      /* Interrupt Clear */
+#define REG_EN_INTRD 0x14      /* Interrupt Enable */
+#define REG_MD_STAT  0x20      /* Bluetooth Mode Status */
+
+static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
+{
+       int err;
+
+       BT_DBG("%s", data->hdev->name);
+
+       /* Prepend Type-A header */
+       skb_push(skb, 4);
+       skb->data[0] = (skb->len & 0x0000ff);
+       skb->data[1] = (skb->len & 0x00ff00) >> 8;
+       skb->data[2] = (skb->len & 0xff0000) >> 16;
+       skb->data[3] = bt_cb(skb)->pkt_type;
+
+       err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
+       if (err < 0) {
+               sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
+               return err;
+       }
+
+       data->hdev->stat.byte_tx += skb->len;
+
+       kfree_skb(skb);
+
+       return 0;
+}
+
+static void btsdio_work(struct work_struct *work)
+{
+       struct btsdio_data *data = container_of(work, struct btsdio_data, work);
+       struct sk_buff *skb;
+       int err;
+
+       BT_DBG("%s", data->hdev->name);
+
+       sdio_claim_host(data->func);
+
+       while ((skb = skb_dequeue(&data->txq))) {
+               err = btsdio_tx_packet(data, skb);
+               if (err < 0) {
+                       data->hdev->stat.err_tx++;
+                       skb_queue_head(&data->txq, skb);
+                       break;
+               }
+       }
+
+       sdio_release_host(data->func);
+}
+
+static int btsdio_rx_packet(struct btsdio_data *data)
+{
+       u8 hdr[4] __attribute__ ((aligned(4)));
+       struct sk_buff *skb;
+       int err, len;
+
+       BT_DBG("%s", data->hdev->name);
+
+       err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
+       if (err < 0)
+               return err;
+
+       len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
+       if (len < 4 || len > 65543)
+               return -EILSEQ;
+
+       skb = bt_skb_alloc(len - 4, GFP_KERNEL);
+       if (!skb) {
+               /* Out of memory. Prepare a read retry and just
+                * return with the expectation that the next time
+                * we're called we'll have more memory. */
+               return -ENOMEM;
+       }
+
+       skb_put(skb, len - 4);
+
+       err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
+       if (err < 0) {
+               kfree(skb);
+               return err;
+       }
+
+       data->hdev->stat.byte_rx += len;
+
+       skb->dev = (void *) data->hdev;
+       bt_cb(skb)->pkt_type = hdr[3];
+
+       err = hci_recv_frame(skb);
+       if (err < 0) {
+               kfree(skb);
+               return err;
+       }
+
+       sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
+
+       return 0;
+}
+
+static void btsdio_interrupt(struct sdio_func *func)
+{
+       struct btsdio_data *data = sdio_get_drvdata(func);
+       int intrd;
+
+       BT_DBG("%s", data->hdev->name);
+
+       intrd = sdio_readb(func, REG_INTRD, NULL);
+       if (intrd & 0x01) {
+               sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
+
+               if (btsdio_rx_packet(data) < 0) {
+                       data->hdev->stat.err_rx++;
+                       sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
+               }
+       }
+}
+
+static int btsdio_open(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       sdio_claim_host(data->func);
+
+       err = sdio_enable_func(data->func);
+       if (err < 0) {
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               goto release;
+       }
+
+       err = sdio_claim_irq(data->func, btsdio_interrupt);
+       if (err < 0) {
+               sdio_disable_func(data->func);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               goto release;
+       }
+
+       if (data->func->class == SDIO_CLASS_BT_B)
+               sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+
+       sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
+
+release:
+       sdio_release_host(data->func);
+
+       return err;
+}
+
+static int btsdio_close(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       sdio_claim_host(data->func);
+
+       sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
+
+       sdio_release_irq(data->func);
+       sdio_disable_func(data->func);
+
+       sdio_release_host(data->func);
+
+       return 0;
+}
+
+static int btsdio_flush(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       skb_queue_purge(&data->txq);
+
+       return 0;
+}
+
+static int btsdio_send_frame(struct sk_buff *skb)
+{
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return -EBUSY;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               hdev->stat.cmd_tx++;
+               break;
+
+       case HCI_ACLDATA_PKT:
+               hdev->stat.acl_tx++;
+               break;
+
+       case HCI_SCODATA_PKT:
+               hdev->stat.sco_tx++;
+               break;
+
+       default:
+               return -EILSEQ;
+       }
+
+       skb_queue_tail(&data->txq, skb);
+
+       schedule_work(&data->work);
+
+       return 0;
+}
+
+static void btsdio_destruct(struct hci_dev *hdev)
+{
+       struct btsdio_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       kfree(data);
+}
+
+static int btsdio_probe(struct sdio_func *func,
+                               const struct sdio_device_id *id)
+{
+       struct btsdio_data *data;
+       struct hci_dev *hdev;
+       struct sdio_func_tuple *tuple = func->tuples;
+       int err;
+
+       BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
+
+       while (tuple) {
+               BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
+               tuple = tuple->next;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->func = func;
+
+       INIT_WORK(&data->work, btsdio_work);
+
+       skb_queue_head_init(&data->txq);
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               kfree(data);
+               return -ENOMEM;
+       }
+
+       hdev->type = HCI_SDIO;
+       hdev->driver_data = data;
+
+       data->hdev = hdev;
+
+       SET_HCIDEV_DEV(hdev, &func->dev);
+
+       hdev->open     = btsdio_open;
+       hdev->close    = btsdio_close;
+       hdev->flush    = btsdio_flush;
+       hdev->send     = btsdio_send_frame;
+       hdev->destruct = btsdio_destruct;
+
+       hdev->owner = THIS_MODULE;
+
+       err = hci_register_dev(hdev);
+       if (err < 0) {
+               hci_free_dev(hdev);
+               kfree(data);
+               return err;
+       }
+
+       sdio_set_drvdata(func, data);
+
+       return 0;
+}
+
+static void btsdio_remove(struct sdio_func *func)
+{
+       struct btsdio_data *data = sdio_get_drvdata(func);
+       struct hci_dev *hdev;
+
+       BT_DBG("func %p", func);
+
+       if (!data)
+               return;
+
+       hdev = data->hdev;
+
+       sdio_set_drvdata(func, NULL);
+
+       hci_unregister_dev(hdev);
+
+       hci_free_dev(hdev);
+}
+
+static struct sdio_driver btsdio_driver = {
+       .name           = "btsdio",
+       .probe          = btsdio_probe,
+       .remove         = btsdio_remove,
+       .id_table       = btsdio_table,
+};
+
+static int __init btsdio_init(void)
+{
+       BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
+
+       return sdio_register_driver(&btsdio_driver);
+}
+
+static void __exit btsdio_exit(void)
+{
+       sdio_unregister_driver(&btsdio_driver);
+}
+
+module_init(btsdio_init);
+module_exit(btsdio_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
index d7d2ea0..08f48d5 100644 (file)
@@ -294,10 +294,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
        int boguscount = 0;
        int iir, lsr;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
new file mode 100644 (file)
index 0000000..12e1089
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *
+ *  Generic Bluetooth USB driver
+ *
+ *  Copyright (C) 2005-2007  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+//#define CONFIG_BT_HCIBTUSB_DEBUG
+#ifndef CONFIG_BT_HCIBTUSB_DEBUG
+#undef  BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static struct usb_device_id btusb_table[] = {
+       /* Generic Bluetooth USB device */
+       { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, btusb_table);
+
+static struct usb_device_id blacklist_table[] = {
+       { }     /* Terminating entry */
+};
+
+#define BTUSB_INTR_RUNNING     0
+#define BTUSB_BULK_RUNNING     1
+
+struct btusb_data {
+       struct hci_dev       *hdev;
+       struct usb_device    *udev;
+
+       spinlock_t lock;
+
+       unsigned long flags;
+
+       struct work_struct work;
+
+       struct usb_anchor tx_anchor;
+       struct usb_anchor intr_anchor;
+       struct usb_anchor bulk_anchor;
+
+       struct usb_endpoint_descriptor *intr_ep;
+       struct usb_endpoint_descriptor *bulk_tx_ep;
+       struct usb_endpoint_descriptor *bulk_rx_ep;
+};
+
+static void btusb_intr_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
+
+       if (urb->status == 0) {
+               if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted event packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
+       }
+
+       if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
+               return;
+
+       usb_anchor_urb(urb, &data->intr_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+       }
+}
+
+static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size;
+
+       BT_DBG("%s", hdev->name);
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
+
+       size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
+
+       buf = kmalloc(size, GFP_ATOMIC);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
+
+       usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+                                               btusb_intr_complete, hdev,
+                                               data->intr_ep->bInterval);
+
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       usb_anchor_urb(urb, &data->intr_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_bulk_complete(struct urb *urb)
+{
+       struct hci_dev *hdev = urb->context;
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return;
+
+       if (urb->status == 0) {
+               if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
+                                               urb->transfer_buffer,
+                                               urb->actual_length) < 0) {
+                       BT_ERR("%s corrupted ACL packet", hdev->name);
+                       hdev->stat.err_rx++;
+               }
+       }
+
+       if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
+               return;
+
+       usb_anchor_urb(urb, &data->bulk_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p failed to resubmit (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+       }
+}
+
+static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size;
+
+       BT_DBG("%s", hdev->name);
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!urb)
+               return -ENOMEM;
+
+       size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
+
+       usb_fill_bulk_urb(urb, data->udev, pipe,
+                                       buf, size, btusb_bulk_complete, hdev);
+
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       usb_anchor_urb(urb, &data->bulk_anchor);
+
+       err = usb_submit_urb(urb, GFP_KERNEL);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
+               usb_unanchor_urb(urb);
+               kfree(buf);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_tx_complete(struct urb *urb)
+{
+       struct sk_buff *skb = urb->context;
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+       BT_DBG("%s urb %p status %d count %d", hdev->name,
+                                       urb, urb->status, urb->actual_length);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               goto done;
+
+       if (!urb->status)
+               hdev->stat.byte_tx += urb->transfer_buffer_length;
+       else
+               hdev->stat.err_tx++;
+
+done:
+       kfree(urb->setup_packet);
+
+       kfree_skb(skb);
+}
+
+static int btusb_open(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
+               return 0;
+
+       err = btusb_submit_intr_urb(hdev);
+       if (err < 0) {
+               clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+       }
+
+       return err;
+}
+
+static int btusb_close(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+       usb_kill_anchored_urbs(&data->bulk_anchor);
+
+       clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+       usb_kill_anchored_urbs(&data->intr_anchor);
+
+       return 0;
+}
+
+static int btusb_flush(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       usb_kill_anchored_urbs(&data->tx_anchor);
+
+       return 0;
+}
+
+static int btusb_send_frame(struct sk_buff *skb)
+{
+       struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+       struct btusb_data *data = hdev->driver_data;
+       struct usb_ctrlrequest *dr;
+       struct urb *urb;
+       unsigned int pipe;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return -EBUSY;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!urb)
+                       return -ENOMEM;
+
+               dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+               if (!dr) {
+                       usb_free_urb(urb);
+                       return -ENOMEM;
+               }
+
+               dr->bRequestType = USB_TYPE_CLASS;
+               dr->bRequest     = 0;
+               dr->wIndex       = 0;
+               dr->wValue       = 0;
+               dr->wLength      = __cpu_to_le16(skb->len);
+
+               pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+               usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+                               skb->data, skb->len, btusb_tx_complete, skb);
+
+               hdev->stat.cmd_tx++;
+               break;
+
+       case HCI_ACLDATA_PKT:
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!urb)
+                       return -ENOMEM;
+
+               pipe = usb_sndbulkpipe(data->udev,
+                                       data->bulk_tx_ep->bEndpointAddress);
+
+               usb_fill_bulk_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, btusb_tx_complete, skb);
+
+               hdev->stat.acl_tx++;
+               break;
+
+       case HCI_SCODATA_PKT:
+               hdev->stat.sco_tx++;
+               kfree_skb(skb);
+               return 0;
+
+       default:
+               return -EILSEQ;
+       }
+
+       usb_anchor_urb(urb, &data->tx_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0) {
+               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               kfree(urb->setup_packet);
+               usb_unanchor_urb(urb);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void btusb_destruct(struct hci_dev *hdev)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s", hdev->name);
+
+       kfree(data);
+}
+
+static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
+{
+       struct btusb_data *data = hdev->driver_data;
+
+       BT_DBG("%s evt %d", hdev->name, evt);
+
+       if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
+               schedule_work(&data->work);
+}
+
+static void btusb_work(struct work_struct *work)
+{
+       struct btusb_data *data = container_of(work, struct btusb_data, work);
+       struct hci_dev *hdev = data->hdev;
+
+       if (hdev->conn_hash.acl_num == 0) {
+               clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+               usb_kill_anchored_urbs(&data->bulk_anchor);
+               return;
+       }
+
+       if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+               if (btusb_submit_bulk_urb(hdev) < 0)
+                       clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+               else
+                       btusb_submit_bulk_urb(hdev);
+       }
+}
+
+static int btusb_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct usb_endpoint_descriptor *ep_desc;
+       struct btusb_data *data;
+       struct hci_dev *hdev;
+       int i, err;
+
+       BT_DBG("intf %p id %p", intf, id);
+
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+               return -ENODEV;
+
+       if (!id->driver_info) {
+               const struct usb_device_id *match;
+               match = usb_match_id(intf, blacklist_table);
+               if (match)
+                       id = match;
+       }
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+               ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+               if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
+                       data->intr_ep = ep_desc;
+                       continue;
+               }
+
+               if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
+                       data->bulk_tx_ep = ep_desc;
+                       continue;
+               }
+
+               if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
+                       data->bulk_rx_ep = ep_desc;
+                       continue;
+               }
+       }
+
+       if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
+               kfree(data);
+               return -ENODEV;
+       }
+
+       data->udev = interface_to_usbdev(intf);
+
+       spin_lock_init(&data->lock);
+
+       INIT_WORK(&data->work, btusb_work);
+
+       init_usb_anchor(&data->tx_anchor);
+       init_usb_anchor(&data->intr_anchor);
+       init_usb_anchor(&data->bulk_anchor);
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               kfree(data);
+               return -ENOMEM;
+       }
+
+       hdev->type = HCI_USB;
+       hdev->driver_data = data;
+
+       data->hdev = hdev;
+
+       SET_HCIDEV_DEV(hdev, &intf->dev);
+
+       hdev->open     = btusb_open;
+       hdev->close    = btusb_close;
+       hdev->flush    = btusb_flush;
+       hdev->send     = btusb_send_frame;
+       hdev->destruct = btusb_destruct;
+       hdev->notify   = btusb_notify;
+
+       hdev->owner = THIS_MODULE;
+
+       set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
+       err = hci_register_dev(hdev);
+       if (err < 0) {
+               hci_free_dev(hdev);
+               kfree(data);
+               return err;
+       }
+
+       usb_set_intfdata(intf, data);
+
+       return 0;
+}
+
+static void btusb_disconnect(struct usb_interface *intf)
+{
+       struct btusb_data *data = usb_get_intfdata(intf);
+       struct hci_dev *hdev;
+
+       BT_DBG("intf %p", intf);
+
+       if (!data)
+               return;
+
+       hdev = data->hdev;
+
+       usb_set_intfdata(intf, NULL);
+
+       hci_unregister_dev(hdev);
+
+       hci_free_dev(hdev);
+}
+
+static struct usb_driver btusb_driver = {
+       .name           = "btusb",
+       .probe          = btusb_probe,
+       .disconnect     = btusb_disconnect,
+       .id_table       = btusb_table,
+};
+
+static int __init btusb_init(void)
+{
+       BT_INFO("Generic Bluetooth USB driver ver %s", VERSION);
+
+       return usb_register(&btusb_driver);
+}
+
+static void __exit btusb_exit(void)
+{
+       usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
index 7f9c54b..dae45cd 100644 (file)
@@ -298,10 +298,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
        int boguscount = 0;
        int iir, lsr;
 
-       if (!info || !info->hdev) {
-               BT_ERR("Call of irq %d for unknown device", irq);
-               return IRQ_NONE;
-       }
+       BUG_ON(!info->hdev);
 
        iobase = info->p_dev->io.BasePort1;
 
index d66064c..696f752 100644 (file)
@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
        if (hciextn && chan == 5) {
                struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
 
-               if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
+               /* Vendor specific commands */
+               if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
                        u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
                        if ((desc & 0xf0) == 0xc0) {
                                data += HCI_COMMAND_HDR_SIZE + 1;
index 6055b9c..e68821d 100644 (file)
@@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
        bcsp_init();
 #endif
-       
+#ifdef CONFIG_BT_HCIUART_LL
+       ll_init();
+#endif
+
        return 0;
 }
 
@@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
 #ifdef CONFIG_BT_HCIUART_BCSP
        bcsp_deinit();
 #endif
+#ifdef CONFIG_BT_HCIUART_LL
+       ll_deinit();
+#endif
 
        /* Release tty registration of line discipline */
        if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
new file mode 100644 (file)
index 0000000..8c3e62a
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ *  Texas Instruments' Bluetooth HCILL UART protocol
+ *
+ *  HCILL (HCI Low Level) is a Texas Instruments' power management
+ *  protocol extension to H4.
+ *
+ *  Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ *  Written by Ohad Ben-Cohen <ohad@bencohen.org>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_h4.c, which was written
+ *  by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation
+ *
+ *  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 <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCILL commands */
+#define HCILL_GO_TO_SLEEP_IND  0x30
+#define HCILL_GO_TO_SLEEP_ACK  0x31
+#define HCILL_WAKE_UP_IND      0x32
+#define HCILL_WAKE_UP_ACK      0x33
+
+/* HCILL receiver States */
+#define HCILL_W4_PACKET_TYPE   0
+#define HCILL_W4_EVENT_HDR     1
+#define HCILL_W4_ACL_HDR       2
+#define HCILL_W4_SCO_HDR       3
+#define HCILL_W4_DATA          4
+
+/* HCILL states */
+enum hcill_states_e {
+       HCILL_ASLEEP,
+       HCILL_ASLEEP_TO_AWAKE,
+       HCILL_AWAKE,
+       HCILL_AWAKE_TO_ASLEEP
+};
+
+struct hcill_cmd {
+       u8 cmd;
+} __attribute__((packed));
+
+struct ll_struct {
+       unsigned long rx_state;
+       unsigned long rx_count;
+       struct sk_buff *rx_skb;
+       struct sk_buff_head txq;
+       spinlock_t hcill_lock;          /* HCILL state lock     */
+       unsigned long hcill_state;      /* HCILL power state    */
+       struct sk_buff_head tx_wait_q;  /* HCILL wait queue     */
+};
+
+/*
+ * Builds and sends an HCILL command packet.
+ * These are very simple packets with only 1 cmd byte
+ */
+static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
+{
+       int err = 0;
+       struct sk_buff *skb = NULL;
+       struct ll_struct *ll = hu->priv;
+       struct hcill_cmd *hcill_packet;
+
+       BT_DBG("hu %p cmd 0x%x", hu, cmd);
+
+       /* allocate packet */
+       skb = bt_skb_alloc(1, GFP_ATOMIC);
+       if (!skb) {
+               BT_ERR("cannot allocate memory for HCILL packet");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* prepare packet */
+       hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
+       hcill_packet->cmd = cmd;
+       skb->dev = (void *) hu->hdev;
+
+       /* send packet */
+       skb_queue_tail(&ll->txq, skb);
+out:
+       return err;
+}
+
+/* Initialize protocol */
+static int ll_open(struct hci_uart *hu)
+{
+       struct ll_struct *ll;
+
+       BT_DBG("hu %p", hu);
+
+       ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+       if (!ll)
+               return -ENOMEM;
+
+       skb_queue_head_init(&ll->txq);
+       skb_queue_head_init(&ll->tx_wait_q);
+       spin_lock_init(&ll->hcill_lock);
+
+       ll->hcill_state = HCILL_AWAKE;
+
+       hu->priv = ll;
+
+       return 0;
+}
+
+/* Flush protocol data */
+static int ll_flush(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ll->tx_wait_q);
+       skb_queue_purge(&ll->txq);
+
+       return 0;
+}
+
+/* Close protocol */
+static int ll_close(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       skb_queue_purge(&ll->tx_wait_q);
+       skb_queue_purge(&ll->txq);
+
+       if (ll->rx_skb)
+               kfree_skb(ll->rx_skb);
+
+       hu->priv = NULL;
+
+       kfree(ll);
+
+       return 0;
+}
+
+/*
+ * internal function, which does common work of the device wake up process:
+ * 1. places all pending packets (waiting in tx_wait_q list) in txq list.
+ * 2. changes internal state to HCILL_AWAKE.
+ * Note: assumes that hcill_lock spinlock is taken,
+ * shouldn't be called otherwise!
+ */
+static void __ll_do_awake(struct ll_struct *ll)
+{
+       struct sk_buff *skb = NULL;
+
+       while ((skb = skb_dequeue(&ll->tx_wait_q)))
+               skb_queue_tail(&ll->txq, skb);
+
+       ll->hcill_state = HCILL_AWAKE;
+}
+
+/*
+ * Called upon a wake-up-indication from the device
+ */
+static void ll_device_want_to_wakeup(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       switch (ll->hcill_state) {
+       case HCILL_ASLEEP:
+               /* acknowledge device wake up */
+               if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
+                       BT_ERR("cannot acknowledge device wake up");
+                       goto out;
+               }
+               break;
+       case HCILL_ASLEEP_TO_AWAKE:
+               /*
+                * this state means that a wake-up-indication
+                * is already on its way to the device,
+                * and will serve as the required wake-up-ack
+                */
+               BT_DBG("dual wake-up-indication");
+               break;
+       default:
+               /* any other state are illegal */
+               BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
+               break;
+       }
+
+       /* send pending packets and change state to HCILL_AWAKE */
+       __ll_do_awake(ll);
+
+out:
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the packets */
+       hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon a sleep-indication from the device
+ */
+static void ll_device_want_to_sleep(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* sanity check */
+       if (ll->hcill_state != HCILL_AWAKE)
+               BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
+
+       /* acknowledge device sleep */
+       if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
+               BT_ERR("cannot acknowledge device sleep");
+               goto out;
+       }
+
+       /* update state */
+       ll->hcill_state = HCILL_ASLEEP;
+
+out:
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the sleep ack packet */
+       hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon wake-up-acknowledgement from the device
+ */
+static void ll_device_woke_up(struct hci_uart *hu)
+{
+       unsigned long flags;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p", hu);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* sanity check */
+       if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
+               BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
+
+       /* send pending packets and change state to HCILL_AWAKE */
+       __ll_do_awake(ll);
+
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       /* actually send the packets */
+       hci_uart_tx_wakeup(hu);
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+       unsigned long flags = 0;
+       struct ll_struct *ll = hu->priv;
+
+       BT_DBG("hu %p skb %p", hu, skb);
+
+       /* Prepend skb with frame type */
+       memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+       /* lock hcill state */
+       spin_lock_irqsave(&ll->hcill_lock, flags);
+
+       /* act according to current state */
+       switch (ll->hcill_state) {
+       case HCILL_AWAKE:
+               BT_DBG("device awake, sending normally");
+               skb_queue_tail(&ll->txq, skb);
+               break;
+       case HCILL_ASLEEP:
+               BT_DBG("device asleep, waking up and queueing packet");
+               /* save packet for later */
+               skb_queue_tail(&ll->tx_wait_q, skb);
+               /* awake device */
+               if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
+                       BT_ERR("cannot wake up device");
+                       break;
+               }
+               ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
+               break;
+       case HCILL_ASLEEP_TO_AWAKE:
+               BT_DBG("device waking up, queueing packet");
+               /* transient state; just keep packet for later */
+               skb_queue_tail(&ll->tx_wait_q, skb);
+               break;
+       default:
+               BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
+               kfree_skb(skb);
+               break;
+       }
+
+       spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+       return 0;
+}
+
+static inline int ll_check_data_len(struct ll_struct *ll, int len)
+{
+       register int room = skb_tailroom(ll->rx_skb);
+
+       BT_DBG("len %d room %d", len, room);
+
+       if (!len) {
+               hci_recv_frame(ll->rx_skb);
+       } else if (len > room) {
+               BT_ERR("Data length is too large");
+               kfree_skb(ll->rx_skb);
+       } else {
+               ll->rx_state = HCILL_W4_DATA;
+               ll->rx_count = len;
+               return len;
+       }
+
+       ll->rx_state = HCILL_W4_PACKET_TYPE;
+       ll->rx_skb   = NULL;
+       ll->rx_count = 0;
+
+       return 0;
+}
+
+/* Recv data */
+static int ll_recv(struct hci_uart *hu, void *data, int count)
+{
+       struct ll_struct *ll = hu->priv;
+       register char *ptr;
+       struct hci_event_hdr *eh;
+       struct hci_acl_hdr   *ah;
+       struct hci_sco_hdr   *sh;
+       register int len, type, dlen;
+
+       BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
+
+       ptr = data;
+       while (count) {
+               if (ll->rx_count) {
+                       len = min_t(unsigned int, ll->rx_count, count);
+                       memcpy(skb_put(ll->rx_skb, len), ptr, len);
+                       ll->rx_count -= len; count -= len; ptr += len;
+
+                       if (ll->rx_count)
+                               continue;
+
+                       switch (ll->rx_state) {
+                       case HCILL_W4_DATA:
+                               BT_DBG("Complete data");
+                               hci_recv_frame(ll->rx_skb);
+
+                               ll->rx_state = HCILL_W4_PACKET_TYPE;
+                               ll->rx_skb = NULL;
+                               continue;
+
+                       case HCILL_W4_EVENT_HDR:
+                               eh = (struct hci_event_hdr *) ll->rx_skb->data;
+
+                               BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+                               ll_check_data_len(ll, eh->plen);
+                               continue;
+
+                       case HCILL_W4_ACL_HDR:
+                               ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+                               dlen = __le16_to_cpu(ah->dlen);
+
+                               BT_DBG("ACL header: dlen %d", dlen);
+
+                               ll_check_data_len(ll, dlen);
+                               continue;
+
+                       case HCILL_W4_SCO_HDR:
+                               sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+
+                               BT_DBG("SCO header: dlen %d", sh->dlen);
+
+                               ll_check_data_len(ll, sh->dlen);
+                               continue;
+                       }
+               }
+
+               /* HCILL_W4_PACKET_TYPE */
+               switch (*ptr) {
+               case HCI_EVENT_PKT:
+                       BT_DBG("Event packet");
+                       ll->rx_state = HCILL_W4_EVENT_HDR;
+                       ll->rx_count = HCI_EVENT_HDR_SIZE;
+                       type = HCI_EVENT_PKT;
+                       break;
+
+               case HCI_ACLDATA_PKT:
+                       BT_DBG("ACL packet");
+                       ll->rx_state = HCILL_W4_ACL_HDR;
+                       ll->rx_count = HCI_ACL_HDR_SIZE;
+                       type = HCI_ACLDATA_PKT;
+                       break;
+
+               case HCI_SCODATA_PKT:
+                       BT_DBG("SCO packet");
+                       ll->rx_state = HCILL_W4_SCO_HDR;
+                       ll->rx_count = HCI_SCO_HDR_SIZE;
+                       type = HCI_SCODATA_PKT;
+                       break;
+
+               /* HCILL signals */
+               case HCILL_GO_TO_SLEEP_IND:
+                       BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
+                       ll_device_want_to_sleep(hu);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_GO_TO_SLEEP_ACK:
+                       /* shouldn't happen */
+                       BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_WAKE_UP_IND:
+                       BT_DBG("HCILL_WAKE_UP_IND packet");
+                       ll_device_want_to_wakeup(hu);
+                       ptr++; count--;
+                       continue;
+
+               case HCILL_WAKE_UP_ACK:
+                       BT_DBG("HCILL_WAKE_UP_ACK packet");
+                       ll_device_woke_up(hu);
+                       ptr++; count--;
+                       continue;
+
+               default:
+                       BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+                       hu->hdev->stat.err_rx++;
+                       ptr++; count--;
+                       continue;
+               };
+
+               ptr++; count--;
+
+               /* Allocate packet */
+               ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+               if (!ll->rx_skb) {
+                       BT_ERR("Can't allocate mem for new packet");
+                       ll->rx_state = HCILL_W4_PACKET_TYPE;
+                       ll->rx_count = 0;
+                       return 0;
+               }
+
+               ll->rx_skb->dev = (void *) hu->hdev;
+               bt_cb(ll->rx_skb)->pkt_type = type;
+       }
+
+       return count;
+}
+
+static struct sk_buff *ll_dequeue(struct hci_uart *hu)
+{
+       struct ll_struct *ll = hu->priv;
+       return skb_dequeue(&ll->txq);
+}
+
+static struct hci_uart_proto llp = {
+       .id             = HCI_UART_LL,
+       .open           = ll_open,
+       .close          = ll_close,
+       .recv           = ll_recv,
+       .enqueue        = ll_enqueue,
+       .dequeue        = ll_dequeue,
+       .flush          = ll_flush,
+};
+
+int ll_init(void)
+{
+       int err = hci_uart_register_proto(&llp);
+
+       if (!err)
+               BT_INFO("HCILL protocol initialized");
+       else
+               BT_ERR("HCILL protocol registration failed");
+
+       return err;
+}
+
+int ll_deinit(void)
+{
+       return hci_uart_unregister_proto(&llp);
+}
index 1097ce7..50113db 100644 (file)
 #define HCIUARTGETDEVICE       _IOR('U', 202, int)
 
 /* UART protocols */
-#define HCI_UART_MAX_PROTO     4
+#define HCI_UART_MAX_PROTO     5
 
 #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
 
 struct hci_uart;
 
@@ -85,3 +86,8 @@ int h4_deinit(void);
 int bcsp_init(void);
 int bcsp_deinit(void);
 #endif
+
+#ifdef CONFIG_BT_HCIUART_LL
+int ll_init(void);
+int ll_deinit(void);
+#endif
index ed53aaa..ae41973 100644 (file)
@@ -471,7 +471,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        len = max(skb->len, ETH_ZLEN);
-       queue = skb->queue_mapping;
+       queue = skb_get_queue_mapping(skb);
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
        netif_stop_subqueue(dev, queue);
 #else
index ed1f9bb..112ab07 100644 (file)
@@ -3103,31 +3103,12 @@ static int niu_alloc_tx_ring_info(struct niu *np,
 
 static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
 {
-       u16 bs;
+       u16 bss;
 
-       switch (PAGE_SIZE) {
-       case 4 * 1024:
-       case 8 * 1024:
-       case 16 * 1024:
-       case 32 * 1024:
-               rp->rbr_block_size = PAGE_SIZE;
-               rp->rbr_blocks_per_page = 1;
-               break;
+       bss = min(PAGE_SHIFT, 15);
 
-       default:
-               if (PAGE_SIZE % (32 * 1024) == 0)
-                       bs = 32 * 1024;
-               else if (PAGE_SIZE % (16 * 1024) == 0)
-                       bs = 16 * 1024;
-               else if (PAGE_SIZE % (8 * 1024) == 0)
-                       bs = 8 * 1024;
-               else if (PAGE_SIZE % (4 * 1024) == 0)
-                       bs = 4 * 1024;
-               else
-                       BUG();
-               rp->rbr_block_size = bs;
-               rp->rbr_blocks_per_page = PAGE_SIZE / bs;
-       }
+       rp->rbr_block_size = 1 << bss;
+       rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
 
        rp->rbr_sizes[0] = 256;
        rp->rbr_sizes[1] = 1024;
@@ -7902,12 +7883,7 @@ static int __init niu_init(void)
 {
        int err = 0;
 
-       BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
-                    ((PAGE_SIZE > 32 * 1024) &&
-                     ((PAGE_SIZE % (32 * 1024)) != 0 &&
-                      (PAGE_SIZE % (16 * 1024)) != 0 &&
-                      (PAGE_SIZE % (8 * 1024)) != 0 &&
-                      (PAGE_SIZE % (4 * 1024)) != 0)));
+       BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
 
        niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
 
index 014dc2c..09440d7 100644 (file)
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.84"
-#define DRV_MODULE_RELDATE     "October 12, 2007"
+#define DRV_MODULE_VERSION     "3.85"
+#define DRV_MODULE_RELDATE     "October 18, 2007"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -200,6 +200,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+       {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
        {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
        {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
@@ -5028,10 +5029,7 @@ static int tg3_poll_fw(struct tg3 *tp)
 /* Save PCI command register before chip reset */
 static void tg3_save_pci_state(struct tg3 *tp)
 {
-       u32 val;
-
-       pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
-       tp->pci_cmd = val;
+       pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
 }
 
 /* Restore PCI state after chip reset */
@@ -5054,7 +5052,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
                       PCISTATE_ALLOW_APE_SHMEM_WR;
        pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
 
-       pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+       pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
 
        if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
                pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
@@ -10820,9 +10818,24 @@ out_not_found:
                strcpy(tp->board_part_number, "none");
 }
 
+static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
+{
+       u32 val;
+
+       if (tg3_nvram_read_swab(tp, offset, &val) ||
+           (val & 0xfc000000) != 0x0c000000 ||
+           tg3_nvram_read_swab(tp, offset + 4, &val) ||
+           val != 0)
+               return 0;
+
+       return 1;
+}
+
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val, offset, start;
+       u32 ver_offset;
+       int i, bcnt;
 
        if (tg3_nvram_read_swab(tp, 0, &val))
                return;
@@ -10835,29 +10848,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
                return;
 
        offset = tg3_nvram_logical_addr(tp, offset);
-       if (tg3_nvram_read_swab(tp, offset, &val))
+
+       if (!tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
                return;
 
-       if ((val & 0xfc000000) == 0x0c000000) {
-               u32 ver_offset, addr;
-               int i;
+       offset = offset + ver_offset - start;
+       for (i = 0; i < 16; i += 4) {
+               if (tg3_nvram_read(tp, offset + i, &val))
+                       return;
 
-               if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
-                   tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+               val = le32_to_cpu(val);
+               memcpy(tp->fw_ver + i, &val, 4);
+       }
+
+       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+            (tp->tg3_flags & TG3_FLG3_ENABLE_APE))
+               return;
+
+       for (offset = TG3_NVM_DIR_START;
+            offset < TG3_NVM_DIR_END;
+            offset += TG3_NVM_DIRENT_SIZE) {
+               if (tg3_nvram_read_swab(tp, offset, &val))
                        return;
 
-               if (val != 0)
+               if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
+                       break;
+       }
+
+       if (offset == TG3_NVM_DIR_END)
+               return;
+
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+               start = 0x08000000;
+       else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+               return;
+
+       if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+           !tg3_fw_img_is_valid(tp, offset) ||
+           tg3_nvram_read_swab(tp, offset + 8, &val))
+               return;
+
+       offset += val - start;
+
+       bcnt = strlen(tp->fw_ver);
+
+       tp->fw_ver[bcnt++] = ',';
+       tp->fw_ver[bcnt++] = ' ';
+
+       for (i = 0; i < 4; i++) {
+               if (tg3_nvram_read(tp, offset, &val))
                        return;
 
-               addr = offset + ver_offset - start;
-               for (i = 0; i < 16; i += 4) {
-                       if (tg3_nvram_read(tp, addr + i, &val))
-                               return;
+               val = le32_to_cpu(val);
+               offset += sizeof(val);
 
-                       val = cpu_to_le32(val);
-                       memcpy(tp->fw_ver + i, &val, 4);
+               if (bcnt > TG3_VER_SIZE - sizeof(val)) {
+                       memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
+                       break;
                }
+
+               memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
+               bcnt += sizeof(val);
        }
+
+       tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
 
 static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
index 6dbdad2..1d5b2a3 100644 (file)
 #define TG3_EEPROM_MAGIC_HW            0xabcd
 #define TG3_EEPROM_MAGIC_HW_MSK                0xffff
 
+#define TG3_NVM_DIR_START              0x18
+#define TG3_NVM_DIR_END                        0x78
+#define TG3_NVM_DIRENT_SIZE            0xc
+#define TG3_NVM_DIRTYPE_SHIFT          24
+#define TG3_NVM_DIRTYPE_ASFINI         1
+
 /* 32K Window into NIC internal memory */
 #define NIC_SRAM_WIN_BASE              0x00008000
 
@@ -2415,10 +2421,11 @@ struct tg3 {
 #define PHY_REV_BCM5411_X0             0x1 /* Found on Netgear GA302T */
 
        u32                             led_ctrl;
-       u32                             pci_cmd;
+       u16                             pci_cmd;
 
        char                            board_part_number[24];
-       char                            fw_ver[16];
+#define TG3_VER_SIZE 32
+       char                            fw_ver[TG3_VER_SIZE];
        u32                             nic_sram_data_cfg;
        u32                             pci_clock_ctrl;
        struct pci_dev                  *pdev_peer;
index c136abc..dd79cdb 100644 (file)
@@ -313,6 +313,10 @@ static const struct proto_ops name##_ops = {                       \
 #define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
        MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
 
+#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \
+       MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
+                    "-type-" __stringify(type))
+
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
 extern ctl_table net_table[];
index 6f85db3..4a3f54e 100644 (file)
@@ -996,7 +996,7 @@ static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
  *
  * Check individual transmit queue of a device with multiple transmit queues.
  */
-static inline int netif_subqueue_stopped(const struct net_device *dev,
+static inline int __netif_subqueue_stopped(const struct net_device *dev,
                                         u16 queue_index)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
@@ -1007,6 +1007,11 @@ static inline int netif_subqueue_stopped(const struct net_device *dev,
 #endif
 }
 
+static inline int netif_subqueue_stopped(const struct net_device *dev,
+                                        struct sk_buff *skb)
+{
+       return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb));
+}
 
 /**
  *     netif_wake_subqueue - allow sending packets on subqueue
index df948b4..4e10a07 100644 (file)
 #define PCI_DEVICE_ID_TIGON3_5720      0x1658
 #define PCI_DEVICE_ID_TIGON3_5721      0x1659
 #define PCI_DEVICE_ID_TIGON3_5722      0x165a
+#define PCI_DEVICE_ID_TIGON3_5723      0x165b
 #define PCI_DEVICE_ID_TIGON3_5705M     0x165d
 #define PCI_DEVICE_ID_TIGON3_5705M_2   0x165e
 #define PCI_DEVICE_ID_TIGON3_5714      0x1668
index f93f22b..fd4e12f 100644 (file)
@@ -41,8 +41,7 @@
 #define SKB_DATA_ALIGN(X)      (((X) + (SMP_CACHE_BYTES - 1)) & \
                                 ~(SMP_CACHE_BYTES - 1))
 #define SKB_WITH_OVERHEAD(X)   \
-       (((X) - sizeof(struct skb_shared_info)) & \
-        ~(SMP_CACHE_BYTES - 1))
+       ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 #define SKB_MAX_ORDER(X, ORDER) \
        SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X))
 #define SKB_MAX_HEAD(X)                (SKB_MAX_ORDER((X), 0))
@@ -301,8 +300,9 @@ struct sk_buff {
 #endif
 
        int                     iif;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
        __u16                   queue_mapping;
-
+#endif
 #ifdef CONFIG_NET_SCHED
        __u16                   tc_index;       /* traffic control index */
 #ifdef CONFIG_NET_CLS_ACT
@@ -1770,6 +1770,15 @@ static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
 #endif
 }
 
+static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+       return skb->queue_mapping;
+#else
+       return 0;
+#endif
+}
+
 static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from)
 {
 #ifdef CONFIG_NETDEVICES_MULTIQUEUE
index f852e1a..c22ef1c 100644 (file)
@@ -291,6 +291,7 @@ struct ucred {
 #define SOL_TIPC       271
 #define SOL_RXRPC      272
 #define SOL_PPPOL2TP   273
+#define SOL_BLUETOOTH  274
 
 /* IPX options */
 #define IPX_TYPE       1
index ebfb96b..a8a9eb6 100644 (file)
@@ -200,119 +200,18 @@ enum {
 #define HCI_LM_SECURE  0x0020
 
 /* -----  HCI Commands ---- */
-/* OGF & OCF values */
-
-/* Informational Parameters */
-#define OGF_INFO_PARAM 0x04
-
-#define OCF_READ_LOCAL_VERSION 0x0001
-struct hci_rp_read_loc_version {
-       __u8     status;
-       __u8     hci_ver;
-       __le16   hci_rev;
-       __u8     lmp_ver;
-       __le16   manufacturer;
-       __le16   lmp_subver;
-} __attribute__ ((packed));
-
-#define OCF_READ_LOCAL_FEATURES        0x0003
-struct hci_rp_read_local_features {
-       __u8 status;
-       __u8 features[8];
-} __attribute__ ((packed));
-
-#define OCF_READ_BUFFER_SIZE   0x0005
-struct hci_rp_read_buffer_size {
-       __u8     status;
-       __le16   acl_mtu;
-       __u8     sco_mtu;
-       __le16   acl_max_pkt;
-       __le16   sco_max_pkt;
-} __attribute__ ((packed));
-
-#define OCF_READ_BD_ADDR       0x0009
-struct hci_rp_read_bd_addr {
-       __u8     status;
-       bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-/* Host Controller and Baseband */
-#define OGF_HOST_CTL   0x03
-#define OCF_RESET              0x0003
-#define OCF_READ_AUTH_ENABLE   0x001F
-#define OCF_WRITE_AUTH_ENABLE  0x0020
-       #define AUTH_DISABLED           0x00
-       #define AUTH_ENABLED            0x01
-
-#define OCF_READ_ENCRYPT_MODE  0x0021
-#define OCF_WRITE_ENCRYPT_MODE 0x0022
-       #define ENCRYPT_DISABLED        0x00
-       #define ENCRYPT_P2P             0x01
-       #define ENCRYPT_BOTH            0x02
-
-#define OCF_WRITE_CA_TIMEOUT   0x0016  
-#define OCF_WRITE_PG_TIMEOUT   0x0018
-
-#define OCF_WRITE_SCAN_ENABLE  0x001A
-       #define SCAN_DISABLED           0x00
-       #define SCAN_INQUIRY            0x01
-       #define SCAN_PAGE               0x02
-
-#define OCF_SET_EVENT_FLT      0x0005
-struct hci_cp_set_event_flt {
-       __u8     flt_type;
-       __u8     cond_type;
-       __u8     condition[0];
-} __attribute__ ((packed));
-
-/* Filter types */
-#define HCI_FLT_CLEAR_ALL      0x00
-#define HCI_FLT_INQ_RESULT     0x01
-#define HCI_FLT_CONN_SETUP     0x02
-
-/* CONN_SETUP Condition types */
-#define HCI_CONN_SETUP_ALLOW_ALL       0x00
-#define HCI_CONN_SETUP_ALLOW_CLASS     0x01
-#define HCI_CONN_SETUP_ALLOW_BDADDR    0x02
-
-/* CONN_SETUP Conditions */
-#define HCI_CONN_SETUP_AUTO_OFF        0x01
-#define HCI_CONN_SETUP_AUTO_ON 0x02
-
-#define OCF_READ_CLASS_OF_DEV  0x0023
-struct hci_rp_read_dev_class {
-       __u8     status;
-       __u8     dev_class[3];
-} __attribute__ ((packed));
-
-#define OCF_WRITE_CLASS_OF_DEV 0x0024
-struct hci_cp_write_dev_class {
-       __u8     dev_class[3];
-} __attribute__ ((packed));
-
-#define OCF_READ_VOICE_SETTING 0x0025
-struct hci_rp_read_voice_setting {
-       __u8     status;
-       __le16   voice_setting;
+#define HCI_OP_INQUIRY                 0x0401
+struct hci_cp_inquiry {
+       __u8     lap[3];
+       __u8     length;
+       __u8     num_rsp;
 } __attribute__ ((packed));
 
-#define OCF_WRITE_VOICE_SETTING        0x0026
-struct hci_cp_write_voice_setting {
-       __le16   voice_setting;
-} __attribute__ ((packed));
+#define HCI_OP_INQUIRY_CANCEL          0x0402
 
-#define OCF_HOST_BUFFER_SIZE   0x0033
-struct hci_cp_host_buffer_size {
-       __le16   acl_mtu;
-       __u8     sco_mtu;
-       __le16   acl_max_pkt;
-       __le16   sco_max_pkt;
-} __attribute__ ((packed));
-
-/* Link Control */
-#define OGF_LINK_CTL   0x01 
+#define HCI_OP_EXIT_PERIODIC_INQ       0x0404
 
-#define OCF_CREATE_CONN                0x0005
+#define HCI_OP_CREATE_CONN             0x0405
 struct hci_cp_create_conn {
        bdaddr_t bdaddr;
        __le16   pkt_type;
@@ -322,105 +221,138 @@ struct hci_cp_create_conn {
        __u8     role_switch;
 } __attribute__ ((packed));
 
-#define OCF_CREATE_CONN_CANCEL 0x0008
-struct hci_cp_create_conn_cancel {
-       bdaddr_t bdaddr;
-} __attribute__ ((packed));
-
-#define OCF_ACCEPT_CONN_REQ    0x0009
-struct hci_cp_accept_conn_req {
-       bdaddr_t bdaddr;
-       __u8     role;
-} __attribute__ ((packed));
-
-#define OCF_REJECT_CONN_REQ    0x000a
-struct hci_cp_reject_conn_req {
-       bdaddr_t bdaddr;
-       __u8     reason;
-} __attribute__ ((packed));
-
-#define OCF_DISCONNECT 0x0006
+#define HCI_OP_DISCONNECT              0x0406
 struct hci_cp_disconnect {
        __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
-#define OCF_ADD_SCO    0x0007
+#define HCI_OP_ADD_SCO                 0x0407
 struct hci_cp_add_sco {
        __le16   handle;
        __le16   pkt_type;
 } __attribute__ ((packed));
 
-#define OCF_INQUIRY            0x0001
-struct hci_cp_inquiry {
-       __u8     lap[3];
-       __u8     length;
-       __u8     num_rsp;
+#define HCI_OP_CREATE_CONN_CANCEL      0x0408
+struct hci_cp_create_conn_cancel {
+       bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_INQUIRY_CANCEL     0x0002
+#define HCI_OP_ACCEPT_CONN_REQ         0x0409
+struct hci_cp_accept_conn_req {
+       bdaddr_t bdaddr;
+       __u8     role;
+} __attribute__ ((packed));
 
-#define OCF_EXIT_PERIODIC_INQ  0x0004
+#define HCI_OP_REJECT_CONN_REQ         0x040a
+struct hci_cp_reject_conn_req {
+       bdaddr_t bdaddr;
+       __u8     reason;
+} __attribute__ ((packed));
 
-#define OCF_LINK_KEY_REPLY     0x000B
+#define HCI_OP_LINK_KEY_REPLY          0x040b
 struct hci_cp_link_key_reply {
        bdaddr_t bdaddr;
        __u8     link_key[16];
 } __attribute__ ((packed));
 
-#define OCF_LINK_KEY_NEG_REPLY 0x000C
+#define HCI_OP_LINK_KEY_NEG_REPLY      0x040c
 struct hci_cp_link_key_neg_reply {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_PIN_CODE_REPLY     0x000D
+#define HCI_OP_PIN_CODE_REPLY          0x040d
 struct hci_cp_pin_code_reply {
        bdaddr_t bdaddr;
        __u8     pin_len;
        __u8     pin_code[16];
 } __attribute__ ((packed));
 
-#define OCF_PIN_CODE_NEG_REPLY 0x000E
+#define HCI_OP_PIN_CODE_NEG_REPLY      0x040e
 struct hci_cp_pin_code_neg_reply {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define OCF_CHANGE_CONN_PTYPE  0x000F
+#define HCI_OP_CHANGE_CONN_PTYPE       0x040f
 struct hci_cp_change_conn_ptype {
        __le16   handle;
        __le16   pkt_type;
 } __attribute__ ((packed));
 
-#define OCF_AUTH_REQUESTED     0x0011
+#define HCI_OP_AUTH_REQUESTED          0x0411
 struct hci_cp_auth_requested {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_SET_CONN_ENCRYPT   0x0013
+#define HCI_OP_SET_CONN_ENCRYPT                0x0413
 struct hci_cp_set_conn_encrypt {
        __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
-#define OCF_CHANGE_CONN_LINK_KEY 0x0015
+#define HCI_OP_CHANGE_CONN_LINK_KEY    0x0415
 struct hci_cp_change_conn_link_key {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_READ_REMOTE_FEATURES 0x001B
+#define HCI_OP_REMOTE_NAME_REQ         0x0419
+struct hci_cp_remote_name_req {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_mode;
+       __le16   clock_offset;
+} __attribute__ ((packed));
+
+#define HCI_OP_REMOTE_NAME_REQ_CANCEL  0x041a
+struct hci_cp_remote_name_req_cancel {
+       bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_FEATURES    0x041b
 struct hci_cp_read_remote_features {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_READ_REMOTE_VERSION 0x001D
+#define HCI_OP_READ_REMOTE_EXT_FEATURES        0x041c
+struct hci_cp_read_remote_ext_features {
+       __le16   handle;
+       __u8     page;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_REMOTE_VERSION     0x041d
 struct hci_cp_read_remote_version {
        __le16   handle;
 } __attribute__ ((packed));
 
-/* Link Policy */
-#define OGF_LINK_POLICY        0x02   
+#define HCI_OP_SETUP_SYNC_CONN         0x0428
+struct hci_cp_setup_sync_conn {
+       __le16   handle;
+       __le32   tx_bandwidth;
+       __le32   rx_bandwidth;
+       __le16   max_latency;
+       __le16   voice_setting;
+       __u8     retrans_effort;
+       __le16   pkt_type;
+} __attribute__ ((packed));
 
-#define OCF_SNIFF_MODE         0x0003
+#define HCI_OP_ACCEPT_SYNC_CONN_REQ    0x0429
+struct hci_cp_accept_sync_conn_req {
+       bdaddr_t bdaddr;
+       __le32   tx_bandwidth;
+       __le32   rx_bandwidth;
+       __le16   max_latency;
+       __le16   content_format;
+       __u8     retrans_effort;
+       __le16   pkt_type;
+} __attribute__ ((packed));
+
+#define HCI_OP_REJECT_SYNC_CONN_REQ    0x042a
+struct hci_cp_reject_sync_conn_req {
+       bdaddr_t bdaddr;
+       __u8     reason;
+} __attribute__ ((packed));
+
+#define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
        __le16   max_interval;
@@ -429,12 +361,12 @@ struct hci_cp_sniff_mode {
        __le16   timeout;
 } __attribute__ ((packed));
 
-#define OCF_EXIT_SNIFF_MODE    0x0004
+#define HCI_OP_EXIT_SNIFF_MODE         0x0804
 struct hci_cp_exit_sniff_mode {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_ROLE_DISCOVERY     0x0009
+#define HCI_OP_ROLE_DISCOVERY          0x0809
 struct hci_cp_role_discovery {
        __le16   handle;
 } __attribute__ ((packed));
@@ -444,7 +376,13 @@ struct hci_rp_role_discovery {
        __u8     role;
 } __attribute__ ((packed));
 
-#define OCF_READ_LINK_POLICY   0x000C
+#define HCI_OP_SWITCH_ROLE             0x080b
+struct hci_cp_switch_role {
+       bdaddr_t bdaddr;
+       __u8     role;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LINK_POLICY                0x080c
 struct hci_cp_read_link_policy {
        __le16   handle;
 } __attribute__ ((packed));
@@ -454,13 +392,7 @@ struct hci_rp_read_link_policy {
        __le16   policy;
 } __attribute__ ((packed));
 
-#define OCF_SWITCH_ROLE                0x000B
-struct hci_cp_switch_role {
-       bdaddr_t bdaddr;
-       __u8     role;
-} __attribute__ ((packed));
-
-#define OCF_WRITE_LINK_POLICY  0x000D
+#define HCI_OP_WRITE_LINK_POLICY       0x080d
 struct hci_cp_write_link_policy {
        __le16   handle;
        __le16   policy;
@@ -470,7 +402,7 @@ struct hci_rp_write_link_policy {
        __le16   handle;
 } __attribute__ ((packed));
 
-#define OCF_SNIFF_SUBRATE      0x0011
+#define HCI_OP_SNIFF_SUBRATE           0x0811
 struct hci_cp_sniff_subrate {
        __le16   handle;
        __le16   max_latency;
@@ -478,59 +410,156 @@ struct hci_cp_sniff_subrate {
        __le16   min_local_timeout;
 } __attribute__ ((packed));
 
-/* Status params */
-#define OGF_STATUS_PARAM       0x05
+#define HCI_OP_SET_EVENT_MASK          0x0c01
+struct hci_cp_set_event_mask {
+       __u8     mask[8];
+} __attribute__ ((packed));
 
-/* Testing commands */
-#define OGF_TESTING_CMD                0x3E
+#define HCI_OP_RESET                   0x0c03
 
-/* Vendor specific commands */
-#define OGF_VENDOR_CMD         0x3F
+#define HCI_OP_SET_EVENT_FLT           0x0c05
+struct hci_cp_set_event_flt {
+       __u8     flt_type;
+       __u8     cond_type;
+       __u8     condition[0];
+} __attribute__ ((packed));
 
-/* ---- HCI Events ---- */
-#define HCI_EV_INQUIRY_COMPLETE        0x01
+/* Filter types */
+#define HCI_FLT_CLEAR_ALL      0x00
+#define HCI_FLT_INQ_RESULT     0x01
+#define HCI_FLT_CONN_SETUP     0x02
 
-#define HCI_EV_INQUIRY_RESULT  0x02
-struct inquiry_info {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
-       __u8     pscan_mode;
+/* CONN_SETUP Condition types */
+#define HCI_CONN_SETUP_ALLOW_ALL       0x00
+#define HCI_CONN_SETUP_ALLOW_CLASS     0x01
+#define HCI_CONN_SETUP_ALLOW_BDADDR    0x02
+
+/* CONN_SETUP Conditions */
+#define HCI_CONN_SETUP_AUTO_OFF        0x01
+#define HCI_CONN_SETUP_AUTO_ON 0x02
+
+#define HCI_OP_WRITE_LOCAL_NAME                0x0c13
+struct hci_cp_write_local_name {
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_NAME         0x0c14
+struct hci_rp_read_local_name {
+       __u8     status;
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_CA_TIMEOUT                0x0c16
+
+#define HCI_OP_WRITE_PG_TIMEOUT                0x0c18
+
+#define HCI_OP_WRITE_SCAN_ENABLE       0x0c1a
+       #define SCAN_DISABLED           0x00
+       #define SCAN_INQUIRY            0x01
+       #define SCAN_PAGE               0x02
+
+#define HCI_OP_READ_AUTH_ENABLE                0x0c1f
+
+#define HCI_OP_WRITE_AUTH_ENABLE       0x0c20
+       #define AUTH_DISABLED           0x00
+       #define AUTH_ENABLED            0x01
+
+#define HCI_OP_READ_ENCRYPT_MODE       0x0c21
+
+#define HCI_OP_WRITE_ENCRYPT_MODE      0x0c22
+       #define ENCRYPT_DISABLED        0x00
+       #define ENCRYPT_P2P             0x01
+       #define ENCRYPT_BOTH            0x02
+
+#define HCI_OP_READ_CLASS_OF_DEV       0x0c23
+struct hci_rp_read_class_of_dev {
+       __u8     status;
        __u8     dev_class[3];
-       __le16   clock_offset;
 } __attribute__ ((packed));
 
-#define HCI_EV_INQUIRY_RESULT_WITH_RSSI        0x22
-struct inquiry_info_with_rssi {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
+#define HCI_OP_WRITE_CLASS_OF_DEV      0x0c24
+struct hci_cp_write_class_of_dev {
        __u8     dev_class[3];
-       __le16   clock_offset;
-       __s8     rssi;
 } __attribute__ ((packed));
-struct inquiry_info_with_rssi_and_pscan_mode {
+
+#define HCI_OP_READ_VOICE_SETTING      0x0c25
+struct hci_rp_read_voice_setting {
+       __u8     status;
+       __le16   voice_setting;
+} __attribute__ ((packed));
+
+#define HCI_OP_WRITE_VOICE_SETTING     0x0c26
+struct hci_cp_write_voice_setting {
+       __le16   voice_setting;
+} __attribute__ ((packed));
+
+#define HCI_OP_HOST_BUFFER_SIZE                0x0c33
+struct hci_cp_host_buffer_size {
+       __le16   acl_mtu;
+       __u8     sco_mtu;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_VERSION      0x1001
+struct hci_rp_read_local_version {
+       __u8     status;
+       __u8     hci_ver;
+       __le16   hci_rev;
+       __u8     lmp_ver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_COMMANDS     0x1002
+struct hci_rp_read_local_commands {
+       __u8     status;
+       __u8     commands[64];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_FEATURES     0x1003
+struct hci_rp_read_local_features {
+       __u8     status;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
+struct hci_rp_read_local_ext_features {
+       __u8     status;
+       __u8     page;
+       __u8     max_page;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BUFFER_SIZE                0x1005
+struct hci_rp_read_buffer_size {
+       __u8     status;
+       __le16   acl_mtu;
+       __u8     sco_mtu;
+       __le16   acl_max_pkt;
+       __le16   sco_max_pkt;
+} __attribute__ ((packed));
+
+#define HCI_OP_READ_BD_ADDR            0x1009
+struct hci_rp_read_bd_addr {
+       __u8     status;
        bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
-       __u8     pscan_period_mode;
-       __u8     pscan_mode;
-       __u8     dev_class[3];
-       __le16   clock_offset;
-       __s8     rssi;
 } __attribute__ ((packed));
 
-#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2F
-struct extended_inquiry_info {
+/* ---- HCI Events ---- */
+#define HCI_EV_INQUIRY_COMPLETE                0x01
+
+#define HCI_EV_INQUIRY_RESULT          0x02
+struct inquiry_info {
        bdaddr_t bdaddr;
        __u8     pscan_rep_mode;
        __u8     pscan_period_mode;
+       __u8     pscan_mode;
        __u8     dev_class[3];
        __le16   clock_offset;
-       __s8     rssi;
-       __u8     data[240];
 } __attribute__ ((packed));
 
-#define HCI_EV_CONN_COMPLETE   0x03
+#define HCI_EV_CONN_COMPLETE           0x03
 struct hci_ev_conn_complete {
        __u8     status;
        __le16   handle;
@@ -539,40 +568,63 @@ struct hci_ev_conn_complete {
        __u8     encr_mode;
 } __attribute__ ((packed));
 
-#define HCI_EV_CONN_REQUEST    0x04
+#define HCI_EV_CONN_REQUEST            0x04
 struct hci_ev_conn_request {
        bdaddr_t bdaddr;
        __u8     dev_class[3];
        __u8     link_type;
 } __attribute__ ((packed));
 
-#define HCI_EV_DISCONN_COMPLETE        0x05
+#define HCI_EV_DISCONN_COMPLETE                0x05
 struct hci_ev_disconn_complete {
        __u8     status;
        __le16   handle;
        __u8     reason;
 } __attribute__ ((packed));
 
-#define HCI_EV_AUTH_COMPLETE   0x06
+#define HCI_EV_AUTH_COMPLETE           0x06
 struct hci_ev_auth_complete {
        __u8     status;
        __le16   handle;
 } __attribute__ ((packed));
 
-#define HCI_EV_ENCRYPT_CHANGE  0x08
+#define HCI_EV_REMOTE_NAME             0x07
+struct hci_ev_remote_name {
+       __u8     status;
+       bdaddr_t bdaddr;
+       __u8     name[248];
+} __attribute__ ((packed));
+
+#define HCI_EV_ENCRYPT_CHANGE          0x08
 struct hci_ev_encrypt_change {
        __u8     status;
        __le16   handle;
        __u8     encrypt;
 } __attribute__ ((packed));
 
-#define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE   0x09
-struct hci_ev_change_conn_link_key_complete {
+#define HCI_EV_CHANGE_LINK_KEY_COMPLETE        0x09
+struct hci_ev_change_link_key_complete {
+       __u8     status;
+       __le16   handle;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_FEATURES         0x0b
+struct hci_ev_remote_features {
+       __u8     status;
+       __le16   handle;
+       __u8     features[8];
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_VERSION          0x0c
+struct hci_ev_remote_version {
        __u8     status;
        __le16   handle;
+       __u8     lmp_ver;
+       __le16   manufacturer;
+       __le16   lmp_subver;
 } __attribute__ ((packed));
 
-#define HCI_EV_QOS_SETUP_COMPLETE      0x0D
+#define HCI_EV_QOS_SETUP_COMPLETE      0x0d
 struct hci_qos {
        __u8     service_type;
        __u32    token_rate;
@@ -586,33 +638,33 @@ struct hci_ev_qos_setup_complete {
        struct   hci_qos qos;
 } __attribute__ ((packed));
 
-#define HCI_EV_CMD_COMPLETE    0x0E
+#define HCI_EV_CMD_COMPLETE            0x0e
 struct hci_ev_cmd_complete {
        __u8     ncmd;
        __le16   opcode;
 } __attribute__ ((packed));
 
-#define HCI_EV_CMD_STATUS      0x0F
+#define HCI_EV_CMD_STATUS              0x0f
 struct hci_ev_cmd_status {
        __u8     status;
        __u8     ncmd;
        __le16   opcode;
 } __attribute__ ((packed));
 
-#define HCI_EV_NUM_COMP_PKTS   0x13
-struct hci_ev_num_comp_pkts {
-       __u8     num_hndl;
-       /* variable length part */
-} __attribute__ ((packed));
-
-#define HCI_EV_ROLE_CHANGE     0x12
+#define HCI_EV_ROLE_CHANGE             0x12
 struct hci_ev_role_change {
        __u8     status;
        bdaddr_t bdaddr;
        __u8     role;
 } __attribute__ ((packed));
 
-#define HCI_EV_MODE_CHANGE     0x14
+#define HCI_EV_NUM_COMP_PKTS           0x13
+struct hci_ev_num_comp_pkts {
+       __u8     num_hndl;
+       /* variable length part */
+} __attribute__ ((packed));
+
+#define HCI_EV_MODE_CHANGE             0x14
 struct hci_ev_mode_change {
        __u8     status;
        __le16   handle;
@@ -620,53 +672,88 @@ struct hci_ev_mode_change {
        __le16   interval;
 } __attribute__ ((packed));
 
-#define HCI_EV_PIN_CODE_REQ    0x16
+#define HCI_EV_PIN_CODE_REQ            0x16
 struct hci_ev_pin_code_req {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define HCI_EV_LINK_KEY_REQ    0x17
+#define HCI_EV_LINK_KEY_REQ            0x17
 struct hci_ev_link_key_req {
        bdaddr_t bdaddr;
 } __attribute__ ((packed));
 
-#define HCI_EV_LINK_KEY_NOTIFY 0x18
+#define HCI_EV_LINK_KEY_NOTIFY         0x18
 struct hci_ev_link_key_notify {
        bdaddr_t bdaddr;
-       __u8     link_key[16];
-       __u8     key_type;
+       __u8     link_key[16];
+       __u8     key_type;
 } __attribute__ ((packed));
 
-#define HCI_EV_REMOTE_FEATURES 0x0B
-struct hci_ev_remote_features {
+#define HCI_EV_CLOCK_OFFSET            0x1c
+struct hci_ev_clock_offset {
        __u8     status;
        __le16   handle;
-       __u8     features[8];
+       __le16   clock_offset;
 } __attribute__ ((packed));
 
-#define HCI_EV_REMOTE_VERSION  0x0C
-struct hci_ev_remote_version {
+#define HCI_EV_PSCAN_REP_MODE          0x20
+struct hci_ev_pscan_rep_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+} __attribute__ ((packed));
+
+#define HCI_EV_INQUIRY_RESULT_WITH_RSSI        0x22
+struct inquiry_info_with_rssi {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+} __attribute__ ((packed));
+struct inquiry_info_with_rssi_and_pscan_mode {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     pscan_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+} __attribute__ ((packed));
+
+#define HCI_EV_REMOTE_EXT_FEATURES     0x23
+struct hci_ev_remote_ext_features {
        __u8     status;
        __le16   handle;
-       __u8     lmp_ver;
-       __le16   manufacturer;
-       __le16   lmp_subver;
+       __u8     page;
+       __u8     max_page;
+       __u8     features[8];
 } __attribute__ ((packed));
 
-#define HCI_EV_CLOCK_OFFSET    0x01C
-struct hci_ev_clock_offset {
+#define HCI_EV_SYNC_CONN_COMPLETE      0x2c
+struct hci_ev_sync_conn_complete {
        __u8     status;
        __le16   handle;
-       __le16   clock_offset;
+       bdaddr_t bdaddr;
+       __u8     link_type;
+       __u8     tx_interval;
+       __u8     retrans_window;
+       __le16   rx_pkt_len;
+       __le16   tx_pkt_len;
+       __u8     air_mode;
 } __attribute__ ((packed));
 
-#define HCI_EV_PSCAN_REP_MODE  0x20
-struct hci_ev_pscan_rep_mode {
-       bdaddr_t bdaddr;
-       __u8     pscan_rep_mode;
+#define HCI_EV_SYNC_CONN_CHANGED       0x2d
+struct hci_ev_sync_conn_changed {
+       __u8     status;
+       __le16   handle;
+       __u8     tx_interval;
+       __u8     retrans_window;
+       __le16   rx_pkt_len;
+       __le16   tx_pkt_len;
 } __attribute__ ((packed));
 
-#define HCI_EV_SNIFF_SUBRATE   0x2E
+#define HCI_EV_SNIFF_SUBRATE           0x2e
 struct hci_ev_sniff_subrate {
        __u8     status;
        __le16   handle;
@@ -676,14 +763,25 @@ struct hci_ev_sniff_subrate {
        __le16   max_local_timeout;
 } __attribute__ ((packed));
 
+#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
+struct extended_inquiry_info {
+       bdaddr_t bdaddr;
+       __u8     pscan_rep_mode;
+       __u8     pscan_period_mode;
+       __u8     dev_class[3];
+       __le16   clock_offset;
+       __s8     rssi;
+       __u8     data[240];
+} __attribute__ ((packed));
+
 /* Internal events generated by Bluetooth stack */
-#define HCI_EV_STACK_INTERNAL  0xFD
+#define HCI_EV_STACK_INTERNAL  0xfd
 struct hci_ev_stack_internal {
        __u16    type;
        __u8     data[0];
 } __attribute__ ((packed));
 
-#define HCI_EV_SI_DEVICE       0x01
+#define HCI_EV_SI_DEVICE       0x01
 struct hci_ev_si_device {
        __u16    event;
        __u16    dev_id;
@@ -704,40 +802,40 @@ struct hci_ev_si_security {
 #define HCI_SCO_HDR_SIZE     3
 
 struct hci_command_hdr {
-       __le16  opcode;         /* OCF & OGF */
+       __le16  opcode;         /* OCF & OGF */
        __u8    plen;
 } __attribute__ ((packed));
 
 struct hci_event_hdr {
-       __u8    evt;
-       __u8    plen;
+       __u8    evt;
+       __u8    plen;
 } __attribute__ ((packed));
 
 struct hci_acl_hdr {
-       __le16  handle;         /* Handle & Flags(PB, BC) */
-       __le16  dlen;
+       __le16  handle;         /* Handle & Flags(PB, BC) */
+       __le16  dlen;
 } __attribute__ ((packed));
 
 struct hci_sco_hdr {
-       __le16  handle;
-       __u8    dlen;
+       __le16  handle;
+       __u8    dlen;
 } __attribute__ ((packed));
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
 static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_event_hdr *)skb->data;
+       return (struct hci_event_hdr *) skb->data;
 }
 
 static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_acl_hdr *)skb->data;
+       return (struct hci_acl_hdr *) skb->data;
 }
 
 static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
 {
-       return (struct hci_sco_hdr *)skb->data;
+       return (struct hci_sco_hdr *) skb->data;
 }
 #endif
 
@@ -771,13 +869,13 @@ struct sockaddr_hci {
 struct hci_filter {
        unsigned long type_mask;
        unsigned long event_mask[2];
-       __le16   opcode;
+       __le16 opcode;
 };
 
 struct hci_ufilter {
-       __u32   type_mask;
-       __u32   event_mask[2];
-       __le16   opcode;
+       __u32  type_mask;
+       __u32  event_mask[2];
+       __le16 opcode;
 };
 
 #define HCI_FLT_TYPE_BITS      31
@@ -825,15 +923,15 @@ struct hci_dev_info {
 struct hci_conn_info {
        __u16    handle;
        bdaddr_t bdaddr;
-       __u8     type;
-       __u8     out;
-       __u16    state;
-       __u32    link_mode;
+       __u8     type;
+       __u8     out;
+       __u16    state;
+       __u32    link_mode;
 };
 
 struct hci_dev_req {
-       __u16 dev_id;
-       __u32 dev_opt;
+       __u16  dev_id;
+       __u32  dev_opt;
 };
 
 struct hci_dev_list_req {
index 8f67c8a..ea13baa 100644 (file)
@@ -71,7 +71,10 @@ struct hci_dev {
        __u16           id;
        __u8            type;
        bdaddr_t        bdaddr;
+       __u8            dev_name[248];
+       __u8            dev_class[3];
        __u8            features[8];
+       __u8            commands[64];
        __u8            hci_ver;
        __u16           hci_rev;
        __u16           manufacturer;
@@ -310,10 +313,12 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
 void hci_acl_connect(struct hci_conn *conn);
 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);
-int    hci_conn_del(struct hci_conn *conn);
-void   hci_conn_hash_flush(struct hci_dev *hdev);
+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 *src);
 int hci_conn_auth(struct hci_conn *conn);
@@ -617,11 +622,11 @@ int hci_unregister_cb(struct hci_cb *hcb);
 int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
 int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
 int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
 void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
 
index 70e70f5..73e115b 100644 (file)
@@ -29,7 +29,8 @@
 #define L2CAP_DEFAULT_MTU      672
 #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
 
-#define L2CAP_CONN_TIMEOUT     (HZ * 40)
+#define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
+#define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -148,6 +149,19 @@ struct l2cap_conf_opt {
 
 #define L2CAP_CONF_MAX_SIZE    22
 
+struct l2cap_conf_rfc {
+       __u8       mode;
+       __u8       txwin_size;
+       __u8       max_transmit;
+       __le16     retrans_timeout;
+       __le16     monitor_timeout;
+       __le16     max_pdu_size;
+} __attribute__ ((packed));
+
+#define L2CAP_MODE_BASIC       0x00
+#define L2CAP_MODE_RETRANS     0x01
+#define L2CAP_MODE_FLOWCTL     0x02
+
 struct l2cap_disconn_req {
        __le16     dcid;
        __le16     scid;
@@ -160,7 +174,6 @@ struct l2cap_disconn_rsp {
 
 struct l2cap_info_req {
        __le16      type;
-       __u8        data[0];
 } __attribute__ ((packed));
 
 struct l2cap_info_rsp {
@@ -192,6 +205,13 @@ struct l2cap_conn {
 
        unsigned int    mtu;
 
+       __u32           feat_mask;
+
+       __u8            info_state;
+       __u8            info_ident;
+
+       struct timer_list info_timer;
+
        spinlock_t      lock;
 
        struct sk_buff *rx_skb;
@@ -202,6 +222,9 @@ struct l2cap_conn {
        struct l2cap_chan_list chan_list;
 };
 
+#define L2CAP_INFO_CL_MTU_REQ_SENT     0x01
+#define L2CAP_INFO_FEAT_MASK_REQ_SENT  0x02
+
 /* ----- L2CAP channel and socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 
@@ -221,7 +244,6 @@ struct l2cap_pinfo {
        __u8            conf_len;
        __u8            conf_state;
        __u8            conf_retry;
-       __u16           conf_mtu;
 
        __u8            ident;
 
@@ -232,10 +254,11 @@ struct l2cap_pinfo {
        struct sock             *prev_c;
 };
 
-#define L2CAP_CONF_REQ_SENT    0x01
-#define L2CAP_CONF_INPUT_DONE  0x02
-#define L2CAP_CONF_OUTPUT_DONE 0x04
-#define L2CAP_CONF_MAX_RETRIES 2
+#define L2CAP_CONF_REQ_SENT    0x01
+#define L2CAP_CONF_INPUT_DONE  0x02
+#define L2CAP_CONF_OUTPUT_DONE 0x04
+
+#define L2CAP_CONF_MAX_RETRIES 2
 
 void l2cap_load(void);
 
index 5fdfc9a..9483320 100644 (file)
@@ -78,11 +78,11 @@ void hci_acl_connect(struct hci_conn *conn)
 
        cp.pkt_type = cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
        if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
-               cp.role_switch  = 0x01;
+               cp.role_switch = 0x01;
        else
-               cp.role_switch  = 0x00;
+               cp.role_switch = 0x00;
 
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
 
 static void hci_acl_connect_cancel(struct hci_conn *conn)
@@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
                return;
 
        bacpy(&cp.bdaddr, &conn->dst);
-       hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                               OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
+       hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
 }
 
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
@@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
 
        cp.handle = cpu_to_le16(conn->handle);
        cp.reason = reason;
-       hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                               OCF_DISCONNECT, sizeof(cp), &cp);
+       hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
 void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -126,7 +124,29 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
        cp.handle   = cpu_to_le16(handle);
        cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
+}
+
+void hci_setup_sync(struct hci_conn *conn, __u16 handle)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct hci_cp_setup_sync_conn cp;
+
+       BT_DBG("%p", conn);
+
+       conn->state = BT_CONNECT;
+       conn->out = 1;
+
+       cp.handle   = cpu_to_le16(handle);
+       cp.pkt_type = cpu_to_le16(hdev->esco_type);
+
+       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+       cp.max_latency    = cpu_to_le16(0xffff);
+       cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
+       cp.retrans_effort = 0xff;
+
+       hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
 }
 
 static void hci_conn_timeout(unsigned long arg)
@@ -143,7 +163,10 @@ static void hci_conn_timeout(unsigned long arg)
 
        switch (conn->state) {
        case BT_CONNECT:
-               hci_acl_connect_cancel(conn);
+               if (conn->type == ACL_LINK)
+                       hci_acl_connect_cancel(conn);
+               else
+                       hci_acl_disconn(conn, 0x13);
                break;
        case BT_CONNECTED:
                hci_acl_disconn(conn, 0x13);
@@ -330,8 +353,12 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
        hci_conn_hold(sco);
 
        if (acl->state == BT_CONNECTED &&
-                       (sco->state == BT_OPEN || sco->state == BT_CLOSED))
-               hci_add_sco(sco, acl->handle);
+                       (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+               if (lmp_esco_capable(hdev))
+                       hci_setup_sync(sco, acl->handle);
+               else
+                       hci_add_sco(sco, acl->handle);
+       }
 
        return sco;
 }
@@ -348,7 +375,7 @@ int hci_conn_auth(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_auth_requested cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -369,7 +396,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
                struct hci_cp_set_conn_encrypt cp;
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 1;
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -383,7 +410,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_change_conn_link_key cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -401,7 +428,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
                struct hci_cp_switch_role cp;
                bacpy(&cp.bdaddr, &conn->dst);
                cp.role = role;
-               hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
+               hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
        }
        return 0;
 }
@@ -423,8 +450,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
        if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
                struct hci_cp_exit_sniff_mode cp;
                cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
        }
 
 timer:
@@ -455,8 +481,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.max_latency        = cpu_to_le16(0);
                cp.min_remote_timeout = cpu_to_le16(0);
                cp.min_local_timeout  = cpu_to_le16(0);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
        }
 
        if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
@@ -466,8 +491,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
                cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
                cp.attempt      = cpu_to_le16(4);
                cp.timeout      = cpu_to_le16(1);
-               hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_SNIFF_MODE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
        }
 }
 
@@ -493,6 +517,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
        }
 }
 
+/* Check pending connect attempts */
+void hci_conn_check_pending(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+
+       BT_DBG("hdev %s", hdev->name);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+       if (conn)
+               hci_acl_connect(conn);
+
+       hci_dev_unlock(hdev);
+}
+
 int hci_get_conn_list(void __user *arg)
 {
        struct hci_conn_list_req req, *cl;
index 18e3afc..372b0d3 100644 (file)
@@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %ld", hdev->name, opt);
 
        /* Reset device */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 }
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 
        /* Reset */
        if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
-                       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+                       hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
        /* Read Local Supported Features */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
        /* Read Local Version */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
 
        /* Read Buffer Size (ACL mtu, max pkt, etc.) */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
 
 #if 0
        /* Host buffer size */
@@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
                cp.sco_mtu = HCI_MAX_SCO_SIZE;
                cp.acl_max_pkt = cpu_to_le16(0xffff);
                cp.sco_max_pkt = cpu_to_le16(0xffff);
-               hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp);
+               hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
        }
 #endif
 
        /* Read BD Address */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+       /* Read Class of Device */
+       hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+       /* Read Local Name */
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
 
        /* Read Voice Setting */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
+       hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
 
        /* Optional initialization */
 
        /* Clear Event Filters */
        flt_type = HCI_FLT_CLEAR_ALL;
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &flt_type);
+       hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
 
        /* Page timeout ~20 secs */
        param = cpu_to_le16(0x8000);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param);
+       hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, &param);
 
        /* Connection accept timeout ~20 secs */
        param = cpu_to_le16(0x7d00);
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param);
+       hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
 }
 
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
@@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, scan);
 
        /* Inquiry and Page scans */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 }
 
 static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
@@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, auth);
 
        /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+       hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
 }
 
 static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
@@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
        BT_DBG("%s %x", hdev->name, encrypt);
 
        /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
+       hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
 }
 
 /* Get HCI device by index.
@@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
        memcpy(&cp.lap, &ir->lap, 3);
        cp.length  = ir->length;
        cp.num_rsp = ir->num_rsp;
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp);
+       hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
 }
 
 int hci_inquiry(void __user *arg)
@@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb)
 }
 
 /* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
 {
        int len = HCI_COMMAND_HDR_SIZE + plen;
        struct hci_command_hdr *hdr;
        struct sk_buff *skb;
 
-       BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+       BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
 
        skb = bt_skb_alloc(len, GFP_ATOMIC);
        if (!skb) {
@@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
        }
 
        hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
-       hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf));
+       hdr->opcode = cpu_to_le16(opcode);
        hdr->plen   = plen;
 
        if (plen)
@@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 }
 
 /* Get data from the previously sent command */
-void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
 {
        struct hci_command_hdr *hdr;
 
@@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
 
        hdr = (void *) hdev->sent_cmd->data;
 
-       if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf)))
+       if (hdr->opcode != cpu_to_le16(opcode))
                return NULL;
 
-       BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+       BT_DBG("%s opcode 0x%x", hdev->name, opcode);
 
        return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
 }
@@ -1355,6 +1361,26 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
        }
 }
 
+static inline void hci_sched_esco(struct hci_dev *hdev)
+{
+       struct hci_conn *conn;
+       struct sk_buff *skb;
+       int quote;
+
+       BT_DBG("%s", hdev->name);
+
+       while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
+               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
+                       BT_DBG("skb %p len %d", skb, skb->len);
+                       hci_send_frame(skb);
+
+                       conn->sent++;
+                       if (conn->sent == ~0)
+                               conn->sent = 0;
+               }
+       }
+}
+
 static void hci_tx_task(unsigned long arg)
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
@@ -1370,6 +1396,8 @@ static void hci_tx_task(unsigned long arg)
 
        hci_sched_sco(hdev);
 
+       hci_sched_esco(hdev);
+
        /* Send next queued raw (unknown type) packet */
        while ((skb = skb_dequeue(&hdev->raw_q)))
                hci_send_frame(skb);
index 4baea1e..46df2e4 100644 (file)
 
 /* Handle HCI Event packets */
 
-/* Command Complete OGF LINK_CTL  */
-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status;
-       struct hci_conn *pend;
+       __u8 status = *((__u8 *) skb->data);
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_INQUIRY_CANCEL:
-       case OCF_EXIT_PERIODIC_INQ:
-               status = *((__u8 *) skb->data);
+       if (status)
+               return;
 
-               if (status) {
-                       BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
-               } else {
-                       clear_bit(HCI_INQUIRY, &hdev->flags);
-                       hci_req_complete(hdev, status);
-               }
+       clear_bit(HCI_INQUIRY, &hdev->flags);
 
-               hci_dev_lock(hdev);
+       hci_req_complete(hdev, status);
+
+       hci_conn_check_pending(hdev);
+}
 
-               pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-               if (pend)
-                       hci_acl_connect(pend);
+static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
 
-               hci_dev_unlock(hdev);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               break;
+       if (status)
+               return;
 
-       default:
-               BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-               break;
+       clear_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_conn_check_pending(hdev);
+}
+
+static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_role_discovery *rp = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn) {
+               if (rp->role)
+                       conn->link_mode &= ~HCI_LM_MASTER;
+               else
+                       conn->link_mode |= HCI_LM_MASTER;
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Complete OGF LINK_POLICY  */
-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct hci_rp_write_link_policy *rp = (void *) skb->data;
        struct hci_conn *conn;
-       struct hci_rp_role_discovery *rd;
-       struct hci_rp_write_link_policy *lp;
        void *sent;
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-       switch (ocf) {
-       case OCF_ROLE_DISCOVERY:
-               rd = (void *) skb->data;
+       if (rp->status)
+               return;
 
-               if (rd->status)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
+       if (!sent)
+               return;
 
-               hci_dev_lock(hdev);
+       hci_dev_lock(hdev);
 
-               conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
-               if (conn) {
-                       if (rd->role)
-                               conn->link_mode &= ~HCI_LM_MASTER;
-                       else
-                               conn->link_mode |= HCI_LM_MASTER;
-               }
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn) {
+               __le16 policy = get_unaligned((__le16 *) (sent + 2));
+               conn->link_policy = __le16_to_cpu(policy);
+       }
 
-               hci_dev_unlock(hdev);
-               break;
+       hci_dev_unlock(hdev);
+}
 
-       case OCF_WRITE_LINK_POLICY:
-               sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY);
-               if (!sent)
-                       break;
+static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
 
-               lp = (struct hci_rp_write_link_policy *) skb->data;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               if (lp->status)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               hci_dev_lock(hdev);
+static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle));
-               if (conn) {
-                       __le16 policy = get_unaligned((__le16 *) (sent + 2));
-                       conn->link_policy = __le16_to_cpu(policy);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               hci_dev_unlock(hdev);
-               break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
+       if (!sent)
+               return;
 
-       default:
-               BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
-                               hdev->name, ocf);
-               break;
+       if (!status)
+               memcpy(hdev->dev_name, sent, 248);
+}
+
+static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_name *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       memcpy(hdev->dev_name, rp->name, 248);
+}
+
+static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
+       if (!sent)
+               return;
+
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
+
+               if (param == AUTH_ENABLED)
+                       set_bit(HCI_AUTH, &hdev->flags);
+               else
+                       clear_bit(HCI_AUTH, &hdev->flags);
        }
+
+       hci_req_complete(hdev, status);
 }
 
-/* Command Complete OGF HOST_CTL  */
-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status, param;
-       __u16 setting;
-       struct hci_rp_read_voice_setting *vs;
+       __u8 status = *((__u8 *) skb->data);
        void *sent;
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_RESET:
-               status = *((__u8 *) skb->data);
-               hci_req_complete(hdev, status);
-               break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
+       if (!sent)
+               return;
 
-       case OCF_SET_EVENT_FLT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
-               }
-               break;
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
+
+               if (param)
+                       set_bit(HCI_ENCRYPT, &hdev->flags);
+               else
+                       clear_bit(HCI_ENCRYPT, &hdev->flags);
+       }
 
-       case OCF_WRITE_AUTH_ENABLE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-               if (!sent)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               if (!status) {
-                       if (param == AUTH_ENABLED)
-                               set_bit(HCI_AUTH, &hdev->flags);
-                       else
-                               clear_bit(HCI_AUTH, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       case OCF_WRITE_ENCRYPT_MODE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-               if (!sent)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
+       if (!sent)
+               return;
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+       if (!status) {
+               __u8 param = *((__u8 *) sent);
 
-               if (!status) {
-                       if (param)
-                               set_bit(HCI_ENCRYPT, &hdev->flags);
-                       else
-                               clear_bit(HCI_ENCRYPT, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+               clear_bit(HCI_PSCAN, &hdev->flags);
+               clear_bit(HCI_ISCAN, &hdev->flags);
 
-       case OCF_WRITE_CA_TIMEOUT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
-               }
-               break;
+               if (param & SCAN_INQUIRY)
+                       set_bit(HCI_ISCAN, &hdev->flags);
 
-       case OCF_WRITE_PG_TIMEOUT:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
-               } else {
-                       BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
-               }
-               break;
+               if (param & SCAN_PAGE)
+                       set_bit(HCI_PSCAN, &hdev->flags);
+       }
 
-       case OCF_WRITE_SCAN_ENABLE:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-               if (!sent)
-                       break;
+       hci_req_complete(hdev, status);
+}
 
-               status = *((__u8 *) skb->data);
-               param  = *((__u8 *) sent);
+static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
 
-               BT_DBG("param 0x%x", param);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               if (!status) {
-                       clear_bit(HCI_PSCAN, &hdev->flags);
-                       clear_bit(HCI_ISCAN, &hdev->flags);
-                       if (param & SCAN_INQUIRY)
-                               set_bit(HCI_ISCAN, &hdev->flags);
+       if (rp->status)
+               return;
 
-                       if (param & SCAN_PAGE)
-                               set_bit(HCI_PSCAN, &hdev->flags);
-               }
-               hci_req_complete(hdev, status);
-               break;
+       memcpy(hdev->dev_class, rp->dev_class, 3);
 
-       case OCF_READ_VOICE_SETTING:
-               vs = (struct hci_rp_read_voice_setting *) skb->data;
+       BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
+               hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
 
-               if (vs->status) {
-                       BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
-                       break;
-               }
+static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
 
-               setting = __le16_to_cpu(vs->voice_setting);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-               if (hdev->voice_setting != setting ) {
-                       hdev->voice_setting = setting;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
+       if (!sent)
+               return;
 
-                       BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+       if (!status)
+               memcpy(hdev->dev_class, sent, 3);
+}
 
-                       if (hdev->notify) {
-                               tasklet_disable(&hdev->tx_task);
-                               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-                               tasklet_enable(&hdev->tx_task);
-                       }
-               }
-               break;
+static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_voice_setting *rp = (void *) skb->data;
+       __u16 setting;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       setting = __le16_to_cpu(rp->voice_setting);
+
+       if (hdev->voice_setting == setting )
+               return;
+
+       hdev->voice_setting = setting;
+
+       BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
+
+       if (hdev->notify) {
+               tasklet_disable(&hdev->tx_task);
+               hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
+               tasklet_enable(&hdev->tx_task);
+       }
+}
+
+static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+       void *sent;
+
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       case OCF_WRITE_VOICE_SETTING:
-               sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
-               if (!sent)
-                       break;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
+       if (!sent)
+               return;
 
-               status = *((__u8 *) skb->data);
-               setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
+       if (!status) {
+               __u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
 
-               if (!status && hdev->voice_setting != setting) {
+               if (hdev->voice_setting != setting) {
                        hdev->voice_setting = setting;
 
-                       BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+                       BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
 
                        if (hdev->notify) {
                                tasklet_disable(&hdev->tx_task);
@@ -287,143 +326,153 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
                                tasklet_enable(&hdev->tx_task);
                        }
                }
-               hci_req_complete(hdev, status);
-               break;
-
-       case OCF_HOST_BUFFER_SIZE:
-               status = *((__u8 *) skb->data);
-               if (status) {
-                       BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
-                       hci_req_complete(hdev, status);
-               }
-               break;
-
-       default:
-               BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
-               break;
        }
 }
 
-/* Command Complete OGF INFO_PARAM  */
-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_rp_read_loc_version *lv;
-       struct hci_rp_read_local_features *lf;
-       struct hci_rp_read_buffer_size *bs;
-       struct hci_rp_read_bd_addr *ba;
+       __u8 status = *((__u8 *) skb->data);
 
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       switch (ocf) {
-       case OCF_READ_LOCAL_VERSION:
-               lv = (struct hci_rp_read_loc_version *) skb->data;
+       hci_req_complete(hdev, status);
+}
 
-               if (lv->status) {
-                       BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
-                       break;
-               }
+static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_version *rp = (void *) skb->data;
 
-               hdev->hci_ver = lv->hci_ver;
-               hdev->hci_rev = btohs(lv->hci_rev);
-               hdev->manufacturer = btohs(lv->manufacturer);
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
-                               hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
+       if (rp->status)
+               return;
 
-               break;
+       hdev->hci_ver = rp->hci_ver;
+       hdev->hci_rev = btohs(rp->hci_rev);
+       hdev->manufacturer = btohs(rp->manufacturer);
 
-       case OCF_READ_LOCAL_FEATURES:
-               lf = (struct hci_rp_read_local_features *) skb->data;
+       BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
+                                       hdev->manufacturer,
+                                       hdev->hci_ver, hdev->hci_rev);
+}
 
-               if (lf->status) {
-                       BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-                       break;
-               }
+static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_commands *rp = (void *) skb->data;
 
-               memcpy(hdev->features, lf->features, sizeof(hdev->features));
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               /* Adjust default settings according to features
-                * supported by device. */
-               if (hdev->features[0] & LMP_3SLOT)
-                       hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+       if (rp->status)
+               return;
 
-               if (hdev->features[0] & LMP_5SLOT)
-                       hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+       memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
+}
 
-               if (hdev->features[1] & LMP_HV2) {
-                       hdev->pkt_type  |= (HCI_HV2);
-                       hdev->esco_type |= (ESCO_HV2);
-               }
+static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_local_features *rp = (void *) skb->data;
 
-               if (hdev->features[1] & LMP_HV3) {
-                       hdev->pkt_type  |= (HCI_HV3);
-                       hdev->esco_type |= (ESCO_HV3);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               if (hdev->features[3] & LMP_ESCO)
-                       hdev->esco_type |= (ESCO_EV3);
+       if (rp->status)
+               return;
 
-               if (hdev->features[4] & LMP_EV4)
-                       hdev->esco_type |= (ESCO_EV4);
+       memcpy(hdev->features, rp->features, 8);
 
-               if (hdev->features[4] & LMP_EV5)
-                       hdev->esco_type |= (ESCO_EV5);
+       /* Adjust default settings according to features
+        * supported by device. */
 
-               BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
-                               lf->features[0], lf->features[1], lf->features[2]);
+       if (hdev->features[0] & LMP_3SLOT)
+               hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
 
-               break;
+       if (hdev->features[0] & LMP_5SLOT)
+               hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
 
-       case OCF_READ_BUFFER_SIZE:
-               bs = (struct hci_rp_read_buffer_size *) skb->data;
+       if (hdev->features[1] & LMP_HV2) {
+               hdev->pkt_type  |= (HCI_HV2);
+               hdev->esco_type |= (ESCO_HV2);
+       }
 
-               if (bs->status) {
-                       BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-                       hci_req_complete(hdev, bs->status);
-                       break;
-               }
+       if (hdev->features[1] & LMP_HV3) {
+               hdev->pkt_type  |= (HCI_HV3);
+               hdev->esco_type |= (ESCO_HV3);
+       }
 
-               hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
-               hdev->sco_mtu  = bs->sco_mtu;
-               hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt);
-               hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt);
+       if (hdev->features[3] & LMP_ESCO)
+               hdev->esco_type |= (ESCO_EV3);
 
-               if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
-                       hdev->sco_mtu  = 64;
-                       hdev->sco_pkts = 8;
-               }
+       if (hdev->features[4] & LMP_EV4)
+               hdev->esco_type |= (ESCO_EV4);
 
-               hdev->acl_cnt = hdev->acl_pkts;
-               hdev->sco_cnt = hdev->sco_pkts;
+       if (hdev->features[4] & LMP_EV5)
+               hdev->esco_type |= (ESCO_EV5);
 
-               BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-                       hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
-               break;
+       BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
+                                       hdev->features[0], hdev->features[1],
+                                       hdev->features[2], hdev->features[3],
+                                       hdev->features[4], hdev->features[5],
+                                       hdev->features[6], hdev->features[7]);
+}
 
-       case OCF_READ_BD_ADDR:
-               ba = (struct hci_rp_read_bd_addr *) skb->data;
+static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_buffer_size *rp = (void *) skb->data;
 
-               if (!ba->status) {
-                       bacpy(&hdev->bdaddr, &ba->bdaddr);
-               } else {
-                       BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-               }
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-               hci_req_complete(hdev, ba->status);
-               break;
+       if (rp->status)
+               return;
 
-       default:
-               BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-               break;
+       hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
+       hdev->sco_mtu  = rp->sco_mtu;
+       hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
+       hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
+
+       if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
+               hdev->sco_mtu  = 64;
+               hdev->sco_pkts = 8;
        }
+
+       hdev->acl_cnt = hdev->acl_pkts;
+       hdev->sco_cnt = hdev->sco_pkts;
+
+       BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
+                                       hdev->acl_mtu, hdev->acl_pkts,
+                                       hdev->sco_mtu, hdev->sco_pkts);
+}
+
+static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_rp_read_bd_addr *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (!rp->status)
+               bacpy(&hdev->bdaddr, &rp->bdaddr);
+
+       hci_req_complete(hdev, rp->status);
+}
+
+static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
+{
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       if (status) {
+               hci_req_complete(hdev, status);
+
+               hci_conn_check_pending(hdev);
+       } else
+               set_bit(HCI_INQUIRY, &hdev->flags);
 }
 
-/* Command Status OGF LINK_CTL  */
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 {
+       struct hci_cp_create_conn *cp;
        struct hci_conn *conn;
-       struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
 
+       BT_DBG("%s status 0x%x", hdev->name, status);
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
        if (!cp)
                return;
 
@@ -431,8 +480,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
-       BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-                       status, batostr(&cp->bdaddr), conn);
+       BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@ -457,234 +505,138 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       case OCF_CREATE_CONN:
-               hci_cs_create_conn(hdev, status);
-               break;
-
-       case OCF_ADD_SCO:
-               if (status) {
-                       struct hci_conn *acl, *sco;
-                       struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO);
-                       __u16 handle;
+       struct hci_cp_add_sco *cp;
+       struct hci_conn *acl, *sco;
+       __u16 handle;
 
-                       if (!cp)
-                               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-                       handle = __le16_to_cpu(cp->handle);
-
-                       BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
+       if (!status)
+               return;
 
-                       hci_dev_lock(hdev);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
+       if (!cp)
+               return;
 
-                       acl = hci_conn_hash_lookup_handle(hdev, handle);
-                       if (acl && (sco = acl->link)) {
-                               sco->state = BT_CLOSED;
+       handle = __le16_to_cpu(cp->handle);
 
-                               hci_proto_connect_cfm(sco, status);
-                               hci_conn_del(sco);
-                       }
+       BT_DBG("%s handle %d", hdev->name, handle);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       hci_dev_lock(hdev);
 
-       case OCF_INQUIRY:
-               if (status) {
-                       BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
-                       hci_req_complete(hdev, status);
-               } else {
-                       set_bit(HCI_INQUIRY, &hdev->flags);
-               }
-               break;
+       acl = hci_conn_hash_lookup_handle(hdev, handle);
+       if (acl && (sco = acl->link)) {
+               sco->state = BT_CLOSED;
 
-       default:
-               BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d",
-                       hdev->name, ocf, status);
-               break;
+               hci_proto_connect_cfm(sco, status);
+               hci_conn_del(sco);
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Status OGF LINK_POLICY */
-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       case OCF_SNIFF_MODE:
-               if (status) {
-                       struct hci_conn *conn;
-                       struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
-
-                       if (!cp)
-                               break;
+       BT_DBG("%s status 0x%x", hdev->name, status);
+}
 
-                       hci_dev_lock(hdev);
+static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
+{
+       struct hci_cp_setup_sync_conn *cp;
+       struct hci_conn *acl, *sco;
+       __u16 handle;
 
-                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-                       if (conn) {
-                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-                       }
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       if (!status)
+               return;
 
-       case OCF_EXIT_SNIFF_MODE:
-               if (status) {
-                       struct hci_conn *conn;
-                       struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN);
+       if (!cp)
+               return;
 
-                       if (!cp)
-                               break;
+       handle = __le16_to_cpu(cp->handle);
 
-                       hci_dev_lock(hdev);
+       BT_DBG("%s handle %d", hdev->name, handle);
 
-                       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
-                       if (conn) {
-                               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
-                       }
+       hci_dev_lock(hdev);
 
-                       hci_dev_unlock(hdev);
-               }
-               break;
+       acl = hci_conn_hash_lookup_handle(hdev, handle);
+       if (acl && (sco = acl->link)) {
+               sco->state = BT_CLOSED;
 
-       default:
-               BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
-               break;
+               hci_proto_connect_cfm(sco, status);
+               hci_conn_del(sco);
        }
+
+       hci_dev_unlock(hdev);
 }
 
-/* Command Status OGF HOST_CTL */
-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
 {
-       BT_DBG("%s ocf 0x%x", hdev->name, ocf);
+       struct hci_cp_sniff_mode *cp;
+       struct hci_conn *conn;
 
-       switch (ocf) {
-       default:
-               BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
-               break;
-       }
-}
-
-/* Command Status OGF INFO_PARAM  */
-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
-{
-       BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
-
-       switch (ocf) {
-       default:
-               BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-               break;
-       }
-}
-
-/* Inquiry Complete */
-static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       __u8 status = *((__u8 *) skb->data);
-       struct hci_conn *pend;
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       BT_DBG("%s status %d", hdev->name, status);
+       if (!status)
+               return;
 
-       clear_bit(HCI_INQUIRY, &hdev->flags);
-       hci_req_complete(hdev, status);
+       cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
+       if (!cp)
+               return;
 
        hci_dev_lock(hdev);
 
-       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-       if (pend)
-               hci_acl_connect(pend);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
        hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result */
-static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
 {
-       struct inquiry_data data;
-       struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1);
-       int num_rsp = *((__u8 *) skb->data);
+       struct hci_cp_exit_sniff_mode *cp;
+       struct hci_conn *conn;
 
-       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+       BT_DBG("%s status 0x%x", hdev->name, status);
 
-       if (!num_rsp)
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
+       if (!cp)
                return;
 
        hci_dev_lock(hdev);
 
-       for (; num_rsp; num_rsp--) {
-               bacpy(&data.bdaddr, &info->bdaddr);
-               data.pscan_rep_mode     = info->pscan_rep_mode;
-               data.pscan_period_mode  = info->pscan_period_mode;
-               data.pscan_mode         = info->pscan_mode;
-               memcpy(data.dev_class, info->dev_class, 3);
-               data.clock_offset       = info->clock_offset;
-               data.rssi               = 0x00;
-               info++;
-               hci_inquiry_cache_update(hdev, &data);
-       }
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
+       if (conn)
+               clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
 
        hci_dev_unlock(hdev);
 }
 
-/* Inquiry Result With RSSI */
-static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct inquiry_data data;
-       int num_rsp = *((__u8 *) skb->data);
-
-       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
-
-       if (!num_rsp)
-               return;
-
-       hci_dev_lock(hdev);
+       __u8 status = *((__u8 *) skb->data);
 
-       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
-               struct inquiry_info_with_rssi_and_pscan_mode *info =
-                       (struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
+       BT_DBG("%s status %d", hdev->name, status);
 
-               for (; num_rsp; num_rsp--) {
-                       bacpy(&data.bdaddr, &info->bdaddr);
-                       data.pscan_rep_mode     = info->pscan_rep_mode;
-                       data.pscan_period_mode  = info->pscan_period_mode;
-                       data.pscan_mode         = info->pscan_mode;
-                       memcpy(data.dev_class, info->dev_class, 3);
-                       data.clock_offset       = info->clock_offset;
-                       data.rssi               = info->rssi;
-                       info++;
-                       hci_inquiry_cache_update(hdev, &data);
-               }
-       } else {
-               struct inquiry_info_with_rssi *info =
-                       (struct inquiry_info_with_rssi *) (skb->data + 1);
+       clear_bit(HCI_INQUIRY, &hdev->flags);
 
-               for (; num_rsp; num_rsp--) {
-                       bacpy(&data.bdaddr, &info->bdaddr);
-                       data.pscan_rep_mode     = info->pscan_rep_mode;
-                       data.pscan_period_mode  = info->pscan_period_mode;
-                       data.pscan_mode         = 0x00;
-                       memcpy(data.dev_class, info->dev_class, 3);
-                       data.clock_offset       = info->clock_offset;
-                       data.rssi               = info->rssi;
-                       info++;
-                       hci_inquiry_cache_update(hdev, &data);
-               }
-       }
+       hci_req_complete(hdev, status);
 
-       hci_dev_unlock(hdev);
+       hci_conn_check_pending(hdev);
 }
 
-/* Extended Inquiry Result */
-static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct inquiry_data data;
-       struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1);
+       struct inquiry_info *info = (void *) (skb->data + 1);
        int num_rsp = *((__u8 *) skb->data);
 
        BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
@@ -696,12 +648,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
 
        for (; num_rsp; num_rsp--) {
                bacpy(&data.bdaddr, &info->bdaddr);
-               data.pscan_rep_mode     = info->pscan_rep_mode;
-               data.pscan_period_mode  = info->pscan_period_mode;
-               data.pscan_mode         = 0x00;
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = info->pscan_mode;
                memcpy(data.dev_class, info->dev_class, 3);
-               data.clock_offset       = info->clock_offset;
-               data.rssi               = info->rssi;
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = 0x00;
                info++;
                hci_inquiry_cache_update(hdev, &data);
        }
@@ -709,70 +661,18 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        hci_dev_unlock(hdev);
 }
 
-/* Connect Request */
-static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_conn_request *ev = (struct hci_ev_conn_request *) skb->data;
-       int mask = hdev->link_mode;
-
-       BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-                       batostr(&ev->bdaddr), ev->link_type);
-
-       mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
-
-       if (mask & HCI_LM_ACCEPT) {
-               /* Connection accepted */
-               struct hci_conn *conn;
-               struct hci_cp_accept_conn_req cp;
-
-               hci_dev_lock(hdev);
-               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))) {
-                               BT_ERR("No memmory for new connection");
-                               hci_dev_unlock(hdev);
-                               return;
-                       }
-               }
-               memcpy(conn->dev_class, ev->dev_class, 3);
-               conn->state = BT_CONNECT;
-               hci_dev_unlock(hdev);
-
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-
-               if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-                       cp.role = 0x00; /* Become master */
-               else
-                       cp.role = 0x01; /* Remain slave */
-
-               hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
-       } else {
-               /* Connection rejected */
-               struct hci_cp_reject_conn_req cp;
-
-               bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x0f;
-               hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
-       }
-}
-
-/* Connect Complete */
 static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
-       struct hci_conn *conn, *pend;
+       struct hci_ev_conn_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
 
        BT_DBG("%s", hdev->name);
 
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
-       if (!conn) {
-               hci_dev_unlock(hdev);
-               return;
-       }
+       if (!conn)
+               goto unlock;
 
        if (!ev->status) {
                conn->handle = __le16_to_cpu(ev->handle);
@@ -788,8 +688,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                if (conn->type == ACL_LINK) {
                        struct hci_cp_read_remote_features cp;
                        cp.handle = ev->handle;
-                       hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
                }
 
                /* Set link policy */
@@ -797,8 +696,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        struct hci_cp_write_link_policy cp;
                        cp.handle = ev->handle;
                        cp.policy = cpu_to_le16(hdev->link_policy);
-                       hci_send_cmd(hdev, OGF_LINK_POLICY,
-                               OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
                }
 
                /* Set packet type for incoming connection */
@@ -809,8 +707,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
                                cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
 
-                       hci_send_cmd(hdev, OGF_LINK_CTL,
-                               OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+                       hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
                } else {
                        /* Update disconnect timer */
                        hci_conn_hold(conn);
@@ -822,9 +719,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (conn->type == ACL_LINK) {
                struct hci_conn *sco = conn->link;
                if (sco) {
-                       if (!ev->status)
-                               hci_add_sco(sco, conn->handle);
-                       else {
+                       if (!ev->status) {
+                               if (lmp_esco_capable(hdev))
+                                       hci_setup_sync(sco, conn->handle);
+                               else
+                                       hci_add_sco(sco, conn->handle);
+                       } else {
                                hci_proto_connect_cfm(sco, ev->status);
                                hci_conn_del(sco);
                        }
@@ -835,136 +735,104 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (ev->status)
                hci_conn_del(conn);
 
-       pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
-       if (pend)
-               hci_acl_connect(pend);
-
+unlock:
        hci_dev_unlock(hdev);
-}
-
-/* Disconnect Complete */
-static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data;
-       struct hci_conn *conn;
-
-       BT_DBG("%s status %d", hdev->name, ev->status);
 
-       if (ev->status)
-               return;
-
-       hci_dev_lock(hdev);
-
-       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               conn->state = BT_CLOSED;
-               hci_proto_disconn_ind(conn, ev->reason);
-               hci_conn_del(conn);
-       }
-
-       hci_dev_unlock(hdev);
+       hci_conn_check_pending(hdev);
 }
 
-/* Number of completed packets */
-static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data;
-       __le16 *ptr;
-       int i;
-
-       skb_pull(skb, sizeof(*ev));
-
-       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+       struct hci_ev_conn_request *ev = (void *) skb->data;
+       int mask = hdev->link_mode;
 
-       if (skb->len < ev->num_hndl * 4) {
-               BT_DBG("%s bad parameters", hdev->name);
-               return;
-       }
+       BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
+                                       batostr(&ev->bdaddr), ev->link_type);
 
-       tasklet_disable(&hdev->tx_task);
+       mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
 
-       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+       if (mask & HCI_LM_ACCEPT) {
+               /* Connection accepted */
                struct hci_conn *conn;
-               __u16  handle, count;
 
-               handle = __le16_to_cpu(get_unaligned(ptr++));
-               count  = __le16_to_cpu(get_unaligned(ptr++));
-
-               conn = hci_conn_hash_lookup_handle(hdev, handle);
-               if (conn) {
-                       conn->sent -= count;
+               hci_dev_lock(hdev);
 
-                       if (conn->type == ACL_LINK) {
-                               if ((hdev->acl_cnt += count) > hdev->acl_pkts)
-                                       hdev->acl_cnt = hdev->acl_pkts;
-                       } else {
-                               if ((hdev->sco_cnt += count) > hdev->sco_pkts)
-                                       hdev->sco_cnt = hdev->sco_pkts;
+               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))) {
+                               BT_ERR("No memmory for new connection");
+                               hci_dev_unlock(hdev);
+                               return;
                        }
                }
-       }
-       hci_sched_tx(hdev);
 
-       tasklet_enable(&hdev->tx_task);
-}
+               memcpy(conn->dev_class, ev->dev_class, 3);
+               conn->state = BT_CONNECT;
 
-/* Role Change */
-static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
-       struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data;
-       struct hci_conn *conn;
+               hci_dev_unlock(hdev);
 
-       BT_DBG("%s status %d", hdev->name, ev->status);
+               if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) {
+                       struct hci_cp_accept_conn_req cp;
 
-       hci_dev_lock(hdev);
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
 
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
-       if (conn) {
-               if (!ev->status) {
-                       if (ev->role)
-                               conn->link_mode &= ~HCI_LM_MASTER;
+                       if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+                               cp.role = 0x00; /* Become master */
                        else
-                               conn->link_mode |= HCI_LM_MASTER;
-               }
+                               cp.role = 0x01; /* Remain slave */
 
-               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ,
+                                                       sizeof(cp), &cp);
+               } else {
+                       struct hci_cp_accept_sync_conn_req cp;
 
-               hci_role_switch_cfm(conn, ev->status, ev->role);
-       }
+                       bacpy(&cp.bdaddr, &ev->bdaddr);
+                       cp.pkt_type = cpu_to_le16(hdev->esco_type);
 
-       hci_dev_unlock(hdev);
+                       cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
+                       cp.max_latency    = cpu_to_le16(0xffff);
+                       cp.content_format = cpu_to_le16(hdev->voice_setting);
+                       cp.retrans_effort = 0xff;
+
+                       hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
+                                                       sizeof(cp), &cp);
+               }
+       } else {
+               /* Connection rejected */
+               struct hci_cp_reject_conn_req cp;
+
+               bacpy(&cp.bdaddr, &ev->bdaddr);
+               cp.reason = 0x0f;
+               hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
+       }
 }
 
-/* Mode Change */
-static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data;
+       struct hci_ev_disconn_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
 
+       if (ev->status)
+               return;
+
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (conn) {
-               conn->mode = ev->mode;
-               conn->interval = __le16_to_cpu(ev->interval);
-
-               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
-                       if (conn->mode == HCI_CM_ACTIVE)
-                               conn->power_save = 1;
-                       else
-                               conn->power_save = 0;
-               }
+               conn->state = BT_CLOSED;
+               hci_proto_disconn_ind(conn, ev->reason);
+               hci_conn_del(conn);
        }
 
        hci_dev_unlock(hdev);
 }
 
-/* Authentication Complete */
 static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data;
+       struct hci_ev_auth_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -985,8 +853,8 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                                struct hci_cp_set_conn_encrypt cp;
                                cp.handle  = cpu_to_le16(conn->handle);
                                cp.encrypt = 1;
-                               hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-                                       OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
+                               hci_send_cmd(conn->hdev,
+                                       HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
                        } else {
                                clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
                                hci_encrypt_cfm(conn, ev->status, 0x00);
@@ -997,10 +865,16 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        hci_dev_unlock(hdev);
 }
 
-/* Encryption Change */
+static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+
+       hci_conn_check_pending(hdev);
+}
+
 static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data;
+       struct hci_ev_encrypt_change *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1024,10 +898,9 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-/* Change Connection Link Key Complete */
-static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data;
+       struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1047,25 +920,263 @@ static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, s
        hci_dev_unlock(hdev);
 }
 
-/* Pin Code Request*/
-static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-}
+       struct hci_ev_remote_features *ev = (void *) skb->data;
+       struct hci_conn *conn;
 
-/* Link Key Request */
-static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       if (ev->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+       if (conn)
+               memcpy(conn->features, ev->features, 8);
+
+       hci_dev_unlock(hdev);
 }
 
-/* Link Key Notification */
-static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       BT_DBG("%s", hdev->name);
 }
 
-/* Remote Features */
-static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data;
+       struct hci_ev_cmd_complete *ev = (void *) skb->data;
+       __u16 opcode;
+
+       skb_pull(skb, sizeof(*ev));
+
+       opcode = __le16_to_cpu(ev->opcode);
+
+       switch (opcode) {
+       case HCI_OP_INQUIRY_CANCEL:
+               hci_cc_inquiry_cancel(hdev, skb);
+               break;
+
+       case HCI_OP_EXIT_PERIODIC_INQ:
+               hci_cc_exit_periodic_inq(hdev, skb);
+               break;
+
+       case HCI_OP_REMOTE_NAME_REQ_CANCEL:
+               hci_cc_remote_name_req_cancel(hdev, skb);
+               break;
+
+       case HCI_OP_ROLE_DISCOVERY:
+               hci_cc_role_discovery(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_LINK_POLICY:
+               hci_cc_write_link_policy(hdev, skb);
+               break;
+
+       case HCI_OP_RESET:
+               hci_cc_reset(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_LOCAL_NAME:
+               hci_cc_write_local_name(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_NAME:
+               hci_cc_read_local_name(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_AUTH_ENABLE:
+               hci_cc_write_auth_enable(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_ENCRYPT_MODE:
+               hci_cc_write_encrypt_mode(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_SCAN_ENABLE:
+               hci_cc_write_scan_enable(hdev, skb);
+               break;
+
+       case HCI_OP_READ_CLASS_OF_DEV:
+               hci_cc_read_class_of_dev(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_CLASS_OF_DEV:
+               hci_cc_write_class_of_dev(hdev, skb);
+               break;
+
+       case HCI_OP_READ_VOICE_SETTING:
+               hci_cc_read_voice_setting(hdev, skb);
+               break;
+
+       case HCI_OP_WRITE_VOICE_SETTING:
+               hci_cc_write_voice_setting(hdev, skb);
+               break;
+
+       case HCI_OP_HOST_BUFFER_SIZE:
+               hci_cc_host_buffer_size(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_VERSION:
+               hci_cc_read_local_version(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_COMMANDS:
+               hci_cc_read_local_commands(hdev, skb);
+               break;
+
+       case HCI_OP_READ_LOCAL_FEATURES:
+               hci_cc_read_local_features(hdev, skb);
+               break;
+
+       case HCI_OP_READ_BUFFER_SIZE:
+               hci_cc_read_buffer_size(hdev, skb);
+               break;
+
+       case HCI_OP_READ_BD_ADDR:
+               hci_cc_read_bd_addr(hdev, skb);
+               break;
+
+       default:
+               BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+               break;
+       }
+
+       if (ev->ncmd) {
+               atomic_set(&hdev->cmd_cnt, 1);
+               if (!skb_queue_empty(&hdev->cmd_q))
+                       hci_sched_cmd(hdev);
+       }
+}
+
+static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_cmd_status *ev = (void *) skb->data;
+       __u16 opcode;
+
+       skb_pull(skb, sizeof(*ev));
+
+       opcode = __le16_to_cpu(ev->opcode);
+
+       switch (opcode) {
+       case HCI_OP_INQUIRY:
+               hci_cs_inquiry(hdev, ev->status);
+               break;
+
+       case HCI_OP_CREATE_CONN:
+               hci_cs_create_conn(hdev, ev->status);
+               break;
+
+       case HCI_OP_ADD_SCO:
+               hci_cs_add_sco(hdev, ev->status);
+               break;
+
+       case HCI_OP_REMOTE_NAME_REQ:
+               hci_cs_remote_name_req(hdev, ev->status);
+               break;
+
+       case HCI_OP_SETUP_SYNC_CONN:
+               hci_cs_setup_sync_conn(hdev, ev->status);
+               break;
+
+       case HCI_OP_SNIFF_MODE:
+               hci_cs_sniff_mode(hdev, ev->status);
+               break;
+
+       case HCI_OP_EXIT_SNIFF_MODE:
+               hci_cs_exit_sniff_mode(hdev, ev->status);
+               break;
+
+       default:
+               BT_DBG("%s opcode 0x%x", hdev->name, opcode);
+               break;
+       }
+
+       if (ev->ncmd) {
+               atomic_set(&hdev->cmd_cnt, 1);
+               if (!skb_queue_empty(&hdev->cmd_q))
+                       hci_sched_cmd(hdev);
+       }
+}
+
+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_role_change *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (conn) {
+               if (!ev->status) {
+                       if (ev->role)
+                               conn->link_mode &= ~HCI_LM_MASTER;
+                       else
+                               conn->link_mode |= HCI_LM_MASTER;
+               }
+
+               clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
+
+               hci_role_switch_cfm(conn, ev->status, ev->role);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
+       __le16 *ptr;
+       int i;
+
+       skb_pull(skb, sizeof(*ev));
+
+       BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
+
+       if (skb->len < ev->num_hndl * 4) {
+               BT_DBG("%s bad parameters", hdev->name);
+               return;
+       }
+
+       tasklet_disable(&hdev->tx_task);
+
+       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+               struct hci_conn *conn;
+               __u16  handle, count;
+
+               handle = __le16_to_cpu(get_unaligned(ptr++));
+               count  = __le16_to_cpu(get_unaligned(ptr++));
+
+               conn = hci_conn_hash_lookup_handle(hdev, handle);
+               if (conn) {
+                       conn->sent -= count;
+
+                       if (conn->type == ACL_LINK) {
+                               if ((hdev->acl_cnt += count) > hdev->acl_pkts)
+                                       hdev->acl_cnt = hdev->acl_pkts;
+                       } else {
+                               if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+                                       hdev->sco_cnt = hdev->sco_pkts;
+                       }
+               }
+       }
+
+       hci_sched_tx(hdev);
+
+       tasklet_enable(&hdev->tx_task);
+}
+
+static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_mode_change *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1073,17 +1184,39 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn && !ev->status) {
-               memcpy(conn->features, ev->features, sizeof(conn->features));
+       if (conn) {
+               conn->mode = ev->mode;
+               conn->interval = __le16_to_cpu(ev->interval);
+
+               if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
+                       if (conn->mode == HCI_CM_ACTIVE)
+                               conn->power_save = 1;
+                       else
+                               conn->power_save = 0;
+               }
        }
 
        hci_dev_unlock(hdev);
 }
 
-/* Clock Offset */
+static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
 static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data;
+       struct hci_ev_clock_offset *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1103,10 +1236,9 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        hci_dev_unlock(hdev);
 }
 
-/* Page Scan Repetition Mode */
 static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data;
+       struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
        struct inquiry_entry *ie;
 
        BT_DBG("%s", hdev->name);
@@ -1121,10 +1253,91 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
        hci_dev_unlock(hdev);
 }
 
-/* Sniff Subrate */
+static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct inquiry_data data;
+       int num_rsp = *((__u8 *) skb->data);
+
+       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
+
+       if (!num_rsp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
+               struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = info->pscan_mode;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       } else {
+               struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
+
+               for (; num_rsp; num_rsp--) {
+                       bacpy(&data.bdaddr, &info->bdaddr);
+                       data.pscan_rep_mode     = info->pscan_rep_mode;
+                       data.pscan_period_mode  = info->pscan_period_mode;
+                       data.pscan_mode         = 0x00;
+                       memcpy(data.dev_class, info->dev_class, 3);
+                       data.clock_offset       = info->clock_offset;
+                       data.rssi               = info->rssi;
+                       info++;
+                       hci_inquiry_cache_update(hdev, &data);
+               }
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
+static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status %d", hdev->name, ev->status);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
+       if (!conn)
+               goto unlock;
+
+       if (!ev->status) {
+               conn->handle = __le16_to_cpu(ev->handle);
+               conn->state  = BT_CONNECTED;
+       } else
+               conn->state = BT_CLOSED;
+
+       hci_proto_connect_cfm(conn, ev->status);
+       if (ev->status)
+               hci_conn_del(conn);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       BT_DBG("%s", hdev->name);
+}
+
 static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data;
+       struct hci_ev_sniff_subrate *ev = (void *) skb->data;
        struct hci_conn *conn;
 
        BT_DBG("%s status %d", hdev->name, ev->status);
@@ -1138,22 +1351,42 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s
        hci_dev_unlock(hdev);
 }
 
-void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data;
-       struct hci_ev_cmd_complete *ec;
-       struct hci_ev_cmd_status *cs;
-       u16 opcode, ocf, ogf;
+       struct inquiry_data data;
+       struct extended_inquiry_info *info = (void *) (skb->data + 1);
+       int num_rsp = *((__u8 *) skb->data);
 
-       skb_pull(skb, HCI_EVENT_HDR_SIZE);
+       BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
 
-       BT_DBG("%s evt 0x%x", hdev->name, hdr->evt);
+       if (!num_rsp)
+               return;
 
-       switch (hdr->evt) {
-       case HCI_EV_NUM_COMP_PKTS:
-               hci_num_comp_pkts_evt(hdev, skb);
-               break;
+       hci_dev_lock(hdev);
+
+       for (; num_rsp; num_rsp--) {
+               bacpy(&data.bdaddr, &info->bdaddr);
+               data.pscan_rep_mode     = info->pscan_rep_mode;
+               data.pscan_period_mode  = info->pscan_period_mode;
+               data.pscan_mode         = 0x00;
+               memcpy(data.dev_class, info->dev_class, 3);
+               data.clock_offset       = info->clock_offset;
+               data.rssi               = info->rssi;
+               info++;
+               hci_inquiry_cache_update(hdev, &data);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_event_hdr *hdr = (void *) skb->data;
+       __u8 event = hdr->evt;
+
+       skb_pull(skb, HCI_EVENT_HDR_SIZE);
 
+       switch (event) {
        case HCI_EV_INQUIRY_COMPLETE:
                hci_inquiry_complete_evt(hdev, skb);
                break;
@@ -1162,44 +1395,64 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_inquiry_result_evt(hdev, skb);
                break;
 
-       case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
-               hci_inquiry_result_with_rssi_evt(hdev, skb);
-               break;
-
-       case HCI_EV_EXTENDED_INQUIRY_RESULT:
-               hci_extended_inquiry_result_evt(hdev, skb);
+       case HCI_EV_CONN_COMPLETE:
+               hci_conn_complete_evt(hdev, skb);
                break;
 
        case HCI_EV_CONN_REQUEST:
                hci_conn_request_evt(hdev, skb);
                break;
 
-       case HCI_EV_CONN_COMPLETE:
-               hci_conn_complete_evt(hdev, skb);
-               break;
-
        case HCI_EV_DISCONN_COMPLETE:
                hci_disconn_complete_evt(hdev, skb);
                break;
 
-       case HCI_EV_ROLE_CHANGE:
-               hci_role_change_evt(hdev, skb);
-               break;
-
-       case HCI_EV_MODE_CHANGE:
-               hci_mode_change_evt(hdev, skb);
-               break;
-
        case HCI_EV_AUTH_COMPLETE:
                hci_auth_complete_evt(hdev, skb);
                break;
 
+       case HCI_EV_REMOTE_NAME:
+               hci_remote_name_evt(hdev, skb);
+               break;
+
        case HCI_EV_ENCRYPT_CHANGE:
                hci_encrypt_change_evt(hdev, skb);
                break;
 
-       case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
-               hci_change_conn_link_key_complete_evt(hdev, skb);
+       case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
+               hci_change_link_key_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_FEATURES:
+               hci_remote_features_evt(hdev, skb);
+               break;
+
+       case HCI_EV_REMOTE_VERSION:
+               hci_remote_version_evt(hdev, skb);
+               break;
+
+       case HCI_EV_QOS_SETUP_COMPLETE:
+               hci_qos_setup_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_CMD_COMPLETE:
+               hci_cmd_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_CMD_STATUS:
+               hci_cmd_status_evt(hdev, skb);
+               break;
+
+       case HCI_EV_ROLE_CHANGE:
+               hci_role_change_evt(hdev, skb);
+               break;
+
+       case HCI_EV_NUM_COMP_PKTS:
+               hci_num_comp_pkts_evt(hdev, skb);
+               break;
+
+       case HCI_EV_MODE_CHANGE:
+               hci_mode_change_evt(hdev, skb);
                break;
 
        case HCI_EV_PIN_CODE_REQ:
@@ -1214,10 +1467,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_link_key_notify_evt(hdev, skb);
                break;
 
-       case HCI_EV_REMOTE_FEATURES:
-               hci_remote_features_evt(hdev, skb);
-               break;
-
        case HCI_EV_CLOCK_OFFSET:
                hci_clock_offset_evt(hdev, skb);
                break;
@@ -1226,82 +1475,32 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_pscan_rep_mode_evt(hdev, skb);
                break;
 
-       case HCI_EV_SNIFF_SUBRATE:
-               hci_sniff_subrate_evt(hdev, skb);
+       case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
+               hci_inquiry_result_with_rssi_evt(hdev, skb);
                break;
 
-       case HCI_EV_CMD_STATUS:
-               cs = (struct hci_ev_cmd_status *) skb->data;
-               skb_pull(skb, sizeof(cs));
-
-               opcode = __le16_to_cpu(cs->opcode);
-               ogf = hci_opcode_ogf(opcode);
-               ocf = hci_opcode_ocf(opcode);
-
-               switch (ogf) {
-               case OGF_INFO_PARAM:
-                       hci_cs_info_param(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_HOST_CTL:
-                       hci_cs_host_ctl(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_LINK_CTL:
-                       hci_cs_link_ctl(hdev, ocf, cs->status);
-                       break;
-
-               case OGF_LINK_POLICY:
-                       hci_cs_link_policy(hdev, ocf, cs->status);
-                       break;
-
-               default:
-                       BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
-                       break;
-               }
-
-               if (cs->ncmd) {
-                       atomic_set(&hdev->cmd_cnt, 1);
-                       if (!skb_queue_empty(&hdev->cmd_q))
-                               hci_sched_cmd(hdev);
-               }
+       case HCI_EV_REMOTE_EXT_FEATURES:
+               hci_remote_ext_features_evt(hdev, skb);
                break;
 
-       case HCI_EV_CMD_COMPLETE:
-               ec = (struct hci_ev_cmd_complete *) skb->data;
-               skb_pull(skb, sizeof(*ec));
-
-               opcode = __le16_to_cpu(ec->opcode);
-               ogf = hci_opcode_ogf(opcode);
-               ocf = hci_opcode_ocf(opcode);
-
-               switch (ogf) {
-               case OGF_INFO_PARAM:
-                       hci_cc_info_param(hdev, ocf, skb);
-                       break;
-
-               case OGF_HOST_CTL:
-                       hci_cc_host_ctl(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SYNC_CONN_COMPLETE:
+               hci_sync_conn_complete_evt(hdev, skb);
+               break;
 
-               case OGF_LINK_CTL:
-                       hci_cc_link_ctl(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SYNC_CONN_CHANGED:
+               hci_sync_conn_changed_evt(hdev, skb);
+               break;
 
-               case OGF_LINK_POLICY:
-                       hci_cc_link_policy(hdev, ocf, skb);
-                       break;
+       case HCI_EV_SNIFF_SUBRATE:
+               hci_sniff_subrate_evt(hdev, skb);
+               break;
 
-               default:
-                       BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-                       break;
-               }
+       case HCI_EV_EXTENDED_INQUIRY_RESULT:
+               hci_extended_inquiry_result_evt(hdev, skb);
+               break;
 
-               if (ec->ncmd) {
-                       atomic_set(&hdev->cmd_cnt, 1);
-                       if (!skb_queue_empty(&hdev->cmd_q))
-                               hci_sched_cmd(hdev);
-               }
+       default:
+               BT_DBG("%s event 0x%x", hdev->name, event);
                break;
        }
 
index 43dd637..8825102 100644 (file)
@@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto drop;
                }
 
-               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
+               if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
                        skb_queue_tail(&hdev->raw_q, skb);
                        hci_sched_tx(hdev);
                } else {
index 2583540..cef1e3e 100644 (file)
@@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
        return sprintf(buf, "%s\n", typetostr(hdev->type));
 }
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+       char name[249];
+       int i;
+
+       for (i = 0; i < 248; i++)
+               name[i] = hdev->dev_name[i];
+
+       name[248] = '\0';
+       return sprintf(buf, "%s\n", name);
+}
+
+static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+       return sprintf(buf, "0x%.2x%.2x%.2x\n",
+                       hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
+}
+
 static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
        return sprintf(buf, "%s\n", batostr(&bdaddr));
 }
 
+static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct hci_dev *hdev = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                               hdev->features[0], hdev->features[1],
+                               hdev->features[2], hdev->features[3],
+                               hdev->features[4], hdev->features[5],
+                               hdev->features[6], hdev->features[7]);
+}
+
 static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
@@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
 }
 
 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
 static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
 static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
 static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
@@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
 
 static struct device_attribute *bt_attrs[] = {
        &dev_attr_type,
+       &dev_attr_name,
+       &dev_attr_class,
        &dev_attr_address,
+       &dev_attr_features,
        &dev_attr_manufacturer,
        &dev_attr_hci_version,
        &dev_attr_hci_revision,
index 66c7369..4bbacdd 100644 (file)
@@ -247,7 +247,7 @@ static inline int hidp_queue_report(struct hidp_session *session, unsigned char
 {
        struct sk_buff *skb;
 
-       BT_DBG("session %p hid %p data %p size %d", session, device, data, size);
+       BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
 
        if (!(skb = alloc_skb(size + 1, GFP_ATOMIC))) {
                BT_ERR("Can't allocate memory for new frame");
index 36ef27b..6fbbae7 100644 (file)
@@ -55,7 +55,9 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.8"
+#define VERSION "2.9"
+
+static u32 l2cap_feat_mask = 0x0000;
 
 static const struct proto_ops l2cap_sock_ops;
 
@@ -258,7 +260,119 @@ static void l2cap_chan_del(struct sock *sk, int err)
                sk->sk_state_change(sk);
 }
 
+static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
+{
+       u8 id;
+
+       /* Get next available identificator.
+        *    1 - 128 are used by kernel.
+        *  129 - 199 are reserved.
+        *  200 - 254 are used by utilities like l2ping, etc.
+        */
+
+       spin_lock_bh(&conn->lock);
+
+       if (++conn->tx_ident > 128)
+               conn->tx_ident = 1;
+
+       id = conn->tx_ident;
+
+       spin_unlock_bh(&conn->lock);
+
+       return id;
+}
+
+static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+{
+       struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
+
+       BT_DBG("code 0x%2.2x", code);
+
+       if (!skb)
+               return -ENOMEM;
+
+       return hci_send_acl(conn->hcon, skb, 0);
+}
+
 /* ---- L2CAP connections ---- */
+static void l2cap_conn_start(struct l2cap_conn *conn)
+{
+       struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock *sk;
+
+       BT_DBG("conn %p", conn);
+
+       read_lock(&l->lock);
+
+       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               bh_lock_sock(sk);
+
+               if (sk->sk_type != SOCK_SEQPACKET) {
+                       l2cap_sock_clear_timer(sk);
+                       sk->sk_state = BT_CONNECTED;
+                       sk->sk_state_change(sk);
+               } else if (sk->sk_state == BT_CONNECT) {
+                       struct l2cap_conn_req req;
+                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
+                       req.psm  = l2cap_pi(sk)->psm;
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_REQ, sizeof(req), &req);
+               }
+
+               bh_unlock_sock(sk);
+       }
+
+       read_unlock(&l->lock);
+}
+
+static void l2cap_conn_ready(struct l2cap_conn *conn)
+{
+       BT_DBG("conn %p", conn);
+
+       if (conn->chan_list.head || !hlist_empty(&l2cap_sk_list.head)) {
+               struct l2cap_info_req req;
+
+               req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
+               conn->info_ident = l2cap_get_ident(conn);
+
+               mod_timer(&conn->info_timer,
+                       jiffies + msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
+
+               l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(req), &req);
+       }
+}
+
+/* Notify sockets that we cannot guaranty reliability anymore */
+static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
+{
+       struct l2cap_chan_list *l = &conn->chan_list;
+       struct sock *sk;
+
+       BT_DBG("conn %p", conn);
+
+       read_lock(&l->lock);
+
+       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+                       sk->sk_err = err;
+       }
+
+       read_unlock(&l->lock);
+}
+
+static void l2cap_info_timeout(unsigned long arg)
+{
+       struct l2cap_conn *conn = (void *) arg;
+
+       conn->info_ident = 0;
+
+       l2cap_conn_start(conn);
+}
+
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
@@ -279,6 +393,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        conn->src = &hcon->hdev->bdaddr;
        conn->dst = &hcon->dst;
 
+       conn->feat_mask = 0;
+
+       init_timer(&conn->info_timer);
+       conn->info_timer.function = l2cap_info_timeout;
+       conn->info_timer.data = (unsigned long) conn;
+
        spin_lock_init(&conn->lock);
        rwlock_init(&conn->chan_list.lock);
 
@@ -318,40 +438,6 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, stru
        write_unlock_bh(&l->lock);
 }
 
-static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
-{
-       u8 id;
-
-       /* Get next available identificator.
-        *    1 - 128 are used by kernel.
-        *  129 - 199 are reserved.
-        *  200 - 254 are used by utilities like l2ping, etc.
-        */
-
-       spin_lock_bh(&conn->lock);
-
-       if (++conn->tx_ident > 128)
-               conn->tx_ident = 1;
-
-       id = conn->tx_ident;
-
-       spin_unlock_bh(&conn->lock);
-
-       return id;
-}
-
-static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
-{
-       struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
-
-       BT_DBG("code 0x%2.2x", code);
-
-       if (!skb)
-               return -ENOMEM;
-
-       return hci_send_acl(conn->hcon, skb, 0);
-}
-
 /* ---- Socket interface ---- */
 static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
 {
@@ -508,7 +594,6 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
        /* Default config options */
        pi->conf_len = 0;
-       pi->conf_mtu = L2CAP_DEFAULT_MTU;
        pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
 }
 
@@ -530,7 +615,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
        INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 
        sk->sk_destruct = l2cap_sock_destruct;
-       sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
+       sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
 
        sock_reset_flag(sk, SOCK_ZAPPED);
 
@@ -650,6 +735,11 @@ static int l2cap_do_connect(struct sock *sk)
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
        if (hcon->state == BT_CONNECTED) {
+               if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
+                       l2cap_conn_ready(conn);
+                       goto done;
+               }
+
                if (sk->sk_type == SOCK_SEQPACKET) {
                        struct l2cap_conn_req req;
                        l2cap_pi(sk)->ident = l2cap_get_ident(conn);
@@ -958,7 +1048,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                opts.imtu     = l2cap_pi(sk)->imtu;
                opts.omtu     = l2cap_pi(sk)->omtu;
                opts.flush_to = l2cap_pi(sk)->flush_to;
-               opts.mode     = 0x00;
+               opts.mode     = L2CAP_MODE_BASIC;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -1007,7 +1097,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                opts.imtu     = l2cap_pi(sk)->imtu;
                opts.omtu     = l2cap_pi(sk)->omtu;
                opts.flush_to = l2cap_pi(sk)->flush_to;
-               opts.mode     = 0x00;
+               opts.mode     = L2CAP_MODE_BASIC;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -1084,52 +1174,6 @@ static int l2cap_sock_release(struct socket *sock)
        return err;
 }
 
-static void l2cap_conn_ready(struct l2cap_conn *conn)
-{
-       struct l2cap_chan_list *l = &conn->chan_list;
-       struct sock *sk;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               bh_lock_sock(sk);
-
-               if (sk->sk_type != SOCK_SEQPACKET) {
-                       l2cap_sock_clear_timer(sk);
-                       sk->sk_state = BT_CONNECTED;
-                       sk->sk_state_change(sk);
-               } else if (sk->sk_state == BT_CONNECT) {
-                       struct l2cap_conn_req req;
-                       l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-                       req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-                       req.psm  = l2cap_pi(sk)->psm;
-                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_REQ, sizeof(req), &req);
-               }
-
-               bh_unlock_sock(sk);
-       }
-
-       read_unlock(&l->lock);
-}
-
-/* Notify sockets that we cannot guaranty reliability anymore */
-static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
-{
-       struct l2cap_chan_list *l = &conn->chan_list;
-       struct sock *sk;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
-                       sk->sk_err = err;
-       }
-       read_unlock(&l->lock);
-}
-
 static void l2cap_chan_ready(struct sock *sk)
 {
        struct sock *parent = bt_sk(sk)->parent;
@@ -1256,11 +1300,11 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned
                break;
 
        case 2:
-               *val = __le16_to_cpu(*((__le16 *)opt->val));
+               *val = __le16_to_cpu(*((__le16 *) opt->val));
                break;
 
        case 4:
-               *val = __le32_to_cpu(*((__le32 *)opt->val));
+               *val = __le32_to_cpu(*((__le32 *) opt->val));
                break;
 
        default:
@@ -1332,6 +1376,8 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
        int len = pi->conf_len;
        int type, hint, olen;
        unsigned long val;
+       struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
 
        BT_DBG("sk %p", sk);
@@ -1344,7 +1390,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
 
                switch (type) {
                case L2CAP_CONF_MTU:
-                       pi->conf_mtu = val;
+                       mtu = val;
                        break;
 
                case L2CAP_CONF_FLUSH_TO:
@@ -1354,6 +1400,11 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
                case L2CAP_CONF_QOS:
                        break;
 
+               case L2CAP_CONF_RFC:
+                       if (olen == sizeof(rfc))
+                               memcpy(&rfc, (void *) val, olen);
+                       break;
+
                default:
                        if (hint)
                                break;
@@ -1368,12 +1419,24 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data)
                /* Configure output options and let the other side know
                 * which ones we don't like. */
 
-               if (pi->conf_mtu < pi->omtu)
+               if (rfc.mode == L2CAP_MODE_BASIC) {
+                       if (mtu < pi->omtu)
+                               result = L2CAP_CONF_UNACCEPT;
+                       else {
+                               pi->omtu = mtu;
+                               pi->conf_state |= L2CAP_CONF_OUTPUT_DONE;
+                       }
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+               } else {
                        result = L2CAP_CONF_UNACCEPT;
-               else
-                       pi->omtu = pi->conf_mtu;
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu);
+                       memset(&rfc, 0, sizeof(rfc));
+                       rfc.mode = L2CAP_MODE_BASIC;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
+                                               sizeof(rfc), (unsigned long) &rfc);
+               }
        }
 
        rsp->scid   = cpu_to_le16(pi->dcid);
@@ -1397,6 +1460,23 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
        return ptr - data;
 }
 
+static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+       struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
+
+       if (rej->reason != 0x0000)
+               return 0;
+
+       if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
+                                       cmd->ident == conn->info_ident) {
+               conn->info_ident = 0;
+               del_timer(&conn->info_timer);
+               l2cap_conn_start(conn);
+       }
+
+       return 0;
+}
+
 static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_chan_list *list = &conn->chan_list;
@@ -1577,16 +1657,19 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
 
-       /* Output config done. */
-       l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-
        /* Reset config buffer. */
        l2cap_pi(sk)->conf_len = 0;
 
+       if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE))
+               goto unlock;
+
        if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
                sk->sk_state = BT_CONNECTED;
                l2cap_chan_ready(sk);
-       } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
+               goto unlock;
+       }
+
+       if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
                u8 req[64];
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(sk, req), req);
@@ -1646,7 +1729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (flags & 0x01)
                goto done;
 
-       /* Input config done */
        l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
 
        if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
@@ -1711,16 +1793,27 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_req *req = (struct l2cap_info_req *) data;
-       struct l2cap_info_rsp rsp;
        u16 type;
 
        type = __le16_to_cpu(req->type);
 
        BT_DBG("type 0x%4.4x", type);
 
-       rsp.type   = cpu_to_le16(type);
-       rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
-       l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+       if (type == L2CAP_IT_FEAT_MASK) {
+               u8 buf[8];
+               struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+               rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
+               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+       } else {
+               struct l2cap_info_rsp rsp;
+               rsp.type   = cpu_to_le16(type);
+               rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+       }
 
        return 0;
 }
@@ -1735,6 +1828,15 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
+       conn->info_ident = 0;
+
+       del_timer(&conn->info_timer);
+
+       if (type == L2CAP_IT_FEAT_MASK)
+               conn->feat_mask = __le32_to_cpu(get_unaligned((__le32 *) rsp->data));
+
+       l2cap_conn_start(conn);
+
        return 0;
 }
 
@@ -1764,7 +1866,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *sk
 
                switch (cmd.code) {
                case L2CAP_COMMAND_REJ:
-                       /* FIXME: We should process this */
+                       l2cap_command_rej(conn, &cmd, data);
                        break;
 
                case L2CAP_CONN_REQ:
index bb72207..e7ac6ba 100644 (file)
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/init.h>
-#include <linux/freezer.h>
 #include <linux/wait.h>
 #include <linux/device.h>
 #include <linux/net.h>
 #include <linux/mutex.h>
+#include <linux/kthread.h>
 
 #include <net/sock.h>
 #include <asm/uaccess.h>
@@ -68,7 +68,6 @@ static DEFINE_MUTEX(rfcomm_mutex);
 static unsigned long rfcomm_event;
 
 static LIST_HEAD(session_list);
-static atomic_t terminate, running;
 
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
@@ -1850,26 +1849,6 @@ static inline void rfcomm_process_sessions(void)
        rfcomm_unlock();
 }
 
-static void rfcomm_worker(void)
-{
-       BT_DBG("");
-
-       while (!atomic_read(&terminate)) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-                       /* No pending events. Let's sleep.
-                        * Incoming connections and data will wake us up. */
-                       schedule();
-               }
-               set_current_state(TASK_RUNNING);
-
-               /* Process stuff */
-               clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-               rfcomm_process_sessions();
-       }
-       return;
-}
-
 static int rfcomm_add_listener(bdaddr_t *ba)
 {
        struct sockaddr_l2 addr;
@@ -1935,22 +1914,28 @@ static void rfcomm_kill_listener(void)
 
 static int rfcomm_run(void *unused)
 {
-       rfcomm_thread = current;
-
-       atomic_inc(&running);
+       BT_DBG("");
 
-       daemonize("krfcommd");
        set_user_nice(current, -10);
 
-       BT_DBG("");
-
        rfcomm_add_listener(BDADDR_ANY);
 
-       rfcomm_worker();
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+                       /* No pending events. Let's sleep.
+                        * Incoming connections and data will wake us up. */
+                       schedule();
+               }
+               set_current_state(TASK_RUNNING);
+
+               /* Process stuff */
+               clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
+               rfcomm_process_sessions();
+       }
 
        rfcomm_kill_listener();
 
-       atomic_dec(&running);
        return 0;
 }
 
@@ -2059,7 +2044,11 @@ static int __init rfcomm_init(void)
 
        hci_register_cb(&rfcomm_cb);
 
-       kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
+       rfcomm_thread = kthread_run(rfcomm_run, NULL, "krfcommd");
+       if (IS_ERR(rfcomm_thread)) {
+               hci_unregister_cb(&rfcomm_cb);
+               return PTR_ERR(rfcomm_thread);
+       }
 
        if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
                BT_ERR("Failed to create RFCOMM info file");
@@ -2081,14 +2070,7 @@ static void __exit rfcomm_exit(void)
 
        hci_unregister_cb(&rfcomm_cb);
 
-       /* Terminate working thread.
-        * ie. Set terminate flag and wake it up */
-       atomic_inc(&terminate);
-       rfcomm_schedule(RFCOMM_SCHED_STATE);
-
-       /* Wait until thread is running */
-       while (atomic_read(&running))
-               schedule();
+       kthread_stop(rfcomm_thread);
 
 #ifdef CONFIG_BT_RFCOMM_TTY
        rfcomm_cleanup_ttys();
index 22a8320..e447651 100644 (file)
@@ -189,6 +189,23 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
        return conn ? &conn->dev : NULL;
 }
 
+static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       bdaddr_t bdaddr;
+       baswap(&bdaddr, &dev->dst);
+       return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
+{
+       struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
+       return sprintf(buf, "%d\n", dev->channel);
+}
+
+static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
+
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
        struct rfcomm_dev *dev;
@@ -281,6 +298,14 @@ out:
                return err;
        }
 
+       dev_set_drvdata(dev->tty_dev, dev);
+
+       if (device_create_file(dev->tty_dev, &dev_attr_address) < 0)
+               BT_ERR("Failed to create address attribute");
+
+       if (device_create_file(dev->tty_dev, &dev_attr_channel) < 0)
+               BT_ERR("Failed to create channel attribute");
+
        return dev->id;
 }
 
index 65b6fb1..82d0dfd 100644 (file)
@@ -189,7 +189,7 @@ static int sco_connect(struct sock *sk)
        struct sco_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev  *hdev;
-       int err = 0;
+       int err, type;
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
@@ -200,7 +200,9 @@ static int sco_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       hcon = hci_connect(hdev, SCO_LINK, dst);
+       type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK;
+
+       hcon = hci_connect(hdev, type, dst);
        if (!hcon)
                goto done;
 
@@ -224,6 +226,7 @@ static int sco_connect(struct sock *sk)
                sk->sk_state = BT_CONNECT;
                sco_sock_set_timer(sk, sk->sk_sndtimeo);
        }
+
 done:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -846,7 +849,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
-       if (hcon->type != SCO_LINK)
+       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
                return 0;
 
        if (!status) {
@@ -865,10 +868,11 @@ static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
-       if (hcon->type != SCO_LINK)
+       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
                return 0;
 
        sco_conn_del(hcon, bt_err(reason));
+
        return 0;
 }
 
index 38b03da..8726589 100644 (file)
@@ -1553,7 +1553,7 @@ gso:
                        return rc;
                }
                if (unlikely((netif_queue_stopped(dev) ||
-                            netif_subqueue_stopped(dev, skb->queue_mapping)) &&
+                            netif_subqueue_stopped(dev, skb)) &&
                             skb->next))
                        return NETDEV_TX_BUSY;
        } while (skb->next);
@@ -1661,7 +1661,7 @@ gso:
                q = dev->qdisc;
                if (q->enqueue) {
                        /* reset queue_mapping to zero */
-                       skb->queue_mapping = 0;
+                       skb_set_queue_mapping(skb, 0);
                        rc = q->enqueue(skb, q);
                        qdisc_run(dev);
                        spin_unlock(&dev->queue_lock);
@@ -1692,7 +1692,7 @@ gso:
                        HARD_TX_LOCK(dev, cpu);
 
                        if (!netif_queue_stopped(dev) &&
-                           !netif_subqueue_stopped(dev, skb->queue_mapping)) {
+                           !netif_subqueue_stopped(dev, skb)) {
                                rc = 0;
                                if (!dev_hard_start_xmit(skb, dev)) {
                                        HARD_TX_UNLOCK(dev);
index 67ba991..05979e3 100644 (file)
@@ -1438,6 +1438,9 @@ int neigh_table_clear(struct neigh_table *tbl)
        free_percpu(tbl->stats);
        tbl->stats = NULL;
 
+       kmem_cache_destroy(tbl->kmem_cachep);
+       tbl->kmem_cachep = NULL;
+
        return 0;
 }
 
index 95daba6..bf8d18f 100644 (file)
@@ -67,7 +67,7 @@ static void queue_process(struct work_struct *work)
                local_irq_save(flags);
                netif_tx_lock(dev);
                if ((netif_queue_stopped(dev) ||
-                    netif_subqueue_stopped(dev, skb->queue_mapping)) ||
+                    netif_subqueue_stopped(dev, skb)) ||
                     dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
                        skb_queue_head(&npinfo->txq, skb);
                        netif_tx_unlock(dev);
@@ -269,7 +269,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
                     tries > 0; --tries) {
                        if (netif_tx_trylock(dev)) {
                                if (!netif_queue_stopped(dev) &&
-                                   !netif_subqueue_stopped(dev, skb->queue_mapping))
+                                   !netif_subqueue_stopped(dev, skb))
                                        status = dev->hard_start_xmit(skb, dev);
                                netif_tx_unlock(dev);
 
index c4719ed..de33f36 100644 (file)
@@ -2603,8 +2603,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct iphdr);
        skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
-       skb->queue_mapping = pkt_dev->cur_queue_map;
-
+       skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
        iph = ip_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -2941,8 +2940,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
        skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
-       skb->queue_mapping = pkt_dev->cur_queue_map;
-
+       skb_set_queue_mapping(skb, pkt_dev->cur_queue_map);
        iph = ipv6_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -3385,7 +3383,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
        if ((netif_queue_stopped(odev) ||
             (pkt_dev->skb &&
-             netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping))) ||
+             netif_subqueue_stopped(odev, pkt_dev->skb))) ||
            need_resched()) {
                idle_start = getCurUs();
 
@@ -3402,7 +3400,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                pkt_dev->idle_acc += getCurUs() - idle_start;
 
                if (netif_queue_stopped(odev) ||
-                   netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+                   netif_subqueue_stopped(odev, pkt_dev->skb)) {
                        pkt_dev->next_tx_us = getCurUs();       /* TODO */
                        pkt_dev->next_tx_ns = 0;
                        goto out;       /* Try the next interface */
@@ -3431,7 +3429,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
        netif_tx_lock_bh(odev);
        if (!netif_queue_stopped(odev) &&
-           !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
+           !netif_subqueue_stopped(odev, pkt_dev->skb)) {
 
                atomic_inc(&(pkt_dev->skb->users));
              retry_now:
index 0f37455..d8a3509 100644 (file)
@@ -68,3 +68,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, DCCPDIAG_GETSOCK);
index 44f6e17..222549a 100644 (file)
@@ -1037,8 +1037,8 @@ module_exit(dccp_v4_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");
index cac5354..bbadd66 100644 (file)
@@ -1219,8 +1219,8 @@ module_exit(dccp_v6_exit);
  * values directly, Also cover the case where the protocol is not specified,
  * i.e. net-pf-PF_INET6-proto-0-type-SOCK_DCCP
  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-33-type-6");
-MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-0-type-6");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 33, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 0, 6);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCPv6 - Datagram Congestion Controlled Protocol");
index 7eb83eb..dc429b6 100644 (file)
@@ -815,6 +815,12 @@ static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
            nlmsg_len(nlh) < hdrlen)
                return -EINVAL;
 
+#ifdef CONFIG_KMOD
+       if (inet_diag_table[nlh->nlmsg_type] == NULL)
+               request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+                              NETLINK_INET_DIAG, nlh->nlmsg_type);
+#endif
+
        if (inet_diag_table[nlh->nlmsg_type] == NULL)
                return -ENOENT;
 
@@ -914,3 +920,4 @@ static void __exit inet_diag_exit(void)
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_INET_DIAG);
index 3904d21..2fbcc7d 100644 (file)
@@ -56,3 +56,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_INET_DIAG, TCPDIAG_GETSOCK);
index 67cd066..66a9139 100644 (file)
@@ -483,6 +483,7 @@ static int ah6_init_state(struct xfrm_state *x)
                break;
        case XFRM_MODE_TUNNEL:
                x->props.header_len += sizeof(struct ipv6hdr);
+               break;
        default:
                goto error;
        }
index b071543..72a6598 100644 (file)
@@ -360,6 +360,7 @@ static int esp6_init_state(struct xfrm_state *x)
                break;
        case XFRM_MODE_TUNNEL:
                x->props.header_len += sizeof(struct ipv6hdr);
+               break;
        default:
                goto error;
        }
index be57cf3..421281d 100644 (file)
@@ -266,7 +266,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
        int busy;
        int nores;
        int len = skb->len;
-       int subq = skb->queue_mapping;
+       int subq = skb_get_queue_mapping(skb);
        struct sk_buff *skb_res = NULL;
 
        start = master->slaves;
@@ -284,7 +284,7 @@ restart:
                if (slave->qdisc_sleeping != q)
                        continue;
                if (netif_queue_stopped(slave) ||
-                   netif_subqueue_stopped(slave, subq) ||
+                   __netif_subqueue_stopped(slave, subq) ||
                    !netif_running(slave)) {
                        busy = 1;
                        continue;
@@ -294,7 +294,7 @@ restart:
                case 0:
                        if (netif_tx_trylock(slave)) {
                                if (!netif_queue_stopped(slave) &&
-                                   !netif_subqueue_stopped(slave, subq) &&
+                                   !__netif_subqueue_stopped(slave, subq) &&
                                    slave->hard_start_xmit(skb, slave) == 0) {
                                        netif_tx_unlock(slave);
                                        master->slaves = NEXT_SLAVE(q);