Commit e9df2323 authored by Maksim Krasnyanskiy's avatar Maksim Krasnyanskiy

[PATCH] Bluetooth subsystem sync up

This updates 2.5.x Bluetooth subsystem and removes the EXPERIMENTAL
status of Bluetooth support.

         BlueZ Core:
                 New generic HCI connection manager.
                 Complete role switch and link policy support.
                 Security mode 1 and 3 support.
                 L2CAP service level security support.
                 HCI filter support.
                 HCI frame time-stamps.
                 SCO (voice links) support.
                 Improved HCI device unregistration (device destructors).
                 Support for L2CAP signalling frame fragmentation.
                 Improved L2CAP timeout handling.
                 New HCI ioctls for changing ACL and SCO MTU.
                 Killed HCI_MAX_DEV limit.
                 Security fixes.

         HCI USB driver:
                 Performance improvements.
                 Firmware loading support.
                 Stability fixes. URB and disconnect handling rewrite.

         HCI UART driver:
                 Support for multiple UART protocols.

         HCI PCMCIA driver:
                 Support for Nokia Bluetooth PC Cards.
                 Support for Anycom Bluetooth PC/CF Cards.
parent 0501bce1
...@@ -372,9 +372,7 @@ endmenu ...@@ -372,9 +372,7 @@ endmenu
source drivers/usb/Config.in source drivers/usb/Config.in
source drivers/input/Config.in source drivers/input/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Kernel hacking' comment 'Kernel hacking'
......
...@@ -655,9 +655,7 @@ source drivers/misc/Config.in ...@@ -655,9 +655,7 @@ source drivers/misc/Config.in
source drivers/usb/Config.in source drivers/usb/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Kernel hacking' comment 'Kernel hacking'
......
...@@ -392,9 +392,7 @@ endmenu ...@@ -392,9 +392,7 @@ endmenu
source drivers/usb/Config.in source drivers/usb/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Kernel hacking' comment 'Kernel hacking'
......
...@@ -226,9 +226,7 @@ source drivers/usb/Config.in ...@@ -226,9 +226,7 @@ source drivers/usb/Config.in
source lib/Config.in source lib/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
fi # !HP_SIM fi # !HP_SIM
......
...@@ -589,9 +589,7 @@ fi ...@@ -589,9 +589,7 @@ fi
source drivers/usb/Config.in source drivers/usb/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
source lib/Config.in source lib/Config.in
......
...@@ -267,9 +267,7 @@ endmenu ...@@ -267,9 +267,7 @@ endmenu
source drivers/usb/Config.in source drivers/usb/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Watchdog' comment 'Watchdog'
......
...@@ -199,9 +199,7 @@ endmenu ...@@ -199,9 +199,7 @@ endmenu
source drivers/usb/Config.in source drivers/usb/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in
source net/bluetooth/Config.in
fi
mainmenu_option next_comment mainmenu_option next_comment
comment 'Kernel hacking' comment 'Kernel hacking'
......
HCI UART driver
CONFIG_BLUEZ_HCIUART CONFIG_BLUEZ_HCIUART
Bluetooth HCI UART driver. Bluetooth HCI UART driver.
This driver is required if you want to use Bluetooth devices with This driver is required if you want to use Bluetooth devices with
serial port interface. serial port interface. You will also need this driver if you have
UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
adapter and BrainBoxes Bluetooth PC Card.
Say Y here to compile support for Bluetooth UART devices into the Say Y here to compile support for Bluetooth UART devices into the
kernel or say M to compile it as module (hci_uart.o). kernel or say M to compile it as module (hci_uart.o).
HCI UART (H4) protocol support
CONFIG_BLUEZ_HCIUART_H4
UART (H4) is serial protocol for communication between Bluetooth
device and host. This protocol is required for most UART based
Bluetooth device (including PCMCIA and CF).
Say Y here to compile support for HCI UART (H4) protocol.
HCI USB driver
CONFIG_BLUEZ_HCIUSB CONFIG_BLUEZ_HCIUSB
Bluetooth HCI USB driver. Bluetooth HCI USB driver.
This driver is required if you want to use Bluetooth devices with This driver is required if you want to use Bluetooth devices with
...@@ -14,6 +26,24 @@ CONFIG_BLUEZ_HCIUSB ...@@ -14,6 +26,24 @@ CONFIG_BLUEZ_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.o). kernel or say M to compile it as module (hci_usb.o).
HCI USB firmware download support
CONFIG_BLUEZ_USB_FW_LOAD
Firmware download support for Bluetooth USB devices.
This support is required for devices like Broadcom BCM2033.
HCI USB driver uses external firmware downloader program provided
in BlueFW package.
For more information, see <http://bluez.sf.net/>.
HCI USB zero packet support
CONFIG_BLUEZ_USB_ZERO_PACKET
Support for USB zero packets.
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.
HCI VHCI Virtual HCI device driver
CONFIG_BLUEZ_HCIVHCI CONFIG_BLUEZ_HCIVHCI
Bluetooth Virtual HCI device driver. Bluetooth Virtual HCI device driver.
This driver is required if you want to use HCI Emulation software. This driver is required if you want to use HCI Emulation software.
...@@ -21,3 +51,24 @@ CONFIG_BLUEZ_HCIVHCI ...@@ -21,3 +51,24 @@ CONFIG_BLUEZ_HCIVHCI
Say Y here to compile support for virtual HCI devices into the Say Y here to compile support for virtual HCI devices into the
kernel or say M to compile it as module (hci_vhci.o). kernel or say M to compile it as module (hci_vhci.o).
HCI DTL1 (PC Card) device driver
CONFIG_BLUEZ_HCIDTL1
Bluetooth HCI DTL1 (PC Card) driver.
This driver provides support for Bluetooth PCMCIA devices with
Nokia DTL1 interface:
Nokia Bluetooth Card
Socket Bluetooth CF Card
Say Y here to compile support for HCI DTL1 devices into the
kernel or say M to compile it as module (dtl1_cs.o).
HCI BlueCard (PC Card) device driver
CONFIG_BLUEZ_HCIBLUECARD
Bluetooth HCI BlueCard (PC Card) driver.
This driver provides support for Bluetooth PCMCIA devices with
Anycom BlueCard interface:
Anycom Bluetooth PC Card
Anycom Bluetooth CF Card
Say Y here to compile support for HCI BlueCard devices into the
kernel or say M to compile it as module (bluecard_cs.o).
...@@ -2,7 +2,20 @@ mainmenu_option next_comment ...@@ -2,7 +2,20 @@ mainmenu_option next_comment
comment 'Bluetooth device drivers' comment 'Bluetooth device drivers'
dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
bool ' Firmware download support' CONFIG_BLUEZ_USB_FW_LOAD
bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET
fi
dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
fi
dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
endmenu endmenu
...@@ -4,8 +4,19 @@ ...@@ -4,8 +4,19 @@
O_TARGET := bluetooth.o O_TARGET := bluetooth.o
list-multi := hci_uart.o
obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o
obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o
obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
uart-y := hci_ldisc.o
uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
hci_uart.o: $(uart-y)
$(LD) -r -o $@ $(uart-y)
This diff is collapsed.
This diff is collapsed.
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
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.
*/
/*
* BlueZ HCI UART(H4) protocol.
*
* $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $
*/
#define VERSION "1.1"
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/config.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"
#include "hci_h4.h"
#ifndef HCI_UART_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
#define BT_DMP( A... )
#endif
/* Initialize protocol */
static int h4_open(struct n_hci *n_hci)
{
struct h4_struct *h4;
BT_DBG("n_hci %p", n_hci);
h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
if (!h4)
return -ENOMEM;
memset(h4, 0, sizeof(*h4));
n_hci->priv = h4;
return 0;
}
/* Flush protocol data */
static int h4_flush(struct n_hci *n_hci)
{
BT_DBG("n_hci %p", n_hci);
return 0;
}
/* Close protocol */
static int h4_close(struct n_hci *n_hci)
{
struct h4_struct *h4 = n_hci->priv;
n_hci->priv = NULL;
BT_DBG("n_hci %p", n_hci);
if (h4->rx_skb)
kfree_skb(h4->rx_skb);
kfree(h4);
return 0;
}
/* Send data */
static int h4_send(struct n_hci *n_hci, void *data, int len)
{
struct tty_struct *tty = n_hci->tty;
BT_DBG("n_hci %p len %d", n_hci, len);
/* Send frame to TTY driver */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
return tty->driver.write(tty, 0, data, len);
}
/* Init frame before queueing (padding, crc, etc) */
static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb)
{
BT_DBG("n_hci %p skb %p", n_hci, skb);
/* Prepend skb with frame type */
memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
return skb;
}
static inline int h4_check_data_len(struct h4_struct *h4, int len)
{
register int room = skb_tailroom(h4->rx_skb);
BT_DBG("len %d room %d", len, room);
if (!len) {
BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
hci_recv_frame(h4->rx_skb);
} else if (len > room) {
BT_ERR("Data length is to large");
kfree_skb(h4->rx_skb);
} else {
h4->rx_state = H4_W4_DATA;
h4->rx_count = len;
return len;
}
h4->rx_state = H4_W4_PACKET_TYPE;
h4->rx_skb = NULL;
h4->rx_count = 0;
return 0;
}
/* Recv data */
static int h4_recv(struct n_hci *n_hci, void *data, int count)
{
struct h4_struct *h4 = n_hci->priv;
register char *ptr;
hci_event_hdr *eh;
hci_acl_hdr *ah;
hci_sco_hdr *sh;
register int len, type, dlen;
BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count);
ptr = data;
while (count) {
if (h4->rx_count) {
len = MIN(h4->rx_count, count);
memcpy(skb_put(h4->rx_skb, len), ptr, len);
h4->rx_count -= len; count -= len; ptr += len;
if (h4->rx_count)
continue;
switch (h4->rx_state) {
case H4_W4_DATA:
BT_DBG("Complete data");
BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
hci_recv_frame(h4->rx_skb);
h4->rx_state = H4_W4_PACKET_TYPE;
h4->rx_skb = NULL;
continue;
case H4_W4_EVENT_HDR:
eh = (hci_event_hdr *) h4->rx_skb->data;
BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
h4_check_data_len(h4, eh->plen);
continue;
case H4_W4_ACL_HDR:
ah = (hci_acl_hdr *) h4->rx_skb->data;
dlen = __le16_to_cpu(ah->dlen);
BT_DBG("ACL header: dlen %d", dlen);
h4_check_data_len(h4, dlen);
continue;
case H4_W4_SCO_HDR:
sh = (hci_sco_hdr *) h4->rx_skb->data;
BT_DBG("SCO header: dlen %d", sh->dlen);
h4_check_data_len(h4, sh->dlen);
continue;
};
}
/* H4_W4_PACKET_TYPE */
switch (*ptr) {
case HCI_EVENT_PKT:
BT_DBG("Event packet");
h4->rx_state = H4_W4_EVENT_HDR;
h4->rx_count = HCI_EVENT_HDR_SIZE;
type = HCI_EVENT_PKT;
break;
case HCI_ACLDATA_PKT:
BT_DBG("ACL packet");
h4->rx_state = H4_W4_ACL_HDR;
h4->rx_count = HCI_ACL_HDR_SIZE;
type = HCI_ACLDATA_PKT;
break;
case HCI_SCODATA_PKT:
BT_DBG("SCO packet");
h4->rx_state = H4_W4_SCO_HDR;
h4->rx_count = HCI_SCO_HDR_SIZE;
type = HCI_SCODATA_PKT;
break;
default:
BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
n_hci->hdev.stat.err_rx++;
ptr++; count--;
continue;
};
ptr++; count--;
/* Allocate packet */
h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
if (!h4->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
h4->rx_state = H4_W4_PACKET_TYPE;
h4->rx_count = 0;
return 0;
}
h4->rx_skb->dev = (void *) &n_hci->hdev;
h4->rx_skb->pkt_type = type;
}
return count;
}
static struct hci_uart_proto h4p = {
id: HCI_UART_H4,
open: h4_open,
close: h4_close,
send: h4_send,
recv: h4_recv,
preq: h4_preq,
flush: h4_flush,
};
int h4_init(void)
{
return hci_uart_register_proto(&h4p);
}
int h4_deinit(void)
{
return hci_uart_unregister_proto(&h4p);
}
...@@ -23,40 +23,21 @@ ...@@ -23,40 +23,21 @@
*/ */
/* /*
* $Id: hci_uart.h,v 1.2 2001/06/02 01:40:08 maxk Exp $ * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
*/ */
#ifndef N_HCI
#define N_HCI 15
#endif
#ifdef __KERNEL__ #ifdef __KERNEL__
struct h4_struct {
#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data))
#define n_hci2tty(n_hci) ((n_hci)->tty)
struct n_hci {
struct tty_struct *tty;
struct hci_dev hdev;
struct sk_buff_head txq;
unsigned long tx_state;
spinlock_t rx_lock;
unsigned long rx_state; unsigned long rx_state;
unsigned long rx_count; unsigned long rx_count;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
}; };
/* Transmit states */ /* H4 receiver States */
#define TRANS_SENDING 1 #define H4_W4_PACKET_TYPE 0
#define TRANS_WAKEUP 2 #define H4_W4_EVENT_HDR 1
#define H4_W4_ACL_HDR 2
/* Receiver States */ #define H4_W4_SCO_HDR 3
#define WAIT_PACKET_TYPE 0 #define H4_W4_DATA 4
#define WAIT_EVENT_HDR 1
#define WAIT_ACL_HDR 2
#define WAIT_SCO_HDR 3
#define WAIT_DATA 4
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
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.
*/
/*
* $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
*/
#ifndef N_HCI
#define N_HCI 15
#endif
/* Ioctls */
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
/* UART protocols */
#define HCI_UART_MAX_PROTO 3
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_NCSP 2
#ifdef __KERNEL__
struct n_hci;
struct hci_uart_proto {
unsigned int id;
int (*open)(struct n_hci *n_hci);
int (*recv)(struct n_hci *n_hci, void *data, int len);
int (*send)(struct n_hci *n_hci, void *data, int len);
int (*close)(struct n_hci *n_hci);
int (*flush)(struct n_hci *n_hci);
struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb);
};
struct n_hci {
struct tty_struct *tty;
struct hci_dev hdev;
unsigned long flags;
struct hci_uart_proto *proto;
void *priv;
struct sk_buff_head txq;
unsigned long tx_state;
spinlock_t rx_lock;
};
/* N_HCI flag bits */
#define N_HCI_PROTO_SET 0x00
/* TX states */
#define N_HCI_SENDING 1
#define N_HCI_TX_WAKEUP 2
int hci_uart_register_proto(struct hci_uart_proto *p);
int hci_uart_unregister_proto(struct hci_uart_proto *p);
#endif /* __KERNEL__ */
This diff is collapsed.
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
/* /*
* $Id: hci_usb.h,v 1.3 2001/06/02 01:40:08 maxk Exp $ * $Id: hci_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $
*/ */
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -35,34 +35,45 @@ ...@@ -35,34 +35,45 @@
#define HCI_CTRL_REQ 0x20 #define HCI_CTRL_REQ 0x20
#define HCI_MAX_IFACE_NUM 3
#define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_RX 1
struct hci_usb { struct hci_usb {
struct hci_dev hdev;
unsigned long state;
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *isoc_iface;
struct usb_ctrlrequest dev_req; __u8 bulk_out_ep;
struct urb *ctrl_urb; __u8 bulk_in_ep;
struct urb *intr_urb; __u8 isoc_out_ep;
struct urb *read_urb; __u8 isoc_in_ep;
struct urb *write_urb;
__u8 *read_buf; __u8 intr_ep;
__u8 *intr_buf; __u8 intr_interval;
struct sk_buff *intr_skb; struct urb * intr_urb;
int intr_count; struct sk_buff * intr_skb;
__u8 bulk_out_ep_addr; rwlock_t completion_lock;
__u8 bulk_in_ep_addr;
__u8 intr_in_ep_addr;
__u8 intr_in_interval;
struct hci_dev hdev; struct sk_buff_head cmd_q; // TX Commands
struct sk_buff_head acl_q; // TX ACLs
struct sk_buff_head pending_q; // Pending requests
struct sk_buff_head completed_q; // Completed requests
};
unsigned long tx_state; struct hci_usb_scb {
struct sk_buff_head tx_ctrl_q; struct urb *urb;
struct sk_buff_head tx_write_q; int intr_len;
}; };
/* Transmit states */ /* States */
#define HCI_TX_CTRL 1 #define HCI_USB_TX_PROCESS 1
#define HCI_TX_WRITE 2 #define HCI_USB_TX_WAKEUP 2
#define HCI_USB_CTRL_TX 3
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
/* /*
* BlueZ HCI virtual device driver. * BlueZ HCI virtual device driver.
* *
* $Id: hci_vhci.c,v 1.3 2001/08/03 04:19:50 maxk Exp $ * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $
*/ */
#define VERSION "1.0" #define VERSION "1.1"
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -49,43 +49,56 @@ ...@@ -49,43 +49,56 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/bluez.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_vhci.h> #include "hci_vhci.h"
/* HCI device part */ /* HCI device part */
int hci_vhci_open(struct hci_dev *hdev) static int hci_vhci_open(struct hci_dev *hdev)
{ {
hdev->flags |= HCI_RUNNING; set_bit(HCI_RUNNING, &hdev->flags);
return 0; return 0;
} }
int hci_vhci_flush(struct hci_dev *hdev) static int hci_vhci_flush(struct hci_dev *hdev)
{ {
struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
skb_queue_purge(&hci_vhci->readq); skb_queue_purge(&hci_vhci->readq);
return 0; return 0;
} }
int hci_vhci_close(struct hci_dev *hdev) static int hci_vhci_close(struct hci_dev *hdev)
{ {
hdev->flags &= ~HCI_RUNNING; if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
hci_vhci_flush(hdev); hci_vhci_flush(hdev);
return 0; return 0;
} }
int hci_vhci_send_frame(struct sk_buff *skb) static void hci_vhci_destruct(struct hci_dev *hdev)
{
struct hci_vhci_struct *vhci;
if (!hdev) return;
vhci = (struct hci_vhci_struct *) hdev->driver_data;
kfree(vhci);
MOD_DEC_USE_COUNT;
}
static int hci_vhci_send_frame(struct sk_buff *skb)
{ {
struct hci_dev* hdev = (struct hci_dev *) skb->dev; struct hci_dev* hdev = (struct hci_dev *) skb->dev;
struct hci_vhci_struct *hci_vhci; struct hci_vhci_struct *hci_vhci;
if (!hdev) { if (!hdev) {
ERR("Frame for uknown device (hdev=NULL)"); BT_ERR("Frame for uknown device (hdev=NULL)");
return -ENODEV; return -ENODEV;
} }
if (!(hdev->flags & HCI_RUNNING)) if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY; return -EBUSY;
hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
...@@ -188,7 +201,7 @@ static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, l ...@@ -188,7 +201,7 @@ static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, l
add_wait_queue(&hci_vhci->read_wait, &wait); add_wait_queue(&hci_vhci->read_wait, &wait);
while (count) { while (count) {
current->state = TASK_INTERRUPTIBLE; set_current_state(TASK_INTERRUPTIBLE);
/* Read frames from device queue */ /* Read frames from device queue */
if (!(skb = skb_dequeue(&hci_vhci->readq))) { if (!(skb = skb_dequeue(&hci_vhci->readq))) {
...@@ -214,13 +227,17 @@ static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, l ...@@ -214,13 +227,17 @@ static ssize_t hci_vhci_chr_read(struct file * file, char * buf, size_t count, l
kfree_skb(skb); kfree_skb(skb);
break; break;
} }
set_current_state(TASK_RUNNING);
current->state = TASK_RUNNING;
remove_wait_queue(&hci_vhci->read_wait, &wait); remove_wait_queue(&hci_vhci->read_wait, &wait);
return ret; return ret;
} }
static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin)
{
return -ESPIPE;
}
static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{ {
return -EINVAL; return -EINVAL;
...@@ -265,11 +282,13 @@ static int hci_vhci_chr_open(struct inode *inode, struct file * file) ...@@ -265,11 +282,13 @@ static int hci_vhci_chr_open(struct inode *inode, struct file * file)
hdev->close = hci_vhci_close; hdev->close = hci_vhci_close;
hdev->flush = hci_vhci_flush; hdev->flush = hci_vhci_flush;
hdev->send = hci_vhci_send_frame; hdev->send = hci_vhci_send_frame;
hdev->destruct = hci_vhci_destruct;
if (hci_register_dev(hdev) < 0) { if (hci_register_dev(hdev) < 0) {
kfree(hci_vhci); kfree(hci_vhci);
return -EBUSY; return -EBUSY;
} }
MOD_INC_USE_COUNT;
file->private_data = hci_vhci; file->private_data = hci_vhci;
return 0; return 0;
...@@ -280,18 +299,16 @@ static int hci_vhci_chr_close(struct inode *inode, struct file *file) ...@@ -280,18 +299,16 @@ static int hci_vhci_chr_close(struct inode *inode, struct file *file)
struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
if (hci_unregister_dev(&hci_vhci->hdev) < 0) { if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
} }
kfree(hci_vhci);
file->private_data = NULL; file->private_data = NULL;
return 0; return 0;
} }
static struct file_operations hci_vhci_fops = { static struct file_operations hci_vhci_fops = {
owner: THIS_MODULE, owner: THIS_MODULE,
llseek: no_llseek, llseek: hci_vhci_chr_lseek,
read: hci_vhci_chr_read, read: hci_vhci_chr_read,
write: hci_vhci_chr_write, write: hci_vhci_chr_write,
poll: hci_vhci_chr_poll, poll: hci_vhci_chr_poll,
...@@ -310,12 +327,12 @@ static struct miscdevice hci_vhci_miscdev= ...@@ -310,12 +327,12 @@ static struct miscdevice hci_vhci_miscdev=
int __init hci_vhci_init(void) int __init hci_vhci_init(void)
{ {
INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
VERSION); VERSION);
INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
if (misc_register(&hci_vhci_miscdev)) { if (misc_register(&hci_vhci_miscdev)) {
ERR("Can't register misc device %d\n", VHCI_MINOR); BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
return -EIO; return -EIO;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
/* /*
* $Id: hci_vhci.h,v 1.2 2001/08/01 01:02:20 maxk Exp $ * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
*/ */
#ifndef __HCI_VHCI_H #ifndef __HCI_VHCI_H
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
/* /*
* $Id: bluetooth.h,v 1.6 2001/08/03 04:19:49 maxk Exp $ * $Id: bluetooth.h,v 1.8 2002/04/17 17:37:20 maxk Exp $
*/ */
#ifndef __BLUETOOTH_H #ifndef __BLUETOOTH_H
...@@ -31,17 +31,61 @@ ...@@ -31,17 +31,61 @@
#include <asm/types.h> #include <asm/types.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/poll.h>
#include <net/sock.h>
#ifndef AF_BLUETOOTH #ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31 #define AF_BLUETOOTH 31
#define PF_BLUETOOTH AF_BLUETOOTH #define PF_BLUETOOTH AF_BLUETOOTH
#endif #endif
/* Reserv for core and drivers use */
#define BLUEZ_SKB_RESERVE 8
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define BTPROTO_L2CAP 0 #define BTPROTO_L2CAP 0
#define BTPROTO_HCI 1 #define BTPROTO_HCI 1
#define BTPROTO_SCO 2
#define BTPROTO_RFCOMM 3
#define SOL_HCI 0 #define SOL_HCI 0
#define SOL_L2CAP 6 #define SOL_L2CAP 6
#define SOL_SCO 17
#define SOL_RFCOMM 18
/* Debugging */
#ifdef CONFIG_BLUEZ_DEBUG
#define HCI_CORE_DEBUG 1
#define HCI_SOCK_DEBUG 1
#define HCI_UART_DEBUG 1
#define HCI_USB_DEBUG 1
//#define HCI_DATA_DUMP 1
#define L2CAP_DEBUG 1
#define SCO_DEBUG 1
#define AF_BLUETOOTH_DEBUG 1
#endif /* CONFIG_BLUEZ_DEBUG */
extern void bluez_dump(char *pref, __u8 *buf, int count);
#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95
#define __func__ __FUNCTION__
#endif
#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
#ifdef HCI_DATA_DUMP
#define BT_DMP(buf, len) bluez_dump(__func__, buf, len)
#else
#define BT_DMP(D...)
#endif
/* Connection and socket states */ /* Connection and socket states */
enum { enum {
...@@ -50,6 +94,7 @@ enum { ...@@ -50,6 +94,7 @@ enum {
BT_BOUND, BT_BOUND,
BT_LISTEN, BT_LISTEN,
BT_CONNECT, BT_CONNECT,
BT_CONNECT2,
BT_CONFIG, BT_CONFIG,
BT_DISCONN, BT_DISCONN,
BT_CLOSED BT_CLOSED
...@@ -66,7 +111,8 @@ typedef struct { ...@@ -66,7 +111,8 @@ typedef struct {
__u8 b[6]; __u8 b[6];
} __attribute__((packed)) bdaddr_t; } __attribute__((packed)) bdaddr_t;
#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000") #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
/* Copy, swap, convert BD Address */ /* Copy, swap, convert BD Address */
static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
...@@ -82,6 +128,89 @@ void baswap(bdaddr_t *dst, bdaddr_t *src); ...@@ -82,6 +128,89 @@ void baswap(bdaddr_t *dst, bdaddr_t *src);
char *batostr(bdaddr_t *ba); char *batostr(bdaddr_t *ba);
bdaddr_t *strtoba(char *str); bdaddr_t *strtoba(char *str);
/* Common socket structures and functions */
#define bluez_sk(__sk) ((struct bluez_sock *) __sk)
struct bluez_sock {
struct sock sk;
bdaddr_t src;
bdaddr_t dst;
struct list_head accept_q;
struct sock *parent;
};
struct bluez_sock_list {
struct sock *head;
rwlock_t lock;
};
int bluez_sock_register(int proto, struct net_proto_family *ops);
int bluez_sock_unregister(int proto);
struct sock *bluez_sock_alloc(struct socket *sock, int proto, int pi_size, int prio);
void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
int bluez_sock_w4_connect(struct sock *sk, int flags);
void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
/* Skb helpers */
struct bluez_skb_cb {
int incomming;
};
#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
{
struct sk_buff *skb;
if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
skb_reserve(skb, BLUEZ_SKB_RESERVE);
bluez_cb(skb)->incomming = 0;
}
return skb;
}
static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
int nb, int *err)
{
struct sk_buff *skb;
if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
skb_reserve(skb, BLUEZ_SKB_RESERVE);
bluez_cb(skb)->incomming = 0;
}
return skb;
}
static inline int skb_frags_no(struct sk_buff *skb)
{
register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
register int n = 1;
for (; frag; frag=frag->next, n++);
return n;
}
int hci_core_init(void);
int hci_core_cleanup(void);
int hci_sock_init(void);
int hci_sock_cleanup(void);
int bterr(__u16 code); int bterr(__u16 code);
#ifndef MODULE_LICENSE
#define MODULE_LICENSE(x)
#endif
#ifndef list_for_each_safe
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif
#endif /* __BLUETOOTH_H */ #endif /* __BLUETOOTH_H */
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
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.
*/
/*
* $Id: bluez.h,v 1.4 2001/08/03 04:19:49 maxk Exp $
*/
#ifndef __IF_BLUEZ_H
#define __IF_BLUEZ_H
#include <net/sock.h>
#define BLUEZ_MAX_PROTO 2
/* Reserv for core and drivers use */
#define BLUEZ_SKB_RESERVE 8
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/* Debugging */
#ifdef BLUEZ_DEBUG
#define HCI_CORE_DEBUG 1
#define HCI_SOCK_DEBUG 1
#define HCI_UART_DEBUG 1
#define HCI_USB_DEBUG 1
//#define HCI_DATA_DUMP 1
#define L2CAP_DEBUG 1
#endif /* BLUEZ_DEBUG */
extern void bluez_dump(char *pref, __u8 *buf, int count);
#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg)
#ifdef HCI_DATA_DUMP
#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len)
#else
#define DMP(D...)
#endif
/* ----- Sockets ------ */
struct bluez_sock_list {
struct sock *head;
rwlock_t lock;
};
extern int bluez_sock_register(int proto, struct net_proto_family *ops);
extern int bluez_sock_unregister(int proto);
extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
/* ----- SKB helpers ----- */
struct bluez_skb_cb {
int incomming;
};
#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb))
static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
{
struct sk_buff *skb;
if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
skb_reserve(skb, BLUEZ_SKB_RESERVE);
bluez_cb(skb)->incomming = 0;
}
return skb;
}
static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len,
int nb, int *err)
{
struct sk_buff *skb;
if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
skb_reserve(skb, BLUEZ_SKB_RESERVE);
bluez_cb(skb)->incomming = 0;
}
return skb;
}
static inline int skb_frags_no(struct sk_buff *skb)
{
register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
register int n = 1;
for (; frag; frag=frag->next, n++);
return n;
}
extern int hci_core_init(void);
extern int hci_core_cleanup(void);
extern int hci_sock_init(void);
extern int hci_sock_cleanup(void);
#endif /* __IF_BLUEZ_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -9,6 +9,7 @@ if [ "$CONFIG_NET" != "n" ]; then ...@@ -9,6 +9,7 @@ if [ "$CONFIG_NET" != "n" ]; then
if [ "$CONFIG_BLUEZ" != "n" ]; then if [ "$CONFIG_BLUEZ" != "n" ]; then
dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
source drivers/bluetooth/Config.in source drivers/bluetooth/Config.in
fi fi
endmenu endmenu
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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