Commit 46fc7407 authored by David S. Miller's avatar David S. Miller

Merge

parents 4547e81c b9ec4b7d
...@@ -1394,7 +1394,9 @@ S: USA ...@@ -1394,7 +1394,9 @@ S: USA
N: Marcel Holtmann N: Marcel Holtmann
E: marcel@holtmann.org E: marcel@holtmann.org
W: http://www.holtmann.org W: http://www.holtmann.org
D: Maintainer of the Linux Bluetooth Subsystem
D: Author and maintainer of the various Bluetooth HCI drivers D: Author and maintainer of the various Bluetooth HCI drivers
D: Author and maintainer of the CAPI message transport protocol driver
D: Various other Bluetooth related patches, cleanups and fixes D: Various other Bluetooth related patches, cleanups and fixes
S: Germany S: Germany
......
...@@ -338,35 +338,64 @@ L: linux-kernel@vger.kernel.org ...@@ -338,35 +338,64 @@ L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
BLUETOOTH SUBSYSTEM BLUETOOTH SUBSYSTEM
P: Marcel Holtmann
M: marcel@holtmann.org
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
L: bluez-devel@lists.sf.net
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained S: Maintained
BLUETOOTH RFCOMM LAYER BLUETOOTH RFCOMM LAYER
P: Marcel Holtmann
M: marcel@holtmann.org
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained S: Maintained
BLUETOOTH BNEP LAYER BLUETOOTH BNEP LAYER
P: Marcel Holtmann
M: marcel@holtmann.org
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained S: Maintained
BLUETOOTH CMTP LAYER
P: Marcel Holtmann
M: marcel@holtmann.org
W: http://www.holtmann.org/linux/bluetooth/
S: Maintained
BLUETOOTH HCI USB DRIVER BLUETOOTH HCI USB DRIVER
P: Marcel Holtmann
M: marcel@holtmann.org
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained S: Maintained
BLUETOOTH HCI UART DRIVER BLUETOOTH HCI UART DRIVER
P: Marcel Holtmann
M: marcel@holtmann.org
P: Maxim Krasnyansky P: Maxim Krasnyansky
M: maxk@qualcomm.com M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained S: Maintained
BLUETOOTH HCI BCM203X DRIVER
P: Marcel Holtmann
M: marcel@holtmann.org
W: http://www.holtmann.org/linux/bluetooth/
S: Maintained
BLUETOOTH HCI BFUSB DRIVER
P: Marcel Holtmann
M: marcel@holtmann.org
W: http://www.holtmann.org/linux/bluetooth/
S: Maintained
BLUETOOTH HCI DTL1 DRIVER BLUETOOTH HCI DTL1 DRIVER
P: Marcel Holtmann P: Marcel Holtmann
M: marcel@holtmann.org M: marcel@holtmann.org
......
...@@ -13,22 +13,14 @@ config BT_HCIUSB ...@@ -13,22 +13,14 @@ config BT_HCIUSB
Say Y here to compile support for Bluetooth USB devices into the Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (hci_usb). kernel or say M to compile it as module (hci_usb).
config BT_USB_SCO config BT_HCIUSB_SCO
bool "SCO over HCI USB support" bool "SCO (voice) support"
depends on BT_HCIUSB depends on BT_HCIUSB
help help
This option enables the SCO support in the HCI USB driver. You need this This option enables the SCO support in the HCI USB driver. You need this
to transmit voice data with your Bluetooth USB device. to transmit voice data with your Bluetooth USB device.
Say Y here to compile support for SCO over HCI USB.
config BT_USB_ZERO_PACKET Say Y here to compile support for SCO over HCI USB.
bool "USB zero packet support"
depends on BT_HCIUSB
help
This option is provided only as a work around for buggy Bluetooth USB
devices. Do _not_ enable it unless you know for sure that your device
requires zero packets.
Most people should say N here.
config BT_HCIUART config BT_HCIUART
tristate "HCI UART driver" tristate "HCI UART driver"
...@@ -72,6 +64,31 @@ config BT_HCIUART_BCSP_TXCRC ...@@ -72,6 +64,31 @@ config BT_HCIUART_BCSP_TXCRC
every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
This increases reliability, but slightly reduces efficiency. This increases reliability, but slightly reduces efficiency.
config BT_HCIBCM203X
tristate "HCI BCM203x USB driver"
depends on USB && BT
select FW_LOADER
help
Bluetooth HCI BCM203x USB driver.
This driver provides the firmware loading mechanism for the Broadcom
Blutonium based devices.
Say Y here to compile support for HCI BCM203x devices into the
kernel or say M to compile it as module (bcm203x).
config BT_HCIBFUSB
tristate "HCI BlueFRITZ! USB driver"
depends on USB && BT
select FW_LOADER
help
Bluetooth HCI BlueFRITZ! USB driver.
This driver provides support for Bluetooth USB devices with AVM
interface:
AVM BlueFRITZ! USB
Say Y here to compile support for HCI BFUSB devices into the
kernel or say M to compile it as module (bfusb).
config BT_HCIDTL1 config BT_HCIDTL1
tristate "HCI DTL1 (PC Card) driver" tristate "HCI DTL1 (PC Card) driver"
depends on PCMCIA && BT depends on PCMCIA && BT
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
obj-$(CONFIG_BT_HCIUSB) += hci_usb.o obj-$(CONFIG_BT_HCIUSB) += hci_usb.o
obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o
obj-$(CONFIG_BT_HCIUART) += hci_uart.o obj-$(CONFIG_BT_HCIUART) += hci_uart.o
obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o
obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
......
/*
*
* Broadcom Blutonium firmware driver
*
* Copyright (C) 2003 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/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/usb.h>
#include <net/bluetooth/bluetooth.h>
#ifndef CONFIG_BT_HCIBCM203X_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
#endif
#define VERSION "1.0"
static struct usb_device_id bcm203x_table[] = {
/* Broadcom Blutonium (BCM2033) */
{ USB_DEVICE(0x0a5c, 0x2033) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, bcm203x_table);
#define BCM203X_ERROR 0
#define BCM203X_RESET 1
#define BCM203X_LOAD_MINIDRV 2
#define BCM203X_SELECT_MEMORY 3
#define BCM203X_CHECK_MEMORY 4
#define BCM203X_LOAD_FIRMWARE 5
#define BCM203X_CHECK_FIRMWARE 6
#define BCM203X_IN_EP 0x81
#define BCM203X_OUT_EP 0x02
struct bcm203x_data {
struct usb_device *udev;
unsigned long state;
struct timer_list timer;
struct urb *urb;
unsigned char buffer[4096];
unsigned char *fw_data;
unsigned int fw_size;
unsigned int fw_sent;
};
static void bcm203x_complete(struct urb *urb, struct pt_regs *regs)
{
struct bcm203x_data *data = urb->context;
struct usb_device *udev = urb->dev;
int len;
BT_DBG("udev %p urb %p", udev, urb);
if (urb->status) {
BT_ERR("URB failed with status %d", urb->status);
data->state = BCM203X_ERROR;
return;
}
switch (data->state) {
case BCM203X_LOAD_MINIDRV:
memcpy(data->buffer, "#", 1);
usb_fill_bulk_urb(urb, udev,
usb_sndbulkpipe(udev, BCM203X_OUT_EP),
data->buffer, 1, bcm203x_complete, data);
data->state = BCM203X_SELECT_MEMORY;
mod_timer(&data->timer, jiffies + (HZ / 10));
break;
case BCM203X_SELECT_MEMORY:
usb_fill_int_urb(urb, udev,
usb_rcvintpipe(udev, BCM203X_IN_EP),
data->buffer, 32, bcm203x_complete, data, 1);
data->state = BCM203X_CHECK_MEMORY;
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
BT_ERR("Can't submit URB");
break;
case BCM203X_CHECK_MEMORY:
if (data->buffer[0] != '#') {
BT_ERR("Memory select failed");
data->state = BCM203X_ERROR;
break;
}
data->state = BCM203X_LOAD_FIRMWARE;
case BCM203X_LOAD_FIRMWARE:
if (data->fw_sent == data->fw_size) {
usb_fill_int_urb(urb, udev,
usb_rcvintpipe(udev, BCM203X_IN_EP),
data->buffer, 32,
bcm203x_complete, data, 1);
data->state = BCM203X_CHECK_FIRMWARE;
} else {
len = min_t(uint, data->fw_size - data->fw_sent,
sizeof(data->buffer));
usb_fill_bulk_urb(urb, udev,
usb_sndbulkpipe(udev, BCM203X_OUT_EP),
data->fw_data + data->fw_sent, len,
bcm203x_complete, data);
data->fw_sent += len;
}
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
BT_ERR("Can't submit URB");
break;
case BCM203X_CHECK_FIRMWARE:
if (data->buffer[0] != '.') {
BT_ERR("Firmware loading failed");
data->state = BCM203X_ERROR;
break;
}
data->state = BCM203X_RESET;
break;
}
}
static void bcm203x_timer(unsigned long user_data)
{
struct bcm203x_data *data = (struct bcm203x_data *) user_data;
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
BT_ERR("Can't submit URB");
}
static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
const struct firmware *firmware;
struct usb_device *udev = interface_to_usbdev(intf);
struct bcm203x_data *data;
BT_DBG("intf %p id %p", intf, id);
if (intf->altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for data structure");
return -ENOMEM;
}
memset(data, 0, sizeof(*data));
data->udev = udev;
data->state = BCM203X_LOAD_MINIDRV;
data->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->urb) {
BT_ERR("Can't allocate URB");
kfree(data);
return -ENOMEM;
}
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
BT_ERR("Mini driver request failed");
usb_free_urb(data->urb);
kfree(data);
return -EIO;
}
BT_DBG("minidrv data %p size %d", firmware->data, firmware->size);
if (firmware->size > sizeof(data->buffer)) {
BT_ERR("Mini driver exceeds size of buffer");
release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data);
return -EIO;
}
memcpy(data->buffer, firmware->data, firmware->size);
usb_fill_bulk_urb(data->urb, udev,
usb_sndbulkpipe(udev, BCM203X_OUT_EP),
data->buffer, firmware->size, bcm203x_complete, data);
release_firmware(firmware);
if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
usb_free_urb(data->urb);
kfree(data);
return -EIO;
}
BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
if (!data->fw_data) {
BT_ERR("Can't allocate memory for firmware image");
usb_free_urb(data->urb);
kfree(data);
return -ENOMEM;
}
memcpy(data->fw_data, firmware->data, firmware->size);
data->fw_size = firmware->size;
data->fw_sent = 0;
release_firmware(firmware);
init_timer(&data->timer);
data->timer.function = bcm203x_timer;
data->timer.data = (unsigned long) data;
usb_set_intfdata(intf, data);
mod_timer(&data->timer, jiffies + HZ);
return 0;
}
static void bcm203x_disconnect(struct usb_interface *intf)
{
struct bcm203x_data *data = usb_get_intfdata(intf);
BT_DBG("intf %p", intf);
usb_unlink_urb(data->urb);
usb_set_intfdata(intf, NULL);
usb_free_urb(data->urb);
kfree(data->fw_data);
kfree(data);
}
static struct usb_driver bcm203x_driver = {
.owner = THIS_MODULE,
.name = "bcm203x",
.probe = bcm203x_probe,
.disconnect = bcm203x_disconnect,
.id_table = bcm203x_table,
};
static int __init bcm203x_init(void)
{
int err;
BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION);
err = usb_register(&bcm203x_driver);
if (err < 0)
BT_ERR("Failed to register USB driver");
return err;
}
static void __exit bcm203x_cleanup(void)
{
usb_deregister(&bcm203x_driver);
}
module_init(bcm203x_init);
module_exit(bcm203x_cleanup);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
MODULE_LICENSE("GPL");
This diff is collapsed.
...@@ -499,7 +499,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) ...@@ -499,7 +499,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
} }
void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{ {
bluecard_info_t *info = dev_inst; bluecard_info_t *info = dev_inst;
unsigned int iobase; unsigned int iobase;
...@@ -507,11 +507,11 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -507,11 +507,11 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
if (!info) { if (!info) {
printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
return; return IRQ_NONE;
} }
if (!test_bit(CARD_READY, &(info->hw_state))) if (!test_bit(CARD_READY, &(info->hw_state)))
return; return IRQ_NONE;
iobase = info->link.io.BasePort1; iobase = info->link.io.BasePort1;
...@@ -556,6 +556,8 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -556,6 +556,8 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
outb(info->ctrl_reg, iobase + REG_CONTROL); outb(info->ctrl_reg, iobase + REG_CONTROL);
spin_unlock(&(info->lock)); spin_unlock(&(info->lock));
return IRQ_HANDLED;
} }
......
...@@ -355,7 +355,7 @@ static void bt3c_receive(bt3c_info_t *info) ...@@ -355,7 +355,7 @@ static void bt3c_receive(bt3c_info_t *info)
} }
void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{ {
bt3c_info_t *info = dev_inst; bt3c_info_t *info = dev_inst;
unsigned int iobase; unsigned int iobase;
...@@ -363,7 +363,7 @@ void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -363,7 +363,7 @@ void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
if (!info) { if (!info) {
printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq); printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
return; return IRQ_NONE;
} }
iobase = info->link.io.BasePort1; iobase = info->link.io.BasePort1;
...@@ -396,6 +396,8 @@ void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -396,6 +396,8 @@ void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
} }
spin_unlock(&(info->lock)); spin_unlock(&(info->lock));
return IRQ_HANDLED;
} }
......
...@@ -301,7 +301,7 @@ static void btuart_receive(btuart_info_t *info) ...@@ -301,7 +301,7 @@ static void btuart_receive(btuart_info_t *info)
} }
void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{ {
btuart_info_t *info = dev_inst; btuart_info_t *info = dev_inst;
unsigned int iobase; unsigned int iobase;
...@@ -310,7 +310,7 @@ void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -310,7 +310,7 @@ void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
if (!info) { if (!info) {
printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq); printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
return; return IRQ_NONE;
} }
iobase = info->link.io.BasePort1; iobase = info->link.io.BasePort1;
...@@ -351,6 +351,8 @@ void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -351,6 +351,8 @@ void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
} }
spin_unlock(&(info->lock)); spin_unlock(&(info->lock));
return IRQ_HANDLED;
} }
......
...@@ -304,7 +304,7 @@ static void dtl1_receive(dtl1_info_t *info) ...@@ -304,7 +304,7 @@ static void dtl1_receive(dtl1_info_t *info)
} }
void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{ {
dtl1_info_t *info = dev_inst; dtl1_info_t *info = dev_inst;
unsigned int iobase; unsigned int iobase;
...@@ -314,7 +314,7 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -314,7 +314,7 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
if (!info) { if (!info) {
printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
return; return IRQ_NONE;
} }
iobase = info->link.io.BasePort1; iobase = info->link.io.BasePort1;
...@@ -363,6 +363,8 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -363,6 +363,8 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
} }
spin_unlock(&(info->lock)); spin_unlock(&(info->lock));
return IRQ_HANDLED;
} }
......
...@@ -62,7 +62,7 @@ ...@@ -62,7 +62,7 @@
#define BT_DMP( A... ) #define BT_DMP( A... )
#endif #endif
#ifndef CONFIG_BT_USB_ZERO_PACKET #ifndef CONFIG_BT_HCIUSB_ZERO_PACKET
#undef URB_ZERO_PACKET #undef URB_ZERO_PACKET
#define URB_ZERO_PACKET 0 #define URB_ZERO_PACKET 0
#endif #endif
...@@ -70,12 +70,21 @@ ...@@ -70,12 +70,21 @@
static struct usb_driver hci_usb_driver; static struct usb_driver hci_usb_driver;
static struct usb_device_id bluetooth_ids[] = { static struct usb_device_id bluetooth_ids[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033), driver_info: HCI_IGNORE },
/* Digianswer device */
{ USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER },
/* Generic Bluetooth USB device */ /* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
/* Ericsson with non-standard id */ /* Ericsson with non-standard id */
{ USB_DEVICE(0x0bdb, 0x1002) }, { USB_DEVICE(0x0bdb, 0x1002) },
/* ALPS Module with non-standard id */
{ USB_DEVICE(0x044e, 0x3002) },
/* Bluetooth Ultraport Module from IBM */ /* Bluetooth Ultraport Module from IBM */
{ USB_DEVICE(0x04bf, 0x030a) }, { USB_DEVICE(0x04bf, 0x030a) },
...@@ -84,13 +93,6 @@ static struct usb_device_id bluetooth_ids[] = { ...@@ -84,13 +93,6 @@ static struct usb_device_id bluetooth_ids[] = {
MODULE_DEVICE_TABLE (usb, bluetooth_ids); MODULE_DEVICE_TABLE (usb, bluetooth_ids);
static struct usb_device_id ignore_ids[] = {
/* Broadcom BCM2033 without firmware */
{ USB_DEVICE(0x0a5c, 0x2033) },
{ } /* Terminating entry */
};
struct _urb *_urb_alloc(int isoc, int gfp) struct _urb *_urb_alloc(int isoc, int gfp)
{ {
struct _urb *_urb = kmalloc(sizeof(struct _urb) + struct _urb *_urb = kmalloc(sizeof(struct _urb) +
...@@ -134,7 +136,7 @@ static inline struct _urb *__get_completed(struct hci_usb *husb, int type) ...@@ -134,7 +136,7 @@ static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
return _urb_dequeue(__completed_q(husb, type)); return _urb_dequeue(__completed_q(husb, type));
} }
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
static void __fill_isoc_desc(struct urb *urb, int len, int mtu) static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
{ {
int offset = 0, i; int offset = 0, i;
...@@ -232,7 +234,7 @@ static int hci_usb_bulk_rx_submit(struct hci_usb *husb) ...@@ -232,7 +234,7 @@ static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
return err; return err;
} }
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
static int hci_usb_isoc_rx_submit(struct hci_usb *husb) static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
{ {
struct _urb *_urb; struct _urb *_urb;
...@@ -301,8 +303,9 @@ static int hci_usb_open(struct hci_dev *hdev) ...@@ -301,8 +303,9 @@ static int hci_usb_open(struct hci_dev *hdev)
for (i = 0; i < HCI_MAX_BULK_RX; i++) for (i = 0; i < HCI_MAX_BULK_RX; i++)
hci_usb_bulk_rx_submit(husb); hci_usb_bulk_rx_submit(husb);
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
if (husb->isoc_iface) if (husb->isoc_iface)
for (i = 0; i < HCI_MAX_ISOC_RX; i++)
hci_usb_isoc_rx_submit(husb); hci_usb_isoc_rx_submit(husb);
#endif #endif
} else { } else {
...@@ -425,7 +428,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) ...@@ -425,7 +428,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
} else } else
dr = (void *) _urb->urb.setup_packet; dr = (void *) _urb->urb.setup_packet;
dr->bRequestType = HCI_CTRL_REQ; dr->bRequestType = husb->ctrl_req;
dr->bRequest = 0; dr->bRequest = 0;
dr->wIndex = 0; dr->wIndex = 0;
dr->wValue = 0; dr->wValue = 0;
...@@ -466,7 +469,7 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) ...@@ -466,7 +469,7 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
return __tx_submit(husb, _urb); return __tx_submit(husb, _urb);
} }
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
{ {
struct _urb *_urb = __get_completed(husb, skb->pkt_type); struct _urb *_urb = __get_completed(husb, skb->pkt_type);
...@@ -517,10 +520,10 @@ static void hci_usb_tx_process(struct hci_usb *husb) ...@@ -517,10 +520,10 @@ static void hci_usb_tx_process(struct hci_usb *husb)
skb_queue_head(q, skb); skb_queue_head(q, skb);
} }
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
/* Process SCO queue */ /* Process SCO queue */
q = __transmit_q(husb, HCI_SCODATA_PKT); q = __transmit_q(husb, HCI_SCODATA_PKT);
if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) && if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
(skb = skb_dequeue(q))) { (skb = skb_dequeue(q))) {
if (hci_usb_send_isoc(husb, skb) < 0) if (hci_usb_send_isoc(husb, skb) < 0)
skb_queue_head(q, skb); skb_queue_head(q, skb);
...@@ -576,7 +579,7 @@ static int hci_usb_send_frame(struct sk_buff *skb) ...@@ -576,7 +579,7 @@ static int hci_usb_send_frame(struct sk_buff *skb)
hdev->stat.acl_tx++; hdev->stat.acl_tx++;
break; break;
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
case HCI_SCODATA_PKT: case HCI_SCODATA_PKT:
hdev->stat.sco_tx++; hdev->stat.sco_tx++;
break; break;
...@@ -626,7 +629,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c ...@@ -626,7 +629,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
} else } else
return -EILSEQ; return -EILSEQ;
break; break;
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
case HCI_SCODATA_PKT: case HCI_SCODATA_PKT:
if (count >= HCI_SCO_HDR_SIZE) { if (count >= HCI_SCO_HDR_SIZE) {
struct hci_sco_hdr *h = data; struct hci_sco_hdr *h = data;
...@@ -691,7 +694,7 @@ static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs) ...@@ -691,7 +694,7 @@ static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
goto resubmit; goto resubmit;
if (_urb->type == HCI_SCODATA_PKT) { if (_urb->type == HCI_SCODATA_PKT) {
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
int i; int i;
for (i=0; i < urb->number_of_packets; i++) { for (i=0; i < urb->number_of_packets; i++) {
BT_DBG("desc %d status %d offset %d len %d", i, BT_DBG("desc %d status %d offset %d len %d", i,
...@@ -785,9 +788,11 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -785,9 +788,11 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
iface = udev->actconfig->interface[0]; iface = udev->actconfig->interface[0];
/* Check our black list */ if (id->driver_info & HCI_IGNORE)
if (usb_match_id(intf, ignore_ids)) return -ENODEV;
return -EIO;
if (intf->altsetting->desc.bInterfaceNumber > 0)
return -ENODEV;
/* Check number of endpoints */ /* Check number of endpoints */
if (intf->altsetting[0].desc.bNumEndpoints < 3) if (intf->altsetting[0].desc.bNumEndpoints < 3)
...@@ -826,9 +831,9 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -826,9 +831,9 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
bulk_out_ep[i] = ep; bulk_out_ep[i] = ep;
break; break;
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
if (ep->desc.wMaxPacketSize < size) if (ep->desc.wMaxPacketSize < size || a > 2)
break; break;
size = ep->desc.wMaxPacketSize; size = ep->desc.wMaxPacketSize;
...@@ -852,7 +857,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -852,7 +857,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto done; goto done;
} }
#ifdef CONFIG_BT_USB_SCO #ifdef CONFIG_BT_HCIUSB_SCO
if (!isoc_in_ep[1] || !isoc_out_ep[1]) { if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
BT_DBG("Isoc endpoints not found"); BT_DBG("Isoc endpoints not found");
isoc_iface = NULL; isoc_iface = NULL;
...@@ -871,7 +876,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -871,7 +876,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
husb->bulk_in_ep = bulk_in_ep[0]; husb->bulk_in_ep = bulk_in_ep[0];
husb->intr_in_ep = intr_in_ep[0]; husb->intr_in_ep = intr_in_ep[0];
#ifdef CONFIG_BT_USB_SCO if (id->driver_info & HCI_DIGIANSWER)
husb->ctrl_req = HCI_DIGI_REQ;
else
husb->ctrl_req = HCI_CTRL_REQ;
#ifdef CONFIG_BT_HCIUSB_SCO
if (isoc_iface) { if (isoc_iface) {
BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
......
...@@ -35,12 +35,19 @@ ...@@ -35,12 +35,19 @@
#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ #define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */
#define HCI_CTRL_REQ 0x20 #define HCI_CTRL_REQ 0x20
#define HCI_DIGI_REQ 0x40
#define HCI_IGNORE 0x01
#define HCI_DIGIANSWER 0x02
#define HCI_MAX_IFACE_NUM 3 #define HCI_MAX_IFACE_NUM 3
#define HCI_MAX_BULK_TX 4 #define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_RX 1 #define HCI_MAX_BULK_RX 1
#define HCI_MAX_ISOC_RX 2
#define HCI_MAX_ISOC_TX 2
#define HCI_MAX_ISOC_FRAMES 10 #define HCI_MAX_ISOC_FRAMES 10
struct _urb_queue { struct _urb_queue {
...@@ -119,6 +126,8 @@ struct hci_usb { ...@@ -119,6 +126,8 @@ struct hci_usb {
struct usb_host_endpoint *isoc_out_ep; struct usb_host_endpoint *isoc_out_ep;
struct usb_host_endpoint *isoc_in_ep; struct usb_host_endpoint *isoc_in_ep;
__u8 ctrl_req;
struct sk_buff_head transmit_q[4]; struct sk_buff_head transmit_q[4];
struct sk_buff *reassembly[4]; // Reassembly buffers struct sk_buff *reassembly[4]; // Reassembly buffers
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define BTPROTO_SCO 2 #define BTPROTO_SCO 2
#define BTPROTO_RFCOMM 3 #define BTPROTO_RFCOMM 3
#define BTPROTO_BNEP 4 #define BTPROTO_BNEP 4
#define BTPROTO_CMTP 5
#define SOL_HCI 0 #define SOL_HCI 0
#define SOL_L2CAP 6 #define SOL_L2CAP 6
......
...@@ -408,6 +408,16 @@ struct inquiry_info { ...@@ -408,6 +408,16 @@ struct inquiry_info {
__u16 clock_offset; __u16 clock_offset;
} __attribute__ ((packed)); } __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];
__u16 clock_offset;
__u8 rssi;
} __attribute__ ((packed));
#define HCI_EV_CONN_COMPLETE 0x03 #define HCI_EV_CONN_COMPLETE 0x03
struct hci_ev_conn_complete { struct hci_ev_conn_complete {
__u8 status; __u8 status;
......
...@@ -176,6 +176,12 @@ static inline void inquiry_cache_init(struct hci_dev *hdev) ...@@ -176,6 +176,12 @@ static inline void inquiry_cache_init(struct hci_dev *hdev)
c->list = NULL; c->list = NULL;
} }
static inline int inquiry_cache_empty(struct hci_dev *hdev)
{
struct inquiry_cache *c = &hdev->inq_cache;
return (c->list == NULL);
}
static inline long inquiry_cache_age(struct hci_dev *hdev) static inline long inquiry_cache_age(struct hci_dev *hdev)
{ {
struct inquiry_cache *c = &hdev->inq_cache; struct inquiry_cache *c = &hdev->inq_cache;
...@@ -281,10 +287,12 @@ static inline void hci_conn_hold(struct hci_conn *conn) ...@@ -281,10 +287,12 @@ static inline void hci_conn_hold(struct hci_conn *conn)
static inline void hci_conn_put(struct hci_conn *conn) static inline void hci_conn_put(struct hci_conn *conn)
{ {
if (atomic_dec_and_test(&conn->refcnt)) { if (atomic_dec_and_test(&conn->refcnt)) {
if (conn->type == SCO_LINK) if (conn->type == ACL_LINK) {
unsigned long timeo = (conn->out) ?
HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2;
hci_conn_set_timer(conn, timeo);
} else
hci_conn_set_timer(conn, HZ / 100); hci_conn_set_timer(conn, HZ / 100);
else if (conn->out)
hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
} }
} }
......
...@@ -167,8 +167,8 @@ struct rfcomm_session { ...@@ -167,8 +167,8 @@ struct rfcomm_session {
int initiator; int initiator;
/* Default DLC parameters */ /* Default DLC parameters */
int cfc;
uint mtu; uint mtu;
uint credits;
struct list_head dlcs; struct list_head dlcs;
}; };
...@@ -190,7 +190,7 @@ struct rfcomm_dlc { ...@@ -190,7 +190,7 @@ struct rfcomm_dlc {
u8 mscex; u8 mscex;
uint mtu; uint mtu;
uint credits; uint cfc;
uint rx_credits; uint rx_credits;
uint tx_credits; uint tx_credits;
...@@ -219,6 +219,11 @@ struct rfcomm_dlc { ...@@ -219,6 +219,11 @@ struct rfcomm_dlc {
#define RFCOMM_MSCEX_RX 2 #define RFCOMM_MSCEX_RX 2
#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) #define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
/* CFC states */
#define RFCOMM_CFC_UNKNOWN -1
#define RFCOMM_CFC_DISABLED 0
#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS
extern struct task_struct *rfcomm_thread; extern struct task_struct *rfcomm_thread;
extern unsigned long rfcomm_event; extern unsigned long rfcomm_event;
......
...@@ -21,6 +21,7 @@ config BT ...@@ -21,6 +21,7 @@ config BT
SCO Module (SCO links) SCO Module (SCO links)
RFCOMM Module (RFCOMM protocol) RFCOMM Module (RFCOMM protocol)
BNEP Module (BNEP protocol) BNEP Module (BNEP protocol)
CMTP Module (CMTP protocol)
Say Y here to enable Linux Bluetooth support and to build Bluetooth Core Say Y here to enable Linux Bluetooth support and to build Bluetooth Core
layer. layer.
...@@ -57,6 +58,8 @@ source "net/bluetooth/rfcomm/Kconfig" ...@@ -57,6 +58,8 @@ source "net/bluetooth/rfcomm/Kconfig"
source "net/bluetooth/bnep/Kconfig" source "net/bluetooth/bnep/Kconfig"
source "net/bluetooth/cmtp/Kconfig"
source "drivers/bluetooth/Kconfig" source "drivers/bluetooth/Kconfig"
endmenu endmenu
......
...@@ -7,5 +7,6 @@ obj-$(CONFIG_BT_L2CAP) += l2cap.o ...@@ -7,5 +7,6 @@ obj-$(CONFIG_BT_L2CAP) += l2cap.o
obj-$(CONFIG_BT_SCO) += sco.o obj-$(CONFIG_BT_SCO) += sco.o
obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP) += cmtp/
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_proc.o lib.o syms.o
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
struct proc_dir_entry *proc_bt; struct proc_dir_entry *proc_bt;
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 5 #define BT_MAX_PROTO 6
static struct net_proto_family *bt_proto[BT_MAX_PROTO]; static struct net_proto_family *bt_proto[BT_MAX_PROTO];
static kmem_cache_t *bt_sock_cache; static kmem_cache_t *bt_sock_cache;
......
...@@ -707,3 +707,4 @@ module_exit(bnep_cleanup_module); ...@@ -707,3 +707,4 @@ module_exit(bnep_cleanup_module);
MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION); MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>"); MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-4");
config BT_CMTP
tristate "CMTP protocol support"
depends on BT && BT_L2CAP && ISDN_CAPI
help
CMTP (CAPI Message Transport Protocol) is a transport layer
for CAPI messages. CMTP is required for the Bluetooth Common
ISDN Access Profile.
Say Y here to compile CMTP support into the kernel or say M to
compile it as module (cmtp).
#
# Makefile for the Linux Bluetooth CMTP layer
#
obj-$(CONFIG_BT_CMTP) += cmtp.o
cmtp-objs := core.o sock.o capi.o
This diff is collapsed.
/*
CMTP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2002-2003 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 version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#ifndef __CMTP_H
#define __CMTP_H
#include <linux/types.h>
#include <net/bluetooth/bluetooth.h>
#define BTNAMSIZ 18
/* CMTP ioctl defines */
#define CMTPCONNADD _IOW('C', 200, int)
#define CMTPCONNDEL _IOW('C', 201, int)
#define CMTPGETCONNLIST _IOR('C', 210, int)
#define CMTPGETCONNINFO _IOR('C', 211, int)
#define CMTP_LOOPBACK 0
struct cmtp_connadd_req {
int sock; // Connected socket
__u32 flags;
};
struct cmtp_conndel_req {
bdaddr_t bdaddr;
__u32 flags;
};
struct cmtp_conninfo {
bdaddr_t bdaddr;
__u32 flags;
__u16 state;
int num;
};
struct cmtp_connlist_req {
__u32 cnum;
struct cmtp_conninfo *ci;
};
int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
int cmtp_del_connection(struct cmtp_conndel_req *req);
int cmtp_get_connlist(struct cmtp_connlist_req *req);
int cmtp_get_conninfo(struct cmtp_conninfo *ci);
/* CMTP session defines */
#define CMTP_INTEROP_TIMEOUT (HZ * 5)
#define CMTP_INITIAL_MSGNUM 0xff00
struct cmtp_session {
struct list_head list;
struct socket *sock;
bdaddr_t bdaddr;
unsigned long state;
unsigned long flags;
uint mtu;
char name[BTNAMSIZ];
atomic_t terminate;
wait_queue_head_t wait;
int ncontroller;
int num;
struct capi_ctr ctrl;
struct list_head applications;
unsigned long blockids;
int msgnum;
struct sk_buff_head transmit;
struct sk_buff *reassembly[16];
};
struct cmtp_application {
struct list_head list;
unsigned long state;
int err;
__u16 appl;
__u16 mapping;
__u16 msgnum;
};
struct cmtp_scb {
int id;
int data;
};
int cmtp_attach_device(struct cmtp_session *session);
void cmtp_detach_device(struct cmtp_session *session);
void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
static inline void cmtp_schedule(struct cmtp_session *session)
{
struct sock *sk = session->sock->sk;
wake_up_interruptible(sk->sk_sleep);
}
/* CMTP init defines */
int cmtp_init_sockets(void);
void cmtp_cleanup_sockets(void);
#endif /* __CMTP_H */
This diff is collapsed.
/*
CMTP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2002-2003 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 version 2 as
published by the Free Software Foundation;
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "cmtp.h"
#ifndef CONFIG_BT_CMTP_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
#endif
static int cmtp_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
BT_DBG("sock %p sk %p", sock, sk);
if (!sk)
return 0;
sock_orphan(sk);
sock_put(sk);
return 0;
}
static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct cmtp_connadd_req ca;
struct cmtp_conndel_req cd;
struct cmtp_connlist_req cl;
struct cmtp_conninfo ci;
struct socket *nsock;
int err;
BT_DBG("cmd %x arg %lx", cmd, arg);
switch (cmd) {
case CMTPCONNADD:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
return -EFAULT;
nsock = sockfd_lookup(ca.sock, &err);
if (!nsock)
return err;
if (nsock->sk->sk_state != BT_CONNECTED)
return -EBADFD;
err = cmtp_add_connection(&ca, nsock);
if (!err) {
if (copy_to_user((void *) arg, &ca, sizeof(ca)))
err = -EFAULT;
} else
fput(nsock->file);
return err;
case CMTPCONNDEL:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
return -EFAULT;
return cmtp_del_connection(&cd);
case CMTPGETCONNLIST:
if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
return -EFAULT;
if (cl.cnum <= 0)
return -EINVAL;
err = cmtp_get_connlist(&cl);
if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
return -EFAULT;
return err;
case CMTPGETCONNINFO:
if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
return -EFAULT;
err = cmtp_get_conninfo(&ci);
if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
return -EFAULT;
return err;
}
return -EINVAL;
}
static struct proto_ops cmtp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = cmtp_sock_release,
.ioctl = cmtp_sock_ioctl,
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
.recvmsg = sock_no_recvmsg,
.poll = sock_no_poll,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.mmap = sock_no_mmap
};
static int cmtp_sock_create(struct socket *sock, int protocol)
{
struct sock *sk;
BT_DBG("sock %p", sock);
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
return -ENOMEM;
sk_set_owner(sk, THIS_MODULE);
sock->ops = &cmtp_sock_ops;
sock->state = SS_UNCONNECTED;
sk->sk_destruct = NULL;
sk->sk_protocol = protocol;
return 0;
}
static struct net_proto_family cmtp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = cmtp_sock_create
};
int cmtp_init_sockets(void)
{
bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
return 0;
}
void cmtp_cleanup_sockets(void)
{
if (bt_sock_unregister(BTPROTO_CMTP))
BT_ERR("Can't unregister CMTP socket");
}
...@@ -71,7 +71,7 @@ void hci_acl_connect(struct hci_conn *conn) ...@@ -71,7 +71,7 @@ void hci_acl_connect(struct hci_conn *conn)
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x01; cp.pscan_rep_mode = 0x02;
if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
......
...@@ -406,6 +406,7 @@ int hci_inquiry(unsigned long arg) ...@@ -406,6 +406,7 @@ int hci_inquiry(unsigned long arg)
hci_dev_lock_bh(hdev); hci_dev_lock_bh(hdev);
if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
inquiry_cache_empty(hdev) ||
ir.flags & IREQ_CACHE_FLUSH) { ir.flags & IREQ_CACHE_FLUSH) {
inquiry_cache_flush(hdev); inquiry_cache_flush(hdev);
do_inquiry = 1; do_inquiry = 1;
......
...@@ -452,6 +452,29 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -452,6 +452,29 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev); 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)
{
struct inquiry_info_with_rssi *info = (struct inquiry_info_with_rssi *) (skb->data + 1);
int num_rsp = *((__u8 *) skb->data);
BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) {
struct inquiry_info tmp;
bacpy(&tmp.bdaddr, &info->bdaddr);
tmp.pscan_rep_mode = info->pscan_rep_mode;
tmp.pscan_period_mode = info->pscan_period_mode;
tmp.pscan_mode = 0x00;
memcpy(tmp.dev_class, &info->dev_class, 3);
tmp.clock_offset = info->clock_offset;
info++;
inquiry_cache_update(hdev, &tmp);
}
hci_dev_unlock(hdev);
}
/* Connect Request */ /* Connect Request */
static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
...@@ -744,6 +767,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -744,6 +767,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_inquiry_result_evt(hdev, skb); hci_inquiry_result_evt(hdev, skb);
break; break;
case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
hci_inquiry_result_with_rssi_evt(hdev, skb);
break;
case HCI_EV_CONN_REQUEST: case HCI_EV_CONN_REQUEST:
hci_conn_request_evt(hdev, skb); hci_conn_request_evt(hdev, skb);
break; break;
......
...@@ -66,20 +66,20 @@ static struct hci_sec_filter hci_sec_filter = { ...@@ -66,20 +66,20 @@ static struct hci_sec_filter hci_sec_filter = {
/* Packet types */ /* Packet types */
0x10, 0x10,
/* Events */ /* Events */
{ 0xd9fe, 0x0 }, { 0x1000d9fe, 0x0000300c },
/* Commands */ /* Commands */
{ {
{ 0x0 }, { 0x0 },
/* OGF_LINK_CTL */ /* OGF_LINK_CTL */
{ 0x2a000002, 0x0, 0x0, 0x0 }, { 0xbe000006, 0x00000001, 0x0000, 0x00 },
/* OGF_LINK_POLICY */ /* OGF_LINK_POLICY */
{ 0x1200, 0x0, 0x0, 0x0 }, { 0x00005200, 0x00000000, 0x0000, 0x00 },
/* OGF_HOST_CTL */ /* OGF_HOST_CTL */
{ 0x80100000, 0x202a, 0x0, 0x0 }, { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
/* OGF_INFO_PARAM */ /* OGF_INFO_PARAM */
{ 0x22a, 0x0, 0x0, 0x0 }, { 0x000002be, 0x00000000, 0x0000, 0x00 },
/* OGF_STATUS_PARAM */ /* OGF_STATUS_PARAM */
{ 0x2e, 0x0, 0x0, 0x0 } { 0x000000ea, 0x00000000, 0x0000, 0x00 }
} }
}; };
......
...@@ -2202,3 +2202,4 @@ module_exit(l2cap_cleanup); ...@@ -2202,3 +2202,4 @@ module_exit(l2cap_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION); MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-0");
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#include <net/bluetooth/l2cap.h> #include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h> #include <net/bluetooth/rfcomm.h>
#define VERSION "1.0" #define VERSION "1.1"
#ifndef CONFIG_BT_RFCOMM_DEBUG #ifndef CONFIG_BT_RFCOMM_DEBUG
#undef BT_DBG #undef BT_DBG
...@@ -207,7 +207,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) ...@@ -207,7 +207,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
d->mtu = RFCOMM_DEFAULT_MTU; d->mtu = RFCOMM_DEFAULT_MTU;
d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
d->credits = RFCOMM_MAX_CREDITS; d->cfc = RFCOMM_CFC_DISABLED;
d->rx_credits = RFCOMM_DEFAULT_CREDITS; d->rx_credits = RFCOMM_DEFAULT_CREDITS;
} }
...@@ -315,7 +315,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, ...@@ -315,7 +315,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
rfcomm_dlc_link(s, d); rfcomm_dlc_link(s, d);
d->mtu = s->mtu; d->mtu = s->mtu;
d->credits = s->credits; d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
if (s->state == BT_CONNECTED) if (s->state == BT_CONNECTED)
rfcomm_send_pn(s, 1, d); rfcomm_send_pn(s, 1, d);
...@@ -415,7 +415,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) ...@@ -415,7 +415,7 @@ void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p state %ld", d, d->state); BT_DBG("dlc %p state %ld", d, d->state);
if (!d->credits) { if (!d->cfc) {
d->v24_sig |= RFCOMM_V24_FC; d->v24_sig |= RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags); set_bit(RFCOMM_MSC_PENDING, &d->flags);
} }
...@@ -426,7 +426,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ...@@ -426,7 +426,7 @@ void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p state %ld", d, d->state); BT_DBG("dlc %p state %ld", d, d->state);
if (!d->credits) { if (!d->cfc) {
d->v24_sig &= ~RFCOMM_V24_FC; d->v24_sig &= ~RFCOMM_V24_FC;
set_bit(RFCOMM_MSC_PENDING, &d->flags); set_bit(RFCOMM_MSC_PENDING, &d->flags);
} }
...@@ -480,7 +480,7 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ...@@ -480,7 +480,7 @@ struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
s->sock = sock; s->sock = sock;
s->mtu = RFCOMM_DEFAULT_MTU; s->mtu = RFCOMM_DEFAULT_MTU;
s->credits = RFCOMM_MAX_CREDITS; s->cfc = RFCOMM_CFC_UNKNOWN;
list_add(&s->list, &session_list); list_add(&s->list, &session_list);
...@@ -752,7 +752,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d ...@@ -752,7 +752,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
pn->ack_timer = 0; pn->ack_timer = 0;
pn->max_retrans = 0; pn->max_retrans = 0;
if (d->credits) { if (s->cfc) {
pn->flow_ctrl = cr ? 0xf0 : 0xe0; pn->flow_ctrl = cr ? 0xf0 : 0xe0;
pn->credits = RFCOMM_DEFAULT_CREDITS; pn->credits = RFCOMM_DEFAULT_CREDITS;
} else { } else {
...@@ -1142,28 +1142,22 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ...@@ -1142,28 +1142,22 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
{ {
struct rfcomm_session *s = d->session;
BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d",
d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits); d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
if (cr) { if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
if (pn->flow_ctrl == 0xf0) { d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
d->tx_credits = pn->credits;
} else {
set_bit(RFCOMM_TX_THROTTLED, &d->flags);
d->credits = 0;
}
} else {
if (pn->flow_ctrl == 0xe0) {
d->tx_credits = pn->credits; d->tx_credits = pn->credits;
} else { } else {
d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
set_bit(RFCOMM_TX_THROTTLED, &d->flags); set_bit(RFCOMM_TX_THROTTLED, &d->flags);
d->credits = 0;
}
} }
d->priority = pn->priority; d->priority = pn->priority;
d->mtu = btohs(pn->mtu); d->mtu = s->mtu = btohs(pn->mtu);
return 0; return 0;
} }
...@@ -1353,7 +1347,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb ...@@ -1353,7 +1347,7 @@ static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb
return 0; return 0;
if (cr) { if (cr) {
if (msc->v24_sig & RFCOMM_V24_FC && !d->credits) if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
set_bit(RFCOMM_TX_THROTTLED, &d->flags); set_bit(RFCOMM_TX_THROTTLED, &d->flags);
else else
clear_bit(RFCOMM_TX_THROTTLED, &d->flags); clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
...@@ -1444,7 +1438,7 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk ...@@ -1444,7 +1438,7 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk
goto drop; goto drop;
} }
if (pf && d->credits) { if (pf && d->cfc) {
u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
d->tx_credits += credits; d->tx_credits += credits;
...@@ -1549,20 +1543,20 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1549,20 +1543,20 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d",
d, d->state, d->credits, d->rx_credits, d->tx_credits); d, d->state, d->cfc, d->rx_credits, d->tx_credits);
/* Send pending MSC */ /* Send pending MSC */
if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
if (d->credits) { if (d->cfc) {
/* CFC enabled. /* CFC enabled.
* Give them some credits */ * Give them some credits */
if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
d->rx_credits <= (d->credits >> 2)) { d->rx_credits <= (d->cfc >> 2)) {
rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits); rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
d->rx_credits = d->credits; d->rx_credits = d->cfc;
} }
} else { } else {
/* CFC disabled. /* CFC disabled.
...@@ -1583,7 +1577,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ...@@ -1583,7 +1577,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
d->tx_credits--; d->tx_credits--;
} }
if (d->credits && !d->tx_credits) { if (d->cfc && !d->tx_credits) {
/* We're out of TX credits. /* We're out of TX credits.
* Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
set_bit(RFCOMM_TX_THROTTLED, &d->flags); set_bit(RFCOMM_TX_THROTTLED, &d->flags);
...@@ -1656,6 +1650,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1656,6 +1650,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
nsock->type = sock->type; nsock->type = sock->type;
nsock->ops = sock->ops; nsock->ops = sock->ops;
__module_get(nsock->ops->owner);
err = sock->ops->accept(sock, nsock, O_NONBLOCK); err = sock->ops->accept(sock, nsock, O_NONBLOCK);
if (err < 0) { if (err < 0) {
sock_release(nsock); sock_release(nsock);
...@@ -1998,3 +1994,4 @@ module_exit(rfcomm_cleanup); ...@@ -1998,3 +1994,4 @@ module_exit(rfcomm_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION); MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-3");
...@@ -1055,3 +1055,4 @@ module_exit(sco_cleanup); ...@@ -1055,3 +1055,4 @@ module_exit(sco_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("bt-proto-2");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment