openzaurus-pxa27x: autoload usb host module
authorMichael Lauer <mickey@vanille-media.de>
Sun, 24 Jul 2005 19:30:31 +0000 (19:30 +0000)
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>
Sun, 24 Jul 2005 19:30:31 +0000 (19:30 +0000)
openzaurus-pxa: remove outdated bluetooth patch, use local WE patches

packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch [deleted file]
packages/linux/openzaurus-pxa27x_2.4.20-rmk2-embedix20050228.bb
packages/linux/openzaurus-pxa_2.4.18-rmk7-pxa3-embedix20031107.inc

diff --git a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch b/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch
deleted file mode 100644 (file)
index ff3582a..0000000
+++ /dev/null
@@ -1,31393 +0,0 @@
-
-#
-# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
-#
-
---- linux/arch/alpha/config.in~bluetooth-2.4.18-mh11   2004-01-25 23:28:10.000000000 +0100
-+++ linux/arch/alpha/config.in 2004-01-25 23:37:39.000000000 +0100
-@@ -372,9 +372,7 @@
- source drivers/usb/Config.in
- source drivers/input/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Kernel hacking'
---- linux/arch/arm/config.in~bluetooth-2.4.18-mh11     2004-01-25 23:28:31.000000000 +0100
-+++ linux/arch/arm/config.in   2004-01-25 23:37:39.000000000 +0100
-@@ -796,9 +796,7 @@
- source drivers/usb/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Kernel hacking'
---- linux/arch/i386/config.in~bluetooth-2.4.18-mh11    2004-01-25 23:28:31.000000000 +0100
-+++ linux/arch/i386/config.in  2004-01-25 23:37:39.000000000 +0100
-@@ -415,9 +415,7 @@
- source drivers/usb/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Kernel hacking'
---- linux/arch/ppc/config.in~bluetooth-2.4.18-mh11     2004-01-25 23:28:11.000000000 +0100
-+++ linux/arch/ppc/config.in   2004-01-25 23:37:39.000000000 +0100
-@@ -390,9 +390,7 @@
- source drivers/usb/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Kernel hacking'
---- linux/arch/sparc/config.in~bluetooth-2.4.18-mh11   2004-01-25 23:28:11.000000000 +0100
-+++ linux/arch/sparc/config.in 2004-01-25 23:37:39.000000000 +0100
-@@ -252,9 +252,7 @@
- source fs/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Watchdog'
---- linux/arch/sparc64/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:11.000000000 +0100
-+++ linux/arch/sparc64/config.in       2004-01-25 23:37:39.000000000 +0100
-@@ -284,9 +284,7 @@
- source drivers/usb/Config.in
--if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
--   source net/bluetooth/Config.in
--fi
-+source net/bluetooth/Config.in
- mainmenu_option next_comment
- comment 'Watchdog'
---- linux/arch/sparc64/kernel/ioctl32.c~bluetooth-2.4.18-mh11  2002-02-25 20:37:56.000000000 +0100
-+++ linux/arch/sparc64/kernel/ioctl32.c        2004-01-25 23:37:39.000000000 +0100
-@@ -92,6 +92,7 @@
- #include <net/bluetooth/bluetooth.h>
- #include <net/bluetooth/hci.h>
-+#include <net/bluetooth/rfcomm.h>
- #include <linux/usb.h>
- #include <linux/usbdevice_fs.h>
-@@ -3822,6 +3823,15 @@
-       return err;
- }
-+/* Bluetooth ioctls */
-+#define HCIUARTSETPROTO       _IOW('U', 200, int)
-+#define HCIUARTGETPROTO       _IOR('U', 201, int)
-+
-+#define BNEPCONNADD   _IOW('B', 200, int)
-+#define BNEPCONNDEL   _IOW('B', 201, int)
-+#define BNEPGETCONNLIST       _IOR('B', 210, int)
-+#define BNEPGETCONNINFO       _IOR('B', 211, int)
-+
- struct mtd_oob_buf32 {
-       u32 start;
-       u32 length;
-@@ -3878,6 +3888,11 @@
-       return ((0 == ret) ? 0 : -EFAULT);
- }     
-+#define CMTPCONNADD   _IOW('C', 200, int)
-+#define CMTPCONNDEL   _IOW('C', 201, int)
-+#define CMTPGETCONNLIST       _IOR('C', 210, int)
-+#define CMTPGETCONNINFO       _IOR('C', 211, int)
-+
- struct ioctl_trans {
-       unsigned int cmd;
-       unsigned int handler;
-@@ -4540,6 +4555,21 @@
- COMPATIBLE_IOCTL(HCISETSCAN)
- COMPATIBLE_IOCTL(HCISETAUTH)
- COMPATIBLE_IOCTL(HCIINQUIRY)
-+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-+COMPATIBLE_IOCTL(BNEPCONNADD)
-+COMPATIBLE_IOCTL(BNEPCONNDEL)
-+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-+COMPATIBLE_IOCTL(CMTPCONNADD)
-+COMPATIBLE_IOCTL(CMTPCONNDEL)
-+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
-+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
- /* Misc. */
- COMPATIBLE_IOCTL(0x41545900)          /* ATYIO_CLKR */
- COMPATIBLE_IOCTL(0x41545901)          /* ATYIO_CLKW */
---- linux/CREDITS~bluetooth-2.4.18-mh11        2004-01-25 23:28:29.000000000 +0100
-+++ linux/CREDITS      2004-01-25 23:37:39.000000000 +0100
-@@ -1317,6 +1317,15 @@
- S: Provo, Utah 84606-5607
- S: USA
-+N: Marcel Holtmann
-+E: marcel@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 CAPI message transport protocol driver
-+D: Various other Bluetooth related patches, cleanups and fixes
-+S: Germany
-+
- N: Rob W. W. Hooft
- E: hooft@EMBL-Heidelberg.DE
- D: Shared libs for graphics-tools and for the f2c compiler
-@@ -2555,6 +2564,7 @@
- N: Aristeu Sergio Rozanski Filho
- E: aris@conectiva.com.br
- D: Support for EtherExpress 10 ISA (i82595) in eepro driver
-+D: User level driver support for input
- S: Conectiva S.A.
- S: R. Tocantins, 89 - Cristo Rei
- S: 80050-430 - Curitiba - ParanĂ¡
---- linux/Documentation/Configure.help~bluetooth-2.4.18-mh11   2004-01-25 23:28:31.000000000 +0100
-+++ linux/Documentation/Configure.help 2004-01-25 23:37:39.000000000 +0100
-@@ -2847,14 +2847,6 @@
-   If unsure, say N.
--HCI EMU (virtual device) driver
--CONFIG_BLUEZ_HCIEMU
--  Bluetooth Virtual HCI device driver.
--  This driver is required if you want to use HCI Emulation software.
--
--  Say Y here to compile support for Virtual HCI devices into the
--  kernel or say M to compile it as module (hci_usb.o).
--
- # Choice: alphatype
- Alpha system type
- CONFIG_ALPHA_GENERIC
-@@ -11067,6 +11059,12 @@
-   If unsure, say N.
-+Hotplug firmware loading support (EXPERIMENTAL)
-+CONFIG_FW_LOADER
-+  This option is provided for the case where no in-kernel-tree modules require
-+  hotplug firmware loading support, but a module built outside the kernel tree
-+  does.
-+
- Use PCI shared memory for NIC registers
- CONFIG_TULIP_MMIO
-   Use PCI shared memory for the NIC registers, rather than going through 
-@@ -12967,6 +12965,15 @@
-   accessible under char device 13:64+ - /dev/input/eventX in a generic
-   way.  This is the future ...
-+CONFIG_INPUT_UINPUT
-+  Say Y here if you want to support user level drivers for input
-+  subsystem accessible under char device 10:223 - /dev/input/uinput.
-+
-+  This driver is also available as a module ( = code which can be
-+  inserted in and removed from the running kernel whenever you want).
-+  The module will be called uinput.o.  If you want to compile it as a
-+  module, say M here and read <file:Documentation/modules.txt>.           
-+
- USB Scanner support
- CONFIG_USB_SCANNER
-   Say Y here if you want to connect a USB scanner to your computer's
-@@ -19986,11 +19993,15 @@
-   Bluetooth can be found at <http://www.bluetooth.com/>.
-   Linux Bluetooth subsystem consist of several layers:
--               HCI Core (device and connection manager, scheduler)
-+               BlueZ Core (HCI device and connection manager, scheduler)
-                HCI Device drivers (interface to the hardware)
-                L2CAP Module (L2CAP protocol)
-+               SCO Module (SCO links)
-+               RFCOMM Module (RFCOMM protocol)
-+               BNEP Module (BNEP protocol)
-+               CMTP Module (CMTP protocol)
--  Say Y here to enable Linux Bluetooth support and to build HCI Core
-+  Say Y here to enable Linux Bluetooth support and to build BlueZ Core
-   layer.
-   To use Linux Bluetooth subsystem, you will need several user-space
-@@ -19998,7 +20009,7 @@
-   Bluetooth kernel modules are provided in the BlueZ package.
-   For more information, see <http://bluez.sourceforge.net/>.
--  If you want to compile HCI Core as module (hci.o) say M here.
-+  If you want to compile BlueZ Core as module (bluez.o) say M here.
- L2CAP protocol support
- CONFIG_BLUEZ_L2CAP
-@@ -20009,15 +20020,91 @@
-   Say Y here to compile L2CAP support into the kernel or say M to
-   compile it as module (l2cap.o).
-+SCO links support
-+CONFIG_BLUEZ_SCO
-+  SCO link provides voice transport over Bluetooth. SCO support is
-+  required for voice applications like Headset and Audio.
-+
-+  Say Y here to compile SCO support into the kernel or say M to
-+  compile it as module (sco.o).
-+
-+RFCOMM protocol support
-+CONFIG_BLUEZ_RFCOMM
-+  RFCOMM provides connection oriented stream transport. RFCOMM
-+  support is required for Dialup Networking, OBEX and other Bluetooth
-+  applications.
-+
-+  Say Y here to compile RFCOMM support into the kernel or say M to
-+  compile it as module (rfcomm.o).
-+
-+RFCOMM TTY emulation support
-+CONFIG_BLUEZ_RFCOMM_TTY
-+  This option enables TTY emulation support for RFCOMM channels.
-+
-+BNEP protocol support
-+CONFIG_BLUEZ_BNEP
-+  BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
-+  emulation layer on top of Bluetooth. BNEP is required for Bluetooth
-+  PAN (Personal Area Network).
-+
-+  To use BNEP, you will need user-space utilities provided in the 
-+  BlueZ-PAN package.
-+  For more information, see <http://bluez.sourceforge.net>.
-+
-+  Say Y here to compile BNEP support into the kernel or say M to
-+  compile it as module (bnep.o).
-+
-+CMTP protocol support
-+CONFIG_BLUEZ_CMTP
-+  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.o).
-+
-+BNEP multicast filter support
-+CONFIG_BLUEZ_BNEP_MC_FILTER
-+  This option enables the multicast filter support for BNEP.
-+
-+BNEP protocol filter support
-+CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+  This option enables the protocol filter support for BNEP.
-+
- HCI UART driver
- CONFIG_BLUEZ_HCIUART
-   Bluetooth HCI UART driver.
-   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
-   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 Bluetooth devices 
-+  with UART interface, including PCMCIA and CF cards. 
-+
-+  Say Y here to compile support for HCI UART (H4) protocol.
-+
-+HCI BCSP protocol support 
-+CONFIG_BLUEZ_HCIUART_BCSP
-+  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
-+  between Bluetooth device and host. This protocol is required for non
-+  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
-+  CF cards.
-+
-+  Say Y here to compile support for HCI BCSP protocol.
-+
-+HCI BCSP transmit CRC with every BCSP packet
-+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+  If you say Y here, a 16-bit CRC checksum will be transmitted along with
-+  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
-+  This increases reliability, but slightly reduces efficiency.
-+
- HCI USB driver
- CONFIG_BLUEZ_HCIUSB
-   Bluetooth HCI USB driver.
-@@ -20027,7 +20114,16 @@
-   Say Y here to compile support for Bluetooth USB devices into the
-   kernel or say M to compile it as module (hci_usb.o).
--HCI VHCI virtual HCI device driver
-+HCI USB SCO (voice) support
-+CONFIG_BLUEZ_HCIUSB_SCO
-+  This option enables the SCO support in the HCI USB driver. You need this
-+  to transmit voice data with your Bluetooth USB device. And your device
-+  must also support sending SCO data over the HCI layer, because some of
-+  them sends the SCO data to an internal PCM adapter.
-+ 
-+  Say Y here to compile support for HCI SCO data.
-+ 
-+HCI VHCI Virtual HCI device driver
- CONFIG_BLUEZ_HCIVHCI
-   Bluetooth Virtual HCI device driver.
-   This driver is required if you want to use HCI Emulation software.
-@@ -20035,6 +20131,66 @@
-   Say Y here to compile support for virtual HCI devices into the
-   kernel or say M to compile it as module (hci_vhci.o).
-+HCI BFUSB device driver
-+CONFIG_BLUEZ_HCIBFUSB
-+  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.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 BT3C (PC Card) device driver
-+CONFIG_BLUEZ_HCIBT3C
-+  Bluetooth HCI BT3C (PC Card) driver.
-+  This driver provides support for Bluetooth PCMCIA devices with
-+  3Com BT3C interface:
-+     3Com Bluetooth Card (3CRWB6096)
-+     HP Bluetooth Card
-+
-+  The HCI BT3C driver uses external firmware loader program provided in
-+  the BlueFW package. For more information, see <http://bluez.sf.net>.
-+
-+  Say Y here to compile support for HCI BT3C devices into the
-+  kernel or say M to compile it as module (bt3c_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).
-+
-+HCI UART (PC Card) device driver
-+CONFIG_BLUEZ_HCIBTUART
-+  Bluetooth HCI UART (PC Card) driver.
-+  This driver provides support for Bluetooth PCMCIA devices with
-+  an UART interface:
-+     Xircom CreditCard Bluetooth Adapter
-+     Xircom RealPort2 Bluetooth Adapter
-+     Sphinx PICO Card
-+     H-Soft blue+Card
-+     Cyber-blue Compact Flash Card
-+
-+  Say Y here to compile support for HCI UART devices into the
-+  kernel or say M to compile it as module (btuart_cs.o).
-+
- # The following options are for Linux when running on the Hitachi
- # SuperH family of RISC microprocessors.
---- linux/Documentation/devices.txt~bluetooth-2.4.18-mh11      2001-11-07 23:46:01.000000000 +0100
-+++ linux/Documentation/devices.txt    2004-01-25 23:37:39.000000000 +0100
-@@ -419,6 +419,7 @@
-               220 = /dev/mptctl       Message passing technology (MPT) control
-               221 = /dev/mvista/hssdsi        Montavista PICMG hot swap system driver
-               222 = /dev/mvista/hasi          Montavista PICMG high availability
-+              223 = /dev/input/uinput         User level driver support for input
-               240-255                 Reserved for local use
-  11 char      Raw keyboard device
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/firmware_class/firmware_sample_driver.c        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,121 @@
-+/*
-+ * firmware_sample_driver.c -
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Sample code on how to use request_firmware() from drivers.
-+ *
-+ * Note that register_firmware() is currently useless.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/string.h>
-+
-+#include "linux/firmware.h"
-+
-+#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+char __init inkernel_firmware[] = "let's say that this is firmware\n";
-+#endif
-+
-+static char ghost_device[] = "ghost0";
-+
-+static void sample_firmware_load(char *firmware, int size)
-+{
-+      u8 buf[size+1];
-+      memcpy(buf, firmware, size);
-+      buf[size] = '\0';
-+      printk("firmware_sample_driver: firmware: %s\n", buf);
-+}
-+
-+static void sample_probe_default(void)
-+{
-+      /* uses the default method to get the firmware */
-+        const struct firmware *fw_entry;
-+      printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+        if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
-+      {
-+              printk(KERN_ERR
-+                     "firmware_sample_driver: Firmware not available\n");
-+              return;
-+      }
-+      
-+      sample_firmware_load(fw_entry->data, fw_entry->size);
-+
-+      release_firmware(fw_entry);
-+
-+      /* finish setting up the device */
-+}
-+static void sample_probe_specific(void)
-+{
-+      /* Uses some specific hotplug support to get the firmware from
-+       * userspace  directly into the hardware, or via some sysfs file */
-+
-+      /* NOTE: This currently doesn't work */
-+
-+      printk("firmware_sample_driver: a ghost device got inserted :)\n");
-+
-+        if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
-+      {
-+              printk(KERN_ERR
-+                     "firmware_sample_driver: Firmware load failed\n");
-+              return;
-+      }
-+      
-+      /* request_firmware blocks until userspace finished, so at
-+       * this point the firmware should be already in the device */
-+
-+      /* finish setting up the device */
-+}
-+static void sample_probe_async_cont(const struct firmware *fw, void *context)
-+{
-+      if(!fw){
-+              printk(KERN_ERR
-+                     "firmware_sample_driver: firmware load failed\n");
-+              return;
-+      }
-+
-+      printk("firmware_sample_driver: device pointer \"%s\"\n",
-+             (char *)context);
-+      sample_firmware_load(fw->data, fw->size);
-+}
-+static void sample_probe_async(void)
-+{
-+      /* Let's say that I can't sleep */
-+      int error;
-+      error = request_firmware_nowait (THIS_MODULE,
-+                                       "sample_driver_fw", ghost_device,
-+                                       "my device pointer",
-+                                       sample_probe_async_cont);
-+      if(error){
-+              printk(KERN_ERR 
-+                     "firmware_sample_driver:"
-+                     " request_firmware_nowait failed\n");
-+      }
-+}
-+
-+static int sample_init(void)
-+{
-+#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
-+      register_firmware("sample_driver_fw", inkernel_firmware,
-+                        sizeof(inkernel_firmware));
-+#endif
-+      /* since there is no real hardware insertion I just call the
-+       * sample probe functions here */
-+      sample_probe_specific();
-+      sample_probe_default();
-+      sample_probe_async();
-+      return 0;
-+}
-+static void __exit sample_exit(void)
-+{
-+}
-+
-+module_init (sample_init);
-+module_exit (sample_exit);
-+
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/firmware_class/hotplug-script  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,16 @@
-+#!/bin/sh
-+
-+# Simple hotplug script sample:
-+# 
-+# Both $DEVPATH and $FIRMWARE are already provided in the environment.
-+
-+HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
-+
-+echo 1 > /sysfs/$DEVPATH/loading
-+cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
-+echo 0 > /sysfs/$DEVPATH/loading
-+
-+# To cancel the load in case of error:
-+#
-+#     echo -1 > /sysfs/$DEVPATH/loading
-+#
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/Documentation/firmware_class/README  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,58 @@
-+
-+ request_firmware() hotplug interface:
-+ ------------------------------------
-+      Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+
-+ Why:
-+ ---
-+
-+ Today, the most extended way to use firmware in the Linux kernel is linking
-+ it statically in a header file. Which has political and technical issues:
-+
-+  1) Some firmware is not legal to redistribute.
-+  2) The firmware occupies memory permanently, even though it often is just
-+     used once.
-+  3) Some people, like the Debian crowd, don't consider some firmware free
-+     enough and remove entire drivers (e.g.: keyspan).
-+
-+ about in-kernel persistence:
-+ ---------------------------
-+ Under some circumstances, as explained below, it would be interesting to keep
-+ firmware images in non-swappable kernel memory or even in the kernel image
-+ (probably within initramfs).
-+
-+ Note that this functionality has not been implemented.
-+
-+ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
-+ 
-+      - If the device that needs the firmware is needed to access the
-+        filesystem. When upon some error the device has to be reset and the
-+        firmware reloaded, it won't be possible to get it from userspace.
-+        e.g.:
-+              - A diskless client with a network card that needs firmware.
-+              - The filesystem is stored in a disk behind an scsi device
-+                that needs firmware.
-+      - Replacing buggy DSDT/SSDT ACPI tables on boot.
-+        Note: this would require the persistent objects to be included
-+        within the kernel image, probably within initramfs.
-+        
-+   And the same device can be needed to access the filesystem or not depending
-+   on the setup, so I think that the choice on what firmware to make
-+   persistent should be left to userspace.
-+
-+ - Why register_firmware()+__init can be useful:
-+      - For boot devices needing firmware.
-+      - To make the transition easier:
-+              The firmware can be declared __init and register_firmware()
-+              called on module_init. Then the firmware is warranted to be
-+              there even if "firmware hotplug userspace" is not there yet or
-+              it doesn't yet provide the needed firmware.
-+              Once the firmware is widely available in userspace, it can be
-+              removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
-+
-+      In either case, if firmware hotplug support is there, it can move the
-+      firmware out of kernel memory into the real filesystem for later
-+      usage.
-+
-+      Note: If persistence is implemented on top of initramfs,
-+      register_firmware() may not be appropriate.
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/bfusb.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,781 @@
-+/*
-+ *
-+ *  AVM BlueFRITZ! USB 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/sched.h>
-+#include <linux/errno.h>
-+#include <linux/skbuff.h>
-+
-+#include <linux/firmware.h>
-+#include <linux/usb.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static struct usb_device_id bfusb_table[] = {
-+      /* AVM BlueFRITZ! USB */
-+      { USB_DEVICE(0x057c, 0x2200) },
-+
-+      { }     /* Terminating entry */
-+};
-+
-+MODULE_DEVICE_TABLE(usb, bfusb_table);
-+
-+
-+#define BFUSB_MAX_BLOCK_SIZE  256
-+
-+#define BFUSB_BLOCK_TIMEOUT   (HZ * 3)
-+
-+#define BFUSB_TX_PROCESS      1
-+#define BFUSB_TX_WAKEUP               2
-+
-+#define BFUSB_MAX_BULK_TX     1
-+#define BFUSB_MAX_BULK_RX     1
-+
-+struct bfusb {
-+      struct hci_dev          hdev;
-+
-+      unsigned long           state;
-+
-+      struct usb_device       *udev;
-+
-+      unsigned int            bulk_in_ep;
-+      unsigned int            bulk_out_ep;
-+      unsigned int            bulk_pkt_size;
-+
-+      rwlock_t                lock;
-+
-+      struct sk_buff_head     transmit_q;
-+
-+      struct sk_buff          *reassembly;
-+
-+      atomic_t                pending_tx;
-+      struct sk_buff_head     pending_q;
-+      struct sk_buff_head     completed_q;
-+};
-+
-+struct bfusb_scb {
-+      struct urb *urb;
-+};
-+
-+static void bfusb_tx_complete(struct urb *urb);
-+static void bfusb_rx_complete(struct urb *urb);
-+
-+static struct urb *bfusb_get_completed(struct bfusb *bfusb)
-+{
-+      struct sk_buff *skb;
-+      struct urb *urb = NULL;
-+
-+      BT_DBG("bfusb %p", bfusb);
-+
-+      skb = skb_dequeue(&bfusb->completed_q);
-+      if (skb) {
-+              urb = ((struct bfusb_scb *) skb->cb)->urb;
-+              kfree_skb(skb);
-+      }
-+
-+      return urb;
-+}
-+
-+static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
-+{
-+      struct sk_buff *skb;
-+      struct urb *urb;
-+
-+      BT_DBG("bfusb %p", bfusb);
-+
-+      while ((skb = skb_dequeue(&bfusb->pending_q))) {
-+              urb = ((struct bfusb_scb *) skb->cb)->urb;
-+              usb_unlink_urb(urb);
-+              skb_queue_tail(&bfusb->completed_q, skb);
-+      }
-+
-+      while ((urb = bfusb_get_completed(bfusb)))
-+              usb_free_urb(urb);
-+}
-+
-+
-+static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
-+{
-+      struct bfusb_scb *scb = (void *) skb->cb;
-+      struct urb *urb = bfusb_get_completed(bfusb);
-+      int err, pipe;
-+
-+      BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
-+
-+      if (!urb && !(urb = usb_alloc_urb(0)))
-+              return -ENOMEM;
-+
-+      pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+      FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
-+                      bfusb_tx_complete, skb);
-+
-+      urb->transfer_flags = USB_QUEUE_BULK;
-+
-+      scb->urb = urb;
-+
-+      skb_queue_tail(&bfusb->pending_q, skb);
-+
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s bulk tx submit failed urb %p err %d", 
-+                                      bfusb->hdev.name, urb, err);
-+              skb_unlink(skb);
-+              usb_free_urb(urb);
-+      } else
-+              atomic_inc(&bfusb->pending_tx);
-+
-+      return err;
-+}
-+
-+static void bfusb_tx_wakeup(struct bfusb *bfusb)
-+{
-+      struct sk_buff *skb;
-+
-+      BT_DBG("bfusb %p", bfusb);
-+
-+      if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
-+              set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+              return;
-+      }
-+
-+      do {
-+              clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
-+
-+              while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
-+                              (skb = skb_dequeue(&bfusb->transmit_q))) {
-+                      if (bfusb_send_bulk(bfusb, skb) < 0) {
-+                              skb_queue_head(&bfusb->transmit_q, skb);
-+                              break;
-+                      }
-+              }
-+
-+      } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
-+
-+      clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
-+}
-+
-+static void bfusb_tx_complete(struct urb *urb)
-+{
-+      struct sk_buff *skb = (struct sk_buff *) urb->context;
-+      struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+
-+      BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+      atomic_dec(&bfusb->pending_tx);
-+
-+      if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+              return;
-+
-+      if (!urb->status)
-+              bfusb->hdev.stat.byte_tx += skb->len;
-+      else
-+              bfusb->hdev.stat.err_tx++;
-+
-+      read_lock(&bfusb->lock);
-+
-+      skb_unlink(skb);
-+      skb_queue_tail(&bfusb->completed_q, skb);
-+
-+      bfusb_tx_wakeup(bfusb);
-+
-+      read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
-+{
-+      struct bfusb_scb *scb;
-+      struct sk_buff *skb;
-+      int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
-+
-+      BT_DBG("bfusb %p urb %p", bfusb, urb);
-+
-+      if (!urb && !(urb = usb_alloc_urb(0)))
-+              return -ENOMEM;
-+
-+      if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
-+              usb_free_urb(urb);
-+              return -ENOMEM;
-+      }
-+
-+      skb->dev = (void *) bfusb;
-+
-+      scb = (struct bfusb_scb *) skb->cb;
-+      scb->urb = urb;
-+
-+      pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
-+
-+      FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
-+                      bfusb_rx_complete, skb);
-+
-+      urb->transfer_flags = USB_QUEUE_BULK;
-+
-+      skb_queue_tail(&bfusb->pending_q, skb);
-+
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s bulk rx submit failed urb %p err %d",
-+                                      bfusb->hdev.name, urb, err);
-+              skb_unlink(skb);
-+              kfree_skb(skb);
-+              usb_free_urb(urb);
-+      }
-+
-+      return err;
-+}
-+
-+static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
-+{
-+      BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
-+
-+      if (hdr & 0x10) {
-+              BT_ERR("%s error in block", bfusb->hdev.name);
-+              if (bfusb->reassembly)
-+                      kfree_skb(bfusb->reassembly);
-+              bfusb->reassembly = NULL;
-+              return -EIO;
-+      }
-+
-+      if (hdr & 0x04) {
-+              struct sk_buff *skb;
-+              unsigned char pkt_type;
-+              int pkt_len = 0;
-+
-+              if (bfusb->reassembly) {
-+                      BT_ERR("%s unexpected start block", bfusb->hdev.name);
-+                      kfree_skb(bfusb->reassembly);
-+                      bfusb->reassembly = NULL;
-+              }
-+
-+              if (len < 1) {
-+                      BT_ERR("%s no packet type found", bfusb->hdev.name);
-+                      return -EPROTO;
-+              }
-+
-+              pkt_type = *data++; len--;
-+
-+              switch (pkt_type) {
-+              case HCI_EVENT_PKT:
-+                      if (len >= HCI_EVENT_HDR_SIZE) {
-+                              hci_event_hdr *hdr = (hci_event_hdr *) data;
-+                              pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
-+                      } else {
-+                              BT_ERR("%s event block is too short", bfusb->hdev.name);
-+                              return -EILSEQ;
-+                      }
-+                      break;
-+
-+              case HCI_ACLDATA_PKT:
-+                      if (len >= HCI_ACL_HDR_SIZE) {
-+                              hci_acl_hdr *hdr = (hci_acl_hdr *) data;
-+                              pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
-+                      } else {
-+                              BT_ERR("%s data block is too short", bfusb->hdev.name);
-+                              return -EILSEQ;
-+                      }
-+                      break;
-+
-+              case HCI_SCODATA_PKT:
-+                      if (len >= HCI_SCO_HDR_SIZE) {
-+                              hci_sco_hdr *hdr = (hci_sco_hdr *) data;
-+                              pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
-+                      } else {
-+                              BT_ERR("%s audio block is too short", bfusb->hdev.name);
-+                              return -EILSEQ;
-+                      }
-+                      break;
-+              }
-+
-+              skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
-+              if (!skb) {
-+                      BT_ERR("%s no memory for the packet", bfusb->hdev.name);
-+                      return -ENOMEM;
-+              }
-+
-+              skb->dev = (void *) &bfusb->hdev;
-+              skb->pkt_type = pkt_type;
-+
-+              bfusb->reassembly = skb;
-+      } else {
-+              if (!bfusb->reassembly) {
-+                      BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
-+                      return -EIO;
-+              }
-+      }
-+
-+      if (len > 0)
-+              memcpy(skb_put(bfusb->reassembly, len), data, len);
-+
-+      if (hdr & 0x08) {
-+              hci_recv_frame(bfusb->reassembly);
-+              bfusb->reassembly = NULL;
-+      }
-+
-+      return 0;
-+}
-+
-+static void bfusb_rx_complete(struct urb *urb)
-+{
-+      struct sk_buff *skb = (struct sk_buff *) urb->context;
-+      struct bfusb *bfusb = (struct bfusb *) skb->dev;
-+      unsigned char *buf = urb->transfer_buffer;
-+      int count = urb->actual_length;
-+      int err, hdr, len;
-+
-+      BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
-+
-+      if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
-+              return;
-+
-+      read_lock(&bfusb->lock);
-+
-+      if (urb->status || !count)
-+              goto resubmit;
-+
-+      bfusb->hdev.stat.byte_rx += count;
-+
-+      skb_put(skb, count);
-+
-+      while (count) {
-+              hdr = buf[0] | (buf[1] << 8);
-+
-+              if (hdr & 0x4000) {
-+                      len = 0;
-+                      count -= 2;
-+                      buf   += 2;
-+              } else {
-+                      len = (buf[2] == 0) ? 256 : buf[2];
-+                      count -= 3;
-+                      buf   += 3;
-+              }
-+
-+              if (count < len) {
-+                      BT_ERR("%s block extends over URB buffer ranges",
-+                                      bfusb->hdev.name);
-+              }
-+
-+              if ((hdr & 0xe1) == 0xc1)
-+                      bfusb_recv_block(bfusb, hdr, buf, len);
-+
-+              count -= len;
-+              buf   += len;
-+      }
-+
-+      skb_unlink(skb);
-+      kfree_skb(skb);
-+
-+      bfusb_rx_submit(bfusb, urb);
-+
-+      read_unlock(&bfusb->lock);
-+
-+      return;
-+
-+resubmit:
-+      urb->dev = bfusb->udev;
-+
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s bulk resubmit failed urb %p err %d",
-+                                      bfusb->hdev.name, urb, err);
-+      }
-+
-+      read_unlock(&bfusb->lock);
-+}
-+
-+
-+static int bfusb_open(struct hci_dev *hdev)
-+{
-+      struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+      unsigned long flags;
-+      int i, err;
-+
-+      BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+      if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+              return 0;
-+
-+      MOD_INC_USE_COUNT;
-+
-+      write_lock_irqsave(&bfusb->lock, flags);
-+
-+      err = bfusb_rx_submit(bfusb, NULL);
-+      if (!err) {
-+              for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
-+                      bfusb_rx_submit(bfusb, NULL);
-+      } else {
-+              clear_bit(HCI_RUNNING, &hdev->flags);
-+              MOD_DEC_USE_COUNT;
-+      }
-+
-+      write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+      return err;
-+}
-+
-+static int bfusb_flush(struct hci_dev *hdev)
-+{
-+      struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+      BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+      skb_queue_purge(&bfusb->transmit_q);
-+
-+      return 0;
-+}
-+
-+static int bfusb_close(struct hci_dev *hdev)
-+{
-+      struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+      unsigned long flags;
-+
-+      BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+      if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+              return 0;
-+
-+      write_lock_irqsave(&bfusb->lock, flags);
-+
-+      bfusb_unlink_urbs(bfusb);
-+      bfusb_flush(hdev);
-+
-+      write_unlock_irqrestore(&bfusb->lock, flags);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      return 0;
-+}
-+
-+static int bfusb_send_frame(struct sk_buff *skb)
-+{
-+      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+      struct bfusb *bfusb;
-+      struct sk_buff *nskb;
-+      unsigned char buf[3];
-+      int sent = 0, size, count;
-+
-+      BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
-+
-+      if (!hdev) {
-+              BT_ERR("Frame for unknown HCI device (hdev=NULL)");
-+              return -ENODEV;
-+      }
-+
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-+              return -EBUSY;
-+
-+      bfusb = (struct bfusb *) hdev->driver_data;
-+
-+      switch (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;
-+      };
-+
-+      /* Prepend skb with frame type */
-+      memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+
-+      count = skb->len;
-+
-+      /* Max HCI frame size seems to be 1511 + 1 */
-+      if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
-+              BT_ERR("Can't allocate memory for new packet");
-+              return -ENOMEM;
-+      }
-+
-+      nskb->dev = (void *) bfusb;
-+
-+      while (count) {
-+              size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
-+
-+              buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
-+              buf[1] = 0x00;
-+              buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
-+
-+              memcpy(skb_put(nskb, 3), buf, 3);
-+              memcpy(skb_put(nskb, size), skb->data + sent, size);
-+
-+              sent  += size;
-+              count -= size;
-+      }
-+
-+      /* Don't send frame with multiple size of bulk max packet */
-+      if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
-+              buf[0] = 0xdd;
-+              buf[1] = 0x00;
-+              memcpy(skb_put(nskb, 2), buf, 2);
-+      }
-+
-+      read_lock(&bfusb->lock);
-+
-+      skb_queue_tail(&bfusb->transmit_q, nskb);
-+      bfusb_tx_wakeup(bfusb);
-+
-+      read_unlock(&bfusb->lock);
-+
-+      kfree_skb(skb);
-+
-+      return 0;
-+}
-+
-+static void bfusb_destruct(struct hci_dev *hdev)
-+{
-+      struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
-+
-+      BT_DBG("hdev %p bfusb %p", hdev, bfusb);
-+
-+      kfree(bfusb);
-+}
-+
-+static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+      return -ENOIOCTLCMD;
-+}
-+
-+
-+static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
-+{
-+      unsigned char *buf;
-+      int err, pipe, len, size, sent = 0;
-+
-+      BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
-+
-+      BT_INFO("BlueFRITZ! USB loading firmware");
-+
-+      if (usb_set_configuration(bfusb->udev, 1) < 0) {
-+              BT_ERR("Can't change to loading configuration");
-+              return -EBUSY;
-+      }
-+
-+      buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
-+      if (!buf) {
-+              BT_ERR("Can't allocate memory chunk for firmware");
-+              return -ENOMEM;
-+      }
-+
-+      pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
-+
-+      while (count) {
-+              size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
-+
-+              memcpy(buf, firmware + sent, size);
-+
-+              err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
-+                                      &len, BFUSB_BLOCK_TIMEOUT);
-+
-+              if (err || (len != size)) {
-+                      BT_ERR("Error in firmware loading");
-+                      goto error;
-+              }
-+
-+              sent  += size;
-+              count -= size;
-+      }
-+
-+      if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
-+                              &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
-+              BT_ERR("Error in null packet request");
-+              goto error;
-+      }
-+
-+      if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
-+              BT_ERR("Can't change to running configuration");
-+              goto error;
-+      }
-+
-+      BT_INFO("BlueFRITZ! USB device ready");
-+
-+      kfree(buf);
-+      return 0;
-+
-+error:
-+      kfree(buf);
-+
-+      pipe = usb_sndctrlpipe(bfusb->udev, 0);
-+
-+      usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
-+                              0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
-+
-+      return err;
-+}
-+
-+static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+{
-+      const struct firmware *firmware;
-+      char device[16];
-+      struct usb_interface *iface;
-+      struct usb_interface_descriptor *iface_desc;
-+      struct usb_endpoint_descriptor *bulk_out_ep;
-+      struct usb_endpoint_descriptor *bulk_in_ep;
-+      struct hci_dev *hdev;
-+      struct bfusb *bfusb;
-+
-+      BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
-+
-+      /* Check number of endpoints */
-+      iface = &udev->actconfig->interface[0];
-+      iface_desc = &iface->altsetting[0];
-+
-+      if (iface_desc->bNumEndpoints < 2)
-+              return NULL;
-+
-+      bulk_out_ep = &iface_desc->endpoint[0];
-+      bulk_in_ep  = &iface_desc->endpoint[1];
-+
-+      if (!bulk_out_ep || !bulk_in_ep) {
-+              BT_ERR("Bulk endpoints not found");
-+              goto done;
-+      }
-+
-+      /* Initialize control structure and load firmware */
-+      if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
-+              BT_ERR("Can't allocate memory for control structure");
-+              goto done;
-+      }
-+
-+      memset(bfusb, 0, sizeof(struct bfusb));
-+
-+      bfusb->udev = udev;
-+      bfusb->bulk_in_ep    = bulk_in_ep->bEndpointAddress;
-+      bfusb->bulk_out_ep   = bulk_out_ep->bEndpointAddress;
-+      bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
-+
-+      bfusb->lock = RW_LOCK_UNLOCKED;
-+
-+      bfusb->reassembly = NULL;
-+
-+      skb_queue_head_init(&bfusb->transmit_q);
-+      skb_queue_head_init(&bfusb->pending_q);
-+      skb_queue_head_init(&bfusb->completed_q);
-+
-+      snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
-+
-+      if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
-+              BT_ERR("Firmware request failed");
-+              goto error;
-+      }
-+
-+      if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
-+              BT_ERR("Firmware loading failed");
-+              goto release;
-+      }
-+
-+      release_firmware(firmware);
-+
-+      /* Initialize and register HCI device */
-+      hdev = &bfusb->hdev;
-+
-+      hdev->type = HCI_USB;
-+      hdev->driver_data = bfusb;
-+
-+      hdev->open     = bfusb_open;
-+      hdev->close    = bfusb_close;
-+      hdev->flush    = bfusb_flush;
-+      hdev->send     = bfusb_send_frame;
-+      hdev->destruct = bfusb_destruct;
-+      hdev->ioctl    = bfusb_ioctl;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              BT_ERR("Can't register HCI device");
-+              goto error;
-+      }
-+
-+      return bfusb;
-+
-+release:
-+      release_firmware(firmware);
-+
-+error:
-+      kfree(bfusb);
-+
-+done:
-+      return NULL;
-+}
-+
-+static void bfusb_disconnect(struct usb_device *udev, void *ptr)
-+{
-+      struct bfusb *bfusb = (struct bfusb *) ptr;
-+      struct hci_dev *hdev = &bfusb->hdev;
-+
-+      BT_DBG("udev %p ptr %p", udev, ptr);
-+
-+      if (!hdev)
-+              return;
-+
-+      bfusb_close(hdev);
-+
-+      if (hci_unregister_dev(hdev) < 0)
-+              BT_ERR("Can't unregister HCI device %s", hdev->name);
-+}
-+
-+static struct usb_driver bfusb_driver = {
-+      name:           "bfusb",
-+      probe:          bfusb_probe,
-+      disconnect:     bfusb_disconnect,
-+      id_table:       bfusb_table,
-+};
-+
-+static int __init bfusb_init(void)
-+{
-+      int err;
-+
-+      BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
-+      BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+      if ((err = usb_register(&bfusb_driver)) < 0)
-+              BT_ERR("Failed to register BlueFRITZ! USB driver");
-+
-+      return err;
-+}
-+
-+static void __exit bfusb_cleanup(void)
-+{
-+      usb_deregister(&bfusb_driver);
-+}
-+
-+module_init(bfusb_init);
-+module_exit(bfusb_cleanup);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/bluecard_cs.c      2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,1113 @@
-+/*
-+ *
-+ *  Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
-+ *
-+ *  Copyright (C) 2001-2002  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;
-+ *
-+ *  Software distributed under the License is distributed on an "AS
-+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ *  implied. See the License for the specific language governing
-+ *  rights and limitations under the License.
-+ *
-+ *  The initial developer of the original code is David A. Hinds
-+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-+ *
-+ */
-+
-+#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/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+#include <linux/skbuff.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0x86bc;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bluecard_info_t {
-+      dev_link_t link;
-+      dev_node_t node;
-+
-+      struct hci_dev hdev;
-+
-+      spinlock_t lock;                /* For serializing operations */
-+      struct timer_list timer;        /* For LED control */
-+
-+      struct sk_buff_head txq;
-+      unsigned long tx_state;
-+
-+      unsigned long rx_state;
-+      unsigned long rx_count;
-+      struct sk_buff *rx_skb;
-+
-+      unsigned char ctrl_reg;
-+      unsigned long hw_state;         /* Status of the hardware and LED control */
-+} bluecard_info_t;
-+
-+
-+void bluecard_config(dev_link_t *link);
-+void bluecard_release(u_long arg);
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bluecard_cs";
-+
-+dev_link_t *bluecard_attach(void);
-+void bluecard_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE  230400
-+
-+
-+/* Hardware states */
-+#define CARD_READY             1
-+#define CARD_HAS_PCCARD_ID     4
-+#define CARD_HAS_POWER_LED     5
-+#define CARD_HAS_ACTIVITY_LED  6
-+
-+/* Transmit states  */
-+#define XMIT_SENDING         1
-+#define XMIT_WAKEUP          2
-+#define XMIT_BUFFER_NUMBER   5        /* unset = buffer one, set = buffer two */
-+#define XMIT_BUF_ONE_READY   6
-+#define XMIT_BUF_TWO_READY   7
-+#define XMIT_SENDING_READY   8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE   0
-+#define RECV_WAIT_EVENT_HEADER  1
-+#define RECV_WAIT_ACL_HEADER    2
-+#define RECV_WAIT_SCO_HEADER    3
-+#define RECV_WAIT_DATA          4
-+
-+/* Special packet types */
-+#define PKT_BAUD_RATE_57600   0x80
-+#define PKT_BAUD_RATE_115200  0x81
-+#define PKT_BAUD_RATE_230400  0x82
-+#define PKT_BAUD_RATE_460800  0x83
-+
-+
-+/* These are the register offsets */
-+#define REG_COMMAND     0x20
-+#define REG_INTERRUPT   0x21
-+#define REG_CONTROL     0x22
-+#define REG_RX_CONTROL  0x24
-+#define REG_CARD_RESET  0x30
-+#define REG_LED_CTRL    0x30
-+
-+/* REG_COMMAND */
-+#define REG_COMMAND_TX_BUF_ONE  0x01
-+#define REG_COMMAND_TX_BUF_TWO  0x02
-+#define REG_COMMAND_RX_BUF_ONE  0x04
-+#define REG_COMMAND_RX_BUF_TWO  0x08
-+#define REG_COMMAND_RX_WIN_ONE  0x00
-+#define REG_COMMAND_RX_WIN_TWO  0x10
-+
-+/* REG_CONTROL */
-+#define REG_CONTROL_BAUD_RATE_57600   0x00
-+#define REG_CONTROL_BAUD_RATE_115200  0x01
-+#define REG_CONTROL_BAUD_RATE_230400  0x02
-+#define REG_CONTROL_BAUD_RATE_460800  0x03
-+#define REG_CONTROL_RTS               0x04
-+#define REG_CONTROL_BT_ON             0x08
-+#define REG_CONTROL_BT_RESET          0x10
-+#define REG_CONTROL_BT_RES_PU         0x20
-+#define REG_CONTROL_INTERRUPT         0x40
-+#define REG_CONTROL_CARD_RESET        0x80
-+
-+/* REG_RX_CONTROL */
-+#define RTS_LEVEL_SHIFT_BITS  0x02
-+
-+
-+
-+/* ======================== LED handling routines ======================== */
-+
-+
-+void bluecard_activity_led_timeout(u_long arg)
-+{
-+      bluecard_info_t *info = (bluecard_info_t *)arg;
-+      unsigned int iobase = info->link.io.BasePort1;
-+
-+      if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+              /* Disable activity LED */
-+              outb(0x08 | 0x20, iobase + 0x30);
-+      } else {
-+              /* Disable power LED */
-+              outb(0x00, iobase + 0x30);
-+      }
-+}
-+
-+
-+static void bluecard_enable_activity_led(bluecard_info_t *info)
-+{
-+      unsigned int iobase = info->link.io.BasePort1;
-+
-+      if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
-+              /* Enable activity LED */
-+              outb(0x10 | 0x40, iobase + 0x30);
-+
-+              /* Stop the LED after HZ/4 */
-+              mod_timer(&(info->timer), jiffies + HZ / 4);
-+      } else {
-+              /* Enable power LED */
-+              outb(0x08 | 0x20, iobase + 0x30);
-+
-+              /* Stop the LED after HZ/2 */
-+              mod_timer(&(info->timer), jiffies + HZ / 2);
-+      }
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
-+{
-+      int i, actual;
-+
-+      actual = (len > 15) ? 15 : len;
-+
-+      outb_p(actual, iobase + offset);
-+
-+      for (i = 0; i < actual; i++)
-+              outb_p(buf[i], iobase + offset + i + 1);
-+
-+      return actual;
-+}
-+
-+
-+static void bluecard_write_wakeup(bluecard_info_t *info)
-+{
-+      if (!info) {
-+              printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
-+              return;
-+      }
-+
-+      if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+              return;
-+
-+      if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+              set_bit(XMIT_WAKEUP, &(info->tx_state));
-+              return;
-+      }
-+
-+      do {
-+              register unsigned int iobase = info->link.io.BasePort1;
-+              register unsigned int offset;
-+              register unsigned char command;
-+              register unsigned long ready_bit;
-+              register struct sk_buff *skb;
-+              register int len;
-+
-+              clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+              if (!(info->link.state & DEV_PRESENT))
-+                      return;
-+
-+              if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
-+                      if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
-+                              break;
-+                      offset = 0x10;
-+                      command = REG_COMMAND_TX_BUF_TWO;
-+                      ready_bit = XMIT_BUF_TWO_READY;
-+              } else {
-+                      if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
-+                              break;
-+                      offset = 0x00;
-+                      command = REG_COMMAND_TX_BUF_ONE;
-+                      ready_bit = XMIT_BUF_ONE_READY;
-+              }
-+
-+              if (!(skb = skb_dequeue(&(info->txq))))
-+                      break;
-+
-+              if (skb->pkt_type & 0x80) {
-+                      /* Disable RTS */
-+                      info->ctrl_reg |= REG_CONTROL_RTS;
-+                      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+              }
-+
-+              /* Activate LED */
-+              bluecard_enable_activity_led(info);
-+
-+              /* Send frame */
-+              len = bluecard_write(iobase, offset, skb->data, skb->len);
-+
-+              /* Tell the FPGA to send the data */
-+              outb_p(command, iobase + REG_COMMAND);
-+
-+              /* Mark the buffer as dirty */
-+              clear_bit(ready_bit, &(info->tx_state));
-+
-+              if (skb->pkt_type & 0x80) {
-+
-+                      wait_queue_head_t wait;
-+                      unsigned char baud_reg;
-+
-+                      switch (skb->pkt_type) {
-+                      case PKT_BAUD_RATE_460800:
-+                              baud_reg = REG_CONTROL_BAUD_RATE_460800;
-+                              break;
-+                      case PKT_BAUD_RATE_230400:
-+                              baud_reg = REG_CONTROL_BAUD_RATE_230400;
-+                              break;
-+                      case PKT_BAUD_RATE_115200:
-+                              baud_reg = REG_CONTROL_BAUD_RATE_115200;
-+                              break;
-+                      case PKT_BAUD_RATE_57600:
-+                              /* Fall through... */
-+                      default:
-+                              baud_reg = REG_CONTROL_BAUD_RATE_57600;
-+                              break;
-+                      }
-+
-+                      /* Wait until the command reaches the baseband */
-+                      init_waitqueue_head(&wait);
-+                      interruptible_sleep_on_timeout(&wait, HZ / 10);
-+
-+                      /* Set baud on baseband */
-+                      info->ctrl_reg &= ~0x03;
-+                      info->ctrl_reg |= baud_reg;
-+                      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+                      /* Enable RTS */
-+                      info->ctrl_reg &= ~REG_CONTROL_RTS;
-+                      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+                      /* Wait before the next HCI packet can be send */
-+                      interruptible_sleep_on_timeout(&wait, HZ);
-+
-+              }
-+
-+              if (len == skb->len) {
-+                      kfree_skb(skb);
-+              } else {
-+                      skb_pull(skb, len);
-+                      skb_queue_head(&(info->txq), skb);
-+              }
-+
-+              info->hdev.stat.byte_tx += len;
-+
-+              /* Change buffer */
-+              change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
-+
-+      } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+      clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
-+{
-+      int i, n, len;
-+
-+      outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
-+
-+      len = inb(iobase + offset);
-+      n = 0;
-+      i = 1;
-+
-+      while (n < len) {
-+
-+              if (i == 16) {
-+                      outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
-+                      i = 0;
-+              }
-+
-+              buf[n] = inb(iobase + offset + i);
-+
-+              n++;
-+              i++;
-+
-+      }
-+
-+      return len;
-+}
-+
-+
-+static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
-+{
-+      unsigned int iobase;
-+      unsigned char buf[31];
-+      int i, len;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
-+              bluecard_enable_activity_led(info);
-+
-+      len = bluecard_read(iobase, offset, buf, sizeof(buf));
-+
-+      for (i = 0; i < len; i++) {
-+
-+              /* Allocate packet */
-+              if (info->rx_skb == NULL) {
-+                      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+                      info->rx_count = 0;
-+                      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+                              printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+                              return;
-+                      }
-+              }
-+
-+              if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+                      info->rx_skb->dev = (void *)&(info->hdev);
-+                      info->rx_skb->pkt_type = buf[i];
-+
-+                      switch (info->rx_skb->pkt_type) {
-+
-+                      case 0x00:
-+                              /* init packet */
-+                              if (offset != 0x00) {
-+                                      set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+                                      set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+                                      set_bit(XMIT_SENDING_READY, &(info->tx_state));
-+                                      bluecard_write_wakeup(info);
-+                              }
-+
-+                              kfree_skb(info->rx_skb);
-+                              info->rx_skb = NULL;
-+                              break;
-+
-+                      case HCI_EVENT_PKT:
-+                              info->rx_state = RECV_WAIT_EVENT_HEADER;
-+                              info->rx_count = HCI_EVENT_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_ACLDATA_PKT:
-+                              info->rx_state = RECV_WAIT_ACL_HEADER;
-+                              info->rx_count = HCI_ACL_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_SCODATA_PKT:
-+                              info->rx_state = RECV_WAIT_SCO_HEADER;
-+                              info->rx_count = HCI_SCO_HDR_SIZE;
-+                              break;
-+
-+                      default:
-+                              /* unknown packet */
-+                              printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+                              info->hdev.stat.err_rx++;
-+
-+                              kfree_skb(info->rx_skb);
-+                              info->rx_skb = NULL;
-+                              break;
-+
-+                      }
-+
-+              } else {
-+
-+                      *skb_put(info->rx_skb, 1) = buf[i];
-+                      info->rx_count--;
-+
-+                      if (info->rx_count == 0) {
-+
-+                              int dlen;
-+                              hci_event_hdr *eh;
-+                              hci_acl_hdr *ah;
-+                              hci_sco_hdr *sh;
-+
-+                              switch (info->rx_state) {
-+
-+                              case RECV_WAIT_EVENT_HEADER:
-+                                      eh = (hci_event_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = eh->plen;
-+                                      break;
-+
-+                              case RECV_WAIT_ACL_HEADER:
-+                                      ah = (hci_acl_hdr *)(info->rx_skb->data);
-+                                      dlen = __le16_to_cpu(ah->dlen);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_SCO_HEADER:
-+                                      sh = (hci_sco_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = sh->dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_DATA:
-+                                      hci_recv_frame(info->rx_skb);
-+                                      info->rx_skb = NULL;
-+                                      break;
-+
-+                              }
-+
-+                      }
-+
-+              }
-+
-+
-+      }
-+
-+      info->hdev.stat.byte_rx += len;
-+}
-+
-+
-+void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+      bluecard_info_t *info = dev_inst;
-+      unsigned int iobase;
-+      unsigned char reg;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
-+              return;
-+      }
-+
-+      if (!test_bit(CARD_READY, &(info->hw_state)))
-+              return;
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      spin_lock(&(info->lock));
-+
-+      /* Disable interrupt */
-+      info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      reg = inb(iobase + REG_INTERRUPT);
-+
-+      if ((reg != 0x00) && (reg != 0xff)) {
-+
-+              if (reg & 0x04) {
-+                      bluecard_receive(info, 0x00);
-+                      outb(0x04, iobase + REG_INTERRUPT);
-+                      outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+              }
-+
-+              if (reg & 0x08) {
-+                      bluecard_receive(info, 0x10);
-+                      outb(0x08, iobase + REG_INTERRUPT);
-+                      outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+              }
-+
-+              if (reg & 0x01) {
-+                      set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
-+                      outb(0x01, iobase + REG_INTERRUPT);
-+                      bluecard_write_wakeup(info);
-+              }
-+
-+              if (reg & 0x02) {
-+                      set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
-+                      outb(0x02, iobase + REG_INTERRUPT);
-+                      bluecard_write_wakeup(info);
-+              }
-+
-+      }
-+
-+      /* Enable interrupt */
-+      info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== Device specific HCI commands ======================== */
-+
-+
-+static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
-+{
-+      bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+      struct sk_buff *skb;
-+
-+      /* Ericsson baud rate command */
-+      unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
-+
-+      if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+              printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
-+              return -1;
-+      }
-+
-+      switch (baud) {
-+      case 460800:
-+              cmd[4] = 0x00;
-+              skb->pkt_type = PKT_BAUD_RATE_460800;
-+              break;
-+      case 230400:
-+              cmd[4] = 0x01;
-+              skb->pkt_type = PKT_BAUD_RATE_230400;
-+              break;
-+      case 115200:
-+              cmd[4] = 0x02;
-+              skb->pkt_type = PKT_BAUD_RATE_115200;
-+              break;
-+      case 57600:
-+              /* Fall through... */
-+      default:
-+              cmd[4] = 0x03;
-+              skb->pkt_type = PKT_BAUD_RATE_57600;
-+              break;
-+      }
-+
-+      memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
-+
-+      skb_queue_tail(&(info->txq), skb);
-+
-+      bluecard_write_wakeup(info);
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bluecard_hci_flush(struct hci_dev *hdev)
-+{
-+      bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+
-+      /* Drop TX queue */
-+      skb_queue_purge(&(info->txq));
-+
-+      return 0;
-+}
-+
-+
-+static int bluecard_hci_open(struct hci_dev *hdev)
-+{
-+      bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+      unsigned int iobase = info->link.io.BasePort1;
-+
-+      bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
-+
-+      if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
-+              return 0;
-+
-+      /* Enable LED */
-+      outb(0x08 | 0x20, iobase + 0x30);
-+
-+      return 0;
-+}
-+
-+
-+static int bluecard_hci_close(struct hci_dev *hdev)
-+{
-+      bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
-+      unsigned int iobase = info->link.io.BasePort1;
-+
-+      if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+              return 0;
-+
-+      bluecard_hci_flush(hdev);
-+
-+      /* Disable LED */
-+      outb(0x00, iobase + 0x30);
-+
-+      return 0;
-+}
-+
-+
-+static int bluecard_hci_send_frame(struct sk_buff *skb)
-+{
-+      bluecard_info_t *info;
-+      struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+      if (!hdev) {
-+              printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
-+              return -ENODEV;
-+      }
-+
-+      info = (bluecard_info_t *)(hdev->driver_data);
-+
-+      switch (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;
-+      };
-+
-+      /* Prepend skb with frame type */
-+      memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+      skb_queue_tail(&(info->txq), skb);
-+
-+      bluecard_write_wakeup(info);
-+
-+      return 0;
-+}
-+
-+
-+static void bluecard_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+      return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int bluecard_open(bluecard_info_t *info)
-+{
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev;
-+      unsigned char id;
-+
-+      spin_lock_init(&(info->lock));
-+
-+      init_timer(&(info->timer));
-+      info->timer.function = &bluecard_activity_led_timeout;
-+      info->timer.data = (u_long)info;
-+
-+      skb_queue_head_init(&(info->txq));
-+
-+      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+      info->rx_count = 0;
-+      info->rx_skb = NULL;
-+
-+      id = inb(iobase + 0x30);
-+
-+      if ((id & 0x0f) == 0x02)
-+              set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
-+
-+      if (id & 0x10)
-+              set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
-+
-+      if (id & 0x20)
-+              set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
-+
-+      /* Reset card */
-+      info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      /* Turn FPGA off */
-+      outb(0x80, iobase + 0x30);
-+
-+      /* Wait some time */
-+      set_current_state(TASK_INTERRUPTIBLE);
-+      schedule_timeout(HZ / 100);
-+
-+      /* Turn FPGA on */
-+      outb(0x00, iobase + 0x30);
-+
-+      /* Activate card */
-+      info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      /* Enable interrupt */
-+      outb(0xff, iobase + REG_INTERRUPT);
-+      info->ctrl_reg |= REG_CONTROL_INTERRUPT;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      /* Start the RX buffers */
-+      outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
-+      outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
-+
-+      /* Signal that the hardware is ready */
-+      set_bit(CARD_READY, &(info->hw_state));
-+
-+      /* Drop TX queue */
-+      skb_queue_purge(&(info->txq));
-+
-+      /* Control the point at which RTS is enabled */
-+      outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
-+
-+      /* Timeout before it is safe to send the first HCI packet */
-+      set_current_state(TASK_INTERRUPTIBLE);
-+      schedule_timeout((HZ * 5) / 4);         // or set it to 3/2
-+
-+
-+      /* Initialize and register HCI device */
-+
-+      hdev = &(info->hdev);
-+
-+      hdev->type = HCI_PCCARD;
-+      hdev->driver_data = info;
-+
-+      hdev->open = bluecard_hci_open;
-+      hdev->close = bluecard_hci_close;
-+      hdev->flush = bluecard_hci_flush;
-+      hdev->send = bluecard_hci_send_frame;
-+      hdev->destruct = bluecard_hci_destruct;
-+      hdev->ioctl = bluecard_hci_ioctl;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
-+              return -ENODEV;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+int bluecard_close(bluecard_info_t *info)
-+{
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev = &(info->hdev);
-+
-+      bluecard_hci_close(hdev);
-+
-+      clear_bit(CARD_READY, &(info->hw_state));
-+
-+      /* Reset card */
-+      info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
-+      outb(info->ctrl_reg, iobase + REG_CONTROL);
-+
-+      /* Turn FPGA off */
-+      outb(0x80, iobase + 0x30);
-+
-+      if (hci_unregister_dev(hdev) < 0)
-+              printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+      error_info_t err = { func, ret };
-+
-+      CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bluecard_attach(void)
-+{
-+      bluecard_info_t *info;
-+      client_reg_t client_reg;
-+      dev_link_t *link;
-+      int i, ret;
-+
-+      /* Create new info device */
-+      info = kmalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return NULL;
-+      memset(info, 0, sizeof(*info));
-+
-+      link = &info->link;
-+      link->priv = info;
-+
-+      link->release.function = &bluecard_release;
-+      link->release.data = (u_long)link;
-+      link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+      link->io.NumPorts1 = 8;
-+      link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+      link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+      if (irq_list[0] == -1)
-+              link->irq.IRQInfo2 = irq_mask;
-+      else
-+              for (i = 0; i < 4; i++)
-+                      link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+      link->irq.Handler = bluecard_interrupt;
-+      link->irq.Instance = info;
-+
-+      link->conf.Attributes = CONF_ENABLE_IRQ;
-+      link->conf.Vcc = 50;
-+      link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+      /* Register with Card Services */
-+      link->next = dev_list;
-+      dev_list = link;
-+      client_reg.dev_info = &dev_info;
-+      client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+      client_reg.EventMask =
-+              CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+              CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+              CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+      client_reg.event_handler = &bluecard_event;
-+      client_reg.Version = 0x0210;
-+      client_reg.event_callback_args.client_data = link;
-+
-+      ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+      if (ret != CS_SUCCESS) {
-+              cs_error(link->handle, RegisterClient, ret);
-+              bluecard_detach(link);
-+              return NULL;
-+      }
-+
-+      return link;
-+}
-+
-+
-+void bluecard_detach(dev_link_t *link)
-+{
-+      bluecard_info_t *info = link->priv;
-+      dev_link_t **linkp;
-+      int ret;
-+
-+      /* Locate device structure */
-+      for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+              if (*linkp == link)
-+                      break;
-+
-+      if (*linkp == NULL)
-+              return;
-+
-+      del_timer(&link->release);
-+      if (link->state & DEV_CONFIG)
-+              bluecard_release((u_long)link);
-+
-+      if (link->handle) {
-+              ret = CardServices(DeregisterClient, link->handle);
-+              if (ret != CS_SUCCESS)
-+                      cs_error(link->handle, DeregisterClient, ret);
-+      }
-+
-+      /* Unlink device structure, free bits */
-+      *linkp = link->next;
-+
-+      kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+      int i;
-+
-+      i = CardServices(fn, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return CS_NO_MORE_ITEMS;
-+
-+      i = CardServices(GetTupleData, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return i;
-+
-+      return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bluecard_config(dev_link_t *link)
-+{
-+      client_handle_t handle = link->handle;
-+      bluecard_info_t *info = link->priv;
-+      tuple_t tuple;
-+      u_short buf[256];
-+      cisparse_t parse;
-+      config_info_t config;
-+      int i, n, last_ret, last_fn;
-+
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+
-+      /* Get configuration register information */
-+      tuple.DesiredTuple = CISTPL_CONFIG;
-+      last_ret = first_tuple(handle, &tuple, &parse);
-+      if (last_ret != CS_SUCCESS) {
-+              last_fn = ParseTuple;
-+              goto cs_failed;
-+      }
-+      link->conf.ConfigBase = parse.config.base;
-+      link->conf.Present = parse.config.rmask[0];
-+
-+      /* Configure card */
-+      link->state |= DEV_CONFIG;
-+      i = CardServices(GetConfigurationInfo, handle, &config);
-+      link->conf.Vcc = config.Vcc;
-+
-+      link->conf.ConfigIndex = 0x20;
-+      link->io.NumPorts1 = 64;
-+      link->io.IOAddrLines = 6;
-+
-+      for (n = 0; n < 0x400; n += 0x40) {
-+              link->io.BasePort1 = n ^ 0x300;
-+              i = CardServices(RequestIO, link->handle, &link->io);
-+              if (i == CS_SUCCESS)
-+                      break;
-+      }
-+
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIO, i);
-+              goto failed;
-+      }
-+
-+      i = CardServices(RequestIRQ, link->handle, &link->irq);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIRQ, i);
-+              link->irq.AssignedIRQ = 0;
-+      }
-+
-+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestConfiguration, i);
-+              goto failed;
-+      }
-+
-+      MOD_INC_USE_COUNT;
-+
-+      if (bluecard_open(info) != 0)
-+              goto failed;
-+
-+      strcpy(info->node.dev_name, info->hdev.name);
-+      link->dev = &info->node;
-+      link->state &= ~DEV_CONFIG_PENDING;
-+
-+      return;
-+
-+cs_failed:
-+      cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+      bluecard_release((u_long)link);
-+}
-+
-+
-+void bluecard_release(u_long arg)
-+{
-+      dev_link_t *link = (dev_link_t *)arg;
-+      bluecard_info_t *info = link->priv;
-+
-+      if (link->state & DEV_PRESENT)
-+              bluecard_close(info);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      link->dev = NULL;
-+
-+      CardServices(ReleaseConfiguration, link->handle);
-+      CardServices(ReleaseIO, link->handle, &link->io);
-+      CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+      link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bluecard_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+      dev_link_t *link = args->client_data;
-+      bluecard_info_t *info = link->priv;
-+
-+      switch (event) {
-+      case CS_EVENT_CARD_REMOVAL:
-+              link->state &= ~DEV_PRESENT;
-+              if (link->state & DEV_CONFIG) {
-+                      bluecard_close(info);
-+                      mod_timer(&link->release, jiffies + HZ / 20);
-+              }
-+              break;
-+      case CS_EVENT_CARD_INSERTION:
-+              link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+              bluecard_config(link);
-+              break;
-+      case CS_EVENT_PM_SUSPEND:
-+              link->state |= DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_RESET_PHYSICAL:
-+              if (link->state & DEV_CONFIG)
-+                      CardServices(ReleaseConfiguration, link->handle);
-+              break;
-+      case CS_EVENT_PM_RESUME:
-+              link->state &= ~DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_CARD_RESET:
-+              if (DEV_OK(link))
-+                      CardServices(RequestConfiguration, link->handle, &link->conf);
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bluecard_cs(void)
-+{
-+      servinfo_t serv;
-+      int err;
-+
-+      CardServices(GetCardServicesInfo, &serv);
-+      if (serv.Revision != CS_RELEASE_CODE) {
-+              printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
-+              return -1;
-+      }
-+
-+      err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
-+
-+      return err;
-+}
-+
-+
-+void __exit exit_bluecard_cs(void)
-+{
-+      unregister_pccard_driver(&dev_info);
-+
-+      while (dev_list != NULL)
-+              bluecard_detach(dev_list);
-+}
-+
-+
-+module_init(init_bluecard_cs);
-+module_exit(exit_bluecard_cs);
-+
-+EXPORT_NO_SYMBOLS;
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/bt3c_cs.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,946 @@
-+/*
-+ *
-+ *  Driver for the 3Com Bluetooth PCMCIA card
-+ *
-+ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
-+ *                           Jose Orlando Pereira <jop@di.uminho.pt>
-+ *
-+ *
-+ *  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;
-+ *
-+ *  Software distributed under the License is distributed on an "AS
-+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ *  implied. See the License for the specific language governing
-+ *  rights and limitations under the License.
-+ *
-+ *  The initial developer of the original code is David A. Hinds
-+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/kernel.h>
-+#include <linux/kmod.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/unistd.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
-+MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct bt3c_info_t {
-+      dev_link_t link;
-+      dev_node_t node;
-+
-+      struct hci_dev hdev;
-+
-+      spinlock_t lock;                /* For serializing operations */
-+
-+      struct sk_buff_head txq;
-+      unsigned long tx_state;
-+
-+      unsigned long rx_state;
-+      unsigned long rx_count;
-+      struct sk_buff *rx_skb;
-+} bt3c_info_t;
-+
-+
-+void bt3c_config(dev_link_t *link);
-+void bt3c_release(u_long arg);
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "bt3c_cs";
-+
-+dev_link_t *bt3c_attach(void);
-+void bt3c_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states  */
-+#define XMIT_SENDING  1
-+#define XMIT_WAKEUP   2
-+#define XMIT_WAITING  8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE   0
-+#define RECV_WAIT_EVENT_HEADER  1
-+#define RECV_WAIT_ACL_HEADER    2
-+#define RECV_WAIT_SCO_HEADER    3
-+#define RECV_WAIT_DATA          4
-+
-+
-+
-+/* ======================== Special I/O functions ======================== */
-+
-+
-+#define DATA_L   0
-+#define DATA_H   1
-+#define ADDR_L   2
-+#define ADDR_H   3
-+#define CONTROL  4
-+
-+
-+inline void bt3c_address(unsigned int iobase, unsigned short addr)
-+{
-+      outb(addr & 0xff, iobase + ADDR_L);
-+      outb((addr >> 8) & 0xff, iobase + ADDR_H);
-+}
-+
-+
-+inline void bt3c_put(unsigned int iobase, unsigned short value)
-+{
-+      outb(value & 0xff, iobase + DATA_L);
-+      outb((value >> 8) & 0xff, iobase + DATA_H);
-+}
-+
-+
-+inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
-+{
-+      bt3c_address(iobase, addr);
-+      bt3c_put(iobase, value);
-+}
-+
-+
-+inline unsigned short bt3c_get(unsigned int iobase)
-+{
-+      unsigned short value = inb(iobase + DATA_L);
-+
-+      value |= inb(iobase + DATA_H) << 8;
-+
-+      return value;
-+}
-+
-+
-+inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
-+{
-+      bt3c_address(iobase, addr);
-+
-+      return bt3c_get(iobase);
-+}
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+      int actual = 0;
-+
-+      bt3c_address(iobase, 0x7080);
-+
-+      /* Fill FIFO with current frame */
-+      while (actual < len) {
-+              /* Transmit next byte */
-+              bt3c_put(iobase, buf[actual]);
-+              actual++;
-+      }
-+
-+      bt3c_io_write(iobase, 0x7005, actual);
-+
-+      return actual;
-+}
-+
-+
-+static void bt3c_write_wakeup(bt3c_info_t *info, int from)
-+{
-+      unsigned long flags;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
-+              return;
-+      }
-+
-+      if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
-+              return;
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      do {
-+              register unsigned int iobase = info->link.io.BasePort1;
-+              register struct sk_buff *skb;
-+              register int len;
-+
-+              if (!(info->link.state & DEV_PRESENT))
-+                      break;
-+
-+
-+              if (!(skb = skb_dequeue(&(info->txq)))) {
-+                      clear_bit(XMIT_SENDING, &(info->tx_state));
-+                      break;
-+              }
-+
-+              /* Send frame */
-+              len = bt3c_write(iobase, 256, skb->data, skb->len);
-+
-+              if (len != skb->len) {
-+                      printk(KERN_WARNING "bt3c_cs: very strange\n");
-+              }
-+
-+              kfree_skb(skb);
-+
-+              info->hdev.stat.byte_tx += len;
-+
-+      } while (0);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+static void bt3c_receive(bt3c_info_t *info)
-+{
-+      unsigned int iobase;
-+      int size = 0, avail;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      avail = bt3c_read(iobase, 0x7006);
-+      //printk("bt3c_cs: receiving %d bytes\n", avail);
-+
-+      bt3c_address(iobase, 0x7480);
-+      while (size < avail) {
-+              size++;
-+              info->hdev.stat.byte_rx++;
-+
-+              /* Allocate packet */
-+              if (info->rx_skb == NULL) {
-+                      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+                      info->rx_count = 0;
-+                      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+                              printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
-+                              return;
-+                      }
-+              }
-+
-+
-+              if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+                      info->rx_skb->dev = (void *)&(info->hdev);
-+                      info->rx_skb->pkt_type = inb(iobase + DATA_L);
-+                      inb(iobase + DATA_H);
-+                      //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
-+
-+                      switch (info->rx_skb->pkt_type) {
-+
-+                      case HCI_EVENT_PKT:
-+                              info->rx_state = RECV_WAIT_EVENT_HEADER;
-+                              info->rx_count = HCI_EVENT_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_ACLDATA_PKT:
-+                              info->rx_state = RECV_WAIT_ACL_HEADER;
-+                              info->rx_count = HCI_ACL_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_SCODATA_PKT:
-+                              info->rx_state = RECV_WAIT_SCO_HEADER;
-+                              info->rx_count = HCI_SCO_HDR_SIZE;
-+                              break;
-+
-+                      default:
-+                              /* Unknown packet */
-+                              printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+                              info->hdev.stat.err_rx++;
-+                              clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+                              kfree_skb(info->rx_skb);
-+                              info->rx_skb = NULL;
-+                              break;
-+
-+                      }
-+
-+              } else {
-+
-+                      __u8 x = inb(iobase + DATA_L);
-+
-+                      *skb_put(info->rx_skb, 1) = x;
-+                      inb(iobase + DATA_H);
-+                      info->rx_count--;
-+
-+                      if (info->rx_count == 0) {
-+
-+                              int dlen;
-+                              hci_event_hdr *eh;
-+                              hci_acl_hdr *ah;
-+                              hci_sco_hdr *sh;
-+
-+                              switch (info->rx_state) {
-+
-+                              case RECV_WAIT_EVENT_HEADER:
-+                                      eh = (hci_event_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = eh->plen;
-+                                      break;
-+
-+                              case RECV_WAIT_ACL_HEADER:
-+                                      ah = (hci_acl_hdr *)(info->rx_skb->data);
-+                                      dlen = __le16_to_cpu(ah->dlen);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_SCO_HEADER:
-+                                      sh = (hci_sco_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = sh->dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_DATA:
-+                                      hci_recv_frame(info->rx_skb);
-+                                      info->rx_skb = NULL;
-+                                      break;
-+
-+                              }
-+
-+                      }
-+
-+              }
-+
-+      }
-+
-+      bt3c_io_write(iobase, 0x7006, 0x0000);
-+}
-+
-+
-+void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+      bt3c_info_t *info = dev_inst;
-+      unsigned int iobase;
-+      int iir;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      spin_lock(&(info->lock));
-+
-+      iir = inb(iobase + CONTROL);
-+      if (iir & 0x80) {
-+              int stat = bt3c_read(iobase, 0x7001);
-+
-+              if ((stat & 0xff) == 0x7f) {
-+                      printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
-+              } else if ((stat & 0xff) != 0xff) {
-+                      if (stat & 0x0020) {
-+                              int stat = bt3c_read(iobase, 0x7002) & 0x10;
-+                              printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
-+                      }
-+                      if (stat & 0x0001)
-+                              bt3c_receive(info);
-+                      if (stat & 0x0002) {
-+                              //printk("bt3c_cs: ACK %04x\n", stat);
-+                              clear_bit(XMIT_SENDING, &(info->tx_state));
-+                              bt3c_write_wakeup(info, 1);
-+                      }
-+
-+                      bt3c_io_write(iobase, 0x7001, 0x0000);
-+
-+                      outb(iir, iobase + CONTROL);
-+              }
-+      }
-+
-+      spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int bt3c_hci_flush(struct hci_dev *hdev)
-+{
-+      bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
-+
-+      /* Drop TX queue */
-+      skb_queue_purge(&(info->txq));
-+
-+      return 0;
-+}
-+
-+
-+static int bt3c_hci_open(struct hci_dev *hdev)
-+{
-+      set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+      return 0;
-+}
-+
-+
-+static int bt3c_hci_close(struct hci_dev *hdev)
-+{
-+      if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+              return 0;
-+
-+      bt3c_hci_flush(hdev);
-+
-+      return 0;
-+}
-+
-+
-+static int bt3c_hci_send_frame(struct sk_buff *skb)
-+{
-+      bt3c_info_t *info;
-+      struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+      if (!hdev) {
-+              printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
-+              return -ENODEV;
-+      }
-+
-+      info = (bt3c_info_t *) (hdev->driver_data);
-+
-+      switch (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;
-+      };
-+
-+      /* Prepend skb with frame type */
-+      memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+      skb_queue_tail(&(info->txq), skb);
-+
-+      bt3c_write_wakeup(info, 0);
-+
-+      return 0;
-+}
-+
-+
-+static void bt3c_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+      return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== User mode firmware loader ======================== */
-+
-+
-+#define FW_LOADER  "/sbin/bluefw"
-+static int errno;
-+
-+
-+static int bt3c_fw_loader_exec(void *dev)
-+{
-+      char *argv[] = { FW_LOADER, "pccard", dev, NULL };
-+      char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-+      int err;
-+
-+      err = exec_usermodehelper(FW_LOADER, argv, envp);
-+      if (err)
-+              printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
-+
-+      return err;
-+}
-+
-+
-+static int bt3c_firmware_load(bt3c_info_t *info)
-+{
-+      sigset_t tmpsig;
-+      char dev[16];
-+      pid_t pid;
-+      int result;
-+
-+      /* Check if root fs is mounted */
-+      if (!current->fs->root) {
-+              printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
-+              return -EPERM;
-+      }
-+
-+      sprintf(dev, "%04x", info->link.io.BasePort1);
-+
-+      pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
-+      if (pid < 0) {
-+              printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
-+              return pid;
-+      }
-+
-+      /* Block signals, everything but SIGKILL/SIGSTOP */
-+      spin_lock_irq(&current->sigmask_lock);
-+      tmpsig = current->blocked;
-+      siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-+      recalc_sigpending(current);
-+      spin_unlock_irq(&current->sigmask_lock);
-+
-+      result = waitpid(pid, NULL, __WCLONE);
-+
-+      /* Allow signals again */
-+      spin_lock_irq(&current->sigmask_lock);
-+      current->blocked = tmpsig;
-+      recalc_sigpending(current);
-+      spin_unlock_irq(&current->sigmask_lock);
-+
-+      if (result != pid) {
-+              printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
-+              return -result;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int bt3c_open(bt3c_info_t *info)
-+{
-+      struct hci_dev *hdev;
-+      int err;
-+
-+      spin_lock_init(&(info->lock));
-+
-+      skb_queue_head_init(&(info->txq));
-+
-+      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+      info->rx_count = 0;
-+      info->rx_skb = NULL;
-+
-+      /* Load firmware */
-+
-+      if ((err = bt3c_firmware_load(info)) < 0)
-+              return err;
-+
-+      /* Timeout before it is safe to send the first HCI packet */
-+
-+      set_current_state(TASK_INTERRUPTIBLE);
-+      schedule_timeout(HZ);
-+
-+
-+      /* Initialize and register HCI device */
-+
-+      hdev = &(info->hdev);
-+
-+      hdev->type = HCI_PCCARD;
-+      hdev->driver_data = info;
-+
-+      hdev->open = bt3c_hci_open;
-+      hdev->close = bt3c_hci_close;
-+      hdev->flush = bt3c_hci_flush;
-+      hdev->send = bt3c_hci_send_frame;
-+      hdev->destruct = bt3c_hci_destruct;
-+      hdev->ioctl = bt3c_hci_ioctl;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
-+              return -ENODEV;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+int bt3c_close(bt3c_info_t *info)
-+{
-+      struct hci_dev *hdev = &(info->hdev);
-+
-+      bt3c_hci_close(hdev);
-+
-+      if (hci_unregister_dev(hdev) < 0)
-+              printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+      error_info_t err = { func, ret };
-+
-+      CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *bt3c_attach(void)
-+{
-+      bt3c_info_t *info;
-+      client_reg_t client_reg;
-+      dev_link_t *link;
-+      int i, ret;
-+
-+      /* Create new info device */
-+      info = kmalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return NULL;
-+      memset(info, 0, sizeof(*info));
-+
-+      link = &info->link;
-+      link->priv = info;
-+
-+      link->release.function = &bt3c_release;
-+      link->release.data = (u_long)link;
-+      link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+      link->io.NumPorts1 = 8;
-+      link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+      link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+      if (irq_list[0] == -1)
-+              link->irq.IRQInfo2 = irq_mask;
-+      else
-+              for (i = 0; i < 4; i++)
-+                      link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+      link->irq.Handler = bt3c_interrupt;
-+      link->irq.Instance = info;
-+
-+      link->conf.Attributes = CONF_ENABLE_IRQ;
-+      link->conf.Vcc = 50;
-+      link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+      /* Register with Card Services */
-+      link->next = dev_list;
-+      dev_list = link;
-+      client_reg.dev_info = &dev_info;
-+      client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+      client_reg.EventMask =
-+          CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+          CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+          CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+      client_reg.event_handler = &bt3c_event;
-+      client_reg.Version = 0x0210;
-+      client_reg.event_callback_args.client_data = link;
-+
-+      ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+      if (ret != CS_SUCCESS) {
-+              cs_error(link->handle, RegisterClient, ret);
-+              bt3c_detach(link);
-+              return NULL;
-+      }
-+
-+      return link;
-+}
-+
-+
-+void bt3c_detach(dev_link_t *link)
-+{
-+      bt3c_info_t *info = link->priv;
-+      dev_link_t **linkp;
-+      int ret;
-+
-+      /* Locate device structure */
-+      for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+              if (*linkp == link)
-+                      break;
-+
-+      if (*linkp == NULL)
-+              return;
-+
-+      del_timer(&link->release);
-+
-+      if (link->state & DEV_CONFIG)
-+              bt3c_release((u_long)link);
-+
-+      if (link->handle) {
-+              ret = CardServices(DeregisterClient, link->handle);
-+              if (ret != CS_SUCCESS)
-+                      cs_error(link->handle, DeregisterClient, ret);
-+      }
-+
-+      /* Unlink device structure, free bits */
-+      *linkp = link->next;
-+
-+      kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+      int i;
-+
-+      i = CardServices(fn, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return CS_NO_MORE_ITEMS;
-+
-+      i = CardServices(GetTupleData, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return i;
-+
-+      return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void bt3c_config(dev_link_t *link)
-+{
-+      static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+      client_handle_t handle = link->handle;
-+      bt3c_info_t *info = link->priv;
-+      tuple_t tuple;
-+      u_short buf[256];
-+      cisparse_t parse;
-+      cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+      config_info_t config;
-+      int i, j, try, last_ret, last_fn;
-+
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+
-+      /* Get configuration register information */
-+      tuple.DesiredTuple = CISTPL_CONFIG;
-+      last_ret = first_tuple(handle, &tuple, &parse);
-+      if (last_ret != CS_SUCCESS) {
-+              last_fn = ParseTuple;
-+              goto cs_failed;
-+      }
-+      link->conf.ConfigBase = parse.config.base;
-+      link->conf.Present = parse.config.rmask[0];
-+
-+      /* Configure card */
-+      link->state |= DEV_CONFIG;
-+      i = CardServices(GetConfigurationInfo, handle, &config);
-+      link->conf.Vcc = config.Vcc;
-+
-+      /* First pass: look for a config entry that looks normal. */
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+      tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+      /* Two tries: without IO aliases, then with aliases */
-+      for (try = 0; try < 2; try++) {
-+              i = first_tuple(handle, &tuple, &parse);
-+              while (i != CS_NO_MORE_ITEMS) {
-+                      if (i != CS_SUCCESS)
-+                              goto next_entry;
-+                      if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+                              link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+                      if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+                              link->conf.ConfigIndex = cf->index;
-+                              link->io.BasePort1 = cf->io.win[0].base;
-+                              link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+                              i = CardServices(RequestIO, link->handle, &link->io);
-+                              if (i == CS_SUCCESS)
-+                                      goto found_port;
-+                      }
-+next_entry:
-+                      i = next_tuple(handle, &tuple, &parse);
-+              }
-+      }
-+
-+      /* Second pass: try to find an entry that isn't picky about
-+         its base address, then try to grab any standard serial port
-+         address, and finally try to get any free port. */
-+      i = first_tuple(handle, &tuple, &parse);
-+      while (i != CS_NO_MORE_ITEMS) {
-+              if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+                      link->conf.ConfigIndex = cf->index;
-+                      for (j = 0; j < 5; j++) {
-+                              link->io.BasePort1 = base[j];
-+                              link->io.IOAddrLines = base[j] ? 16 : 3;
-+                              i = CardServices(RequestIO, link->handle, &link->io);
-+                              if (i == CS_SUCCESS)
-+                                      goto found_port;
-+                      }
-+              }
-+              i = next_tuple(handle, &tuple, &parse);
-+      }
-+
-+found_port:
-+      if (i != CS_SUCCESS) {
-+              printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
-+              cs_error(link->handle, RequestIO, i);
-+              goto failed;
-+      }
-+
-+      i = CardServices(RequestIRQ, link->handle, &link->irq);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIRQ, i);
-+              link->irq.AssignedIRQ = 0;
-+      }
-+
-+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestConfiguration, i);
-+              goto failed;
-+      }
-+
-+      MOD_INC_USE_COUNT;
-+
-+      if (bt3c_open(info) != 0)
-+              goto failed;
-+
-+      strcpy(info->node.dev_name, info->hdev.name);
-+      link->dev = &info->node;
-+      link->state &= ~DEV_CONFIG_PENDING;
-+
-+      return;
-+
-+cs_failed:
-+      cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+      bt3c_release((u_long)link);
-+}
-+
-+
-+void bt3c_release(u_long arg)
-+{
-+      dev_link_t *link = (dev_link_t *)arg;
-+      bt3c_info_t *info = link->priv;
-+
-+      if (link->state & DEV_PRESENT)
-+              bt3c_close(info);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      link->dev = NULL;
-+
-+      CardServices(ReleaseConfiguration, link->handle);
-+      CardServices(ReleaseIO, link->handle, &link->io);
-+      CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+      link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int bt3c_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+      dev_link_t *link = args->client_data;
-+      bt3c_info_t *info = link->priv;
-+
-+      switch (event) {
-+      case CS_EVENT_CARD_REMOVAL:
-+              link->state &= ~DEV_PRESENT;
-+              if (link->state & DEV_CONFIG) {
-+                      bt3c_close(info);
-+                      mod_timer(&link->release, jiffies + HZ / 20);
-+              }
-+              break;
-+      case CS_EVENT_CARD_INSERTION:
-+              link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+              bt3c_config(link);
-+              break;
-+      case CS_EVENT_PM_SUSPEND:
-+              link->state |= DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_RESET_PHYSICAL:
-+              if (link->state & DEV_CONFIG)
-+                      CardServices(ReleaseConfiguration, link->handle);
-+              break;
-+      case CS_EVENT_PM_RESUME:
-+              link->state &= ~DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_CARD_RESET:
-+              if (DEV_OK(link))
-+                      CardServices(RequestConfiguration, link->handle, &link->conf);
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_bt3c_cs(void)
-+{
-+      servinfo_t serv;
-+      int err;
-+
-+      CardServices(GetCardServicesInfo, &serv);
-+      if (serv.Revision != CS_RELEASE_CODE) {
-+              printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
-+              return -1;
-+      }
-+
-+      err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
-+
-+      return err;
-+}
-+
-+
-+void __exit exit_bt3c_cs(void)
-+{
-+      unregister_pccard_driver(&dev_info);
-+
-+      while (dev_list != NULL)
-+              bt3c_detach(dev_list);
-+}
-+
-+
-+module_init(init_bt3c_cs);
-+module_exit(exit_bt3c_cs);
-+
-+EXPORT_NO_SYMBOLS;
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/btuart_cs.c        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,906 @@
-+/*
-+ *
-+ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
-+ *
-+ *  Copyright (C) 2001-2002  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;
-+ *
-+ *  Software distributed under the License is distributed on an "AS
-+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ *  implied. See the License for the specific language governing
-+ *  rights and limitations under the License.
-+ *
-+ *  The initial developer of the original code is David A. Hinds
-+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-+ *
-+ */
-+
-+#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/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct btuart_info_t {
-+      dev_link_t link;
-+      dev_node_t node;
-+
-+      struct hci_dev hdev;
-+
-+      spinlock_t lock;        /* For serializing operations */
-+
-+      struct sk_buff_head txq;
-+      unsigned long tx_state;
-+
-+      unsigned long rx_state;
-+      unsigned long rx_count;
-+      struct sk_buff *rx_skb;
-+} btuart_info_t;
-+
-+
-+void btuart_config(dev_link_t *link);
-+void btuart_release(u_long arg);
-+int btuart_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "btuart_cs";
-+
-+dev_link_t *btuart_attach(void);
-+void btuart_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Maximum baud rate */
-+#define SPEED_MAX  115200
-+
-+/* Default baud rate: 57600, 115200, 230400 or 460800 */
-+#define DEFAULT_BAUD_RATE  115200
-+
-+
-+/* Transmit states  */
-+#define XMIT_SENDING  1
-+#define XMIT_WAKEUP   2
-+#define XMIT_WAITING  8
-+
-+/* Receiver states */
-+#define RECV_WAIT_PACKET_TYPE 0
-+#define RECV_WAIT_EVENT_HEADER        1
-+#define RECV_WAIT_ACL_HEADER  2
-+#define RECV_WAIT_SCO_HEADER  3
-+#define RECV_WAIT_DATA                4
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+      int actual = 0;
-+
-+      /* Tx FIFO should be empty */
-+      if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+              return 0;
-+
-+      /* Fill FIFO with current frame */
-+      while ((fifo_size-- > 0) && (actual < len)) {
-+              /* Transmit next byte */
-+              outb(buf[actual], iobase + UART_TX);
-+              actual++;
-+      }
-+
-+      return actual;
-+}
-+
-+
-+static void btuart_write_wakeup(btuart_info_t *info)
-+{
-+      if (!info) {
-+              printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
-+              return;
-+      }
-+
-+      if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+              set_bit(XMIT_WAKEUP, &(info->tx_state));
-+              return;
-+      }
-+
-+      do {
-+              register unsigned int iobase = info->link.io.BasePort1;
-+              register struct sk_buff *skb;
-+              register int len;
-+
-+              clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+              if (!(info->link.state & DEV_PRESENT))
-+                      return;
-+
-+              if (!(skb = skb_dequeue(&(info->txq))))
-+                      break;
-+
-+              /* Send frame */
-+              len = btuart_write(iobase, 16, skb->data, skb->len);
-+              set_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+              if (len == skb->len) {
-+                      kfree_skb(skb);
-+              } else {
-+                      skb_pull(skb, len);
-+                      skb_queue_head(&(info->txq), skb);
-+              }
-+
-+              info->hdev.stat.byte_tx += len;
-+
-+      } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+      clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void btuart_receive(btuart_info_t *info)
-+{
-+      unsigned int iobase;
-+      int boguscount = 0;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      do {
-+              info->hdev.stat.byte_rx++;
-+
-+              /* Allocate packet */
-+              if (info->rx_skb == NULL) {
-+                      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+                      info->rx_count = 0;
-+                      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+                              printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
-+                              return;
-+                      }
-+              }
-+
-+              if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
-+
-+                      info->rx_skb->dev = (void *)&(info->hdev);
-+                      info->rx_skb->pkt_type = inb(iobase + UART_RX);
-+
-+                      switch (info->rx_skb->pkt_type) {
-+
-+                      case HCI_EVENT_PKT:
-+                              info->rx_state = RECV_WAIT_EVENT_HEADER;
-+                              info->rx_count = HCI_EVENT_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_ACLDATA_PKT:
-+                              info->rx_state = RECV_WAIT_ACL_HEADER;
-+                              info->rx_count = HCI_ACL_HDR_SIZE;
-+                              break;
-+
-+                      case HCI_SCODATA_PKT:
-+                              info->rx_state = RECV_WAIT_SCO_HEADER;
-+                              info->rx_count = HCI_SCO_HDR_SIZE;
-+                              break;
-+
-+                      default:
-+                              /* Unknown packet */
-+                              printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+                              info->hdev.stat.err_rx++;
-+                              clear_bit(HCI_RUNNING, &(info->hdev.flags));
-+
-+                              kfree_skb(info->rx_skb);
-+                              info->rx_skb = NULL;
-+                              break;
-+
-+                      }
-+
-+              } else {
-+
-+                      *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+                      info->rx_count--;
-+
-+                      if (info->rx_count == 0) {
-+
-+                              int dlen;
-+                              hci_event_hdr *eh;
-+                              hci_acl_hdr *ah;
-+                              hci_sco_hdr *sh;
-+
-+
-+                              switch (info->rx_state) {
-+
-+                              case RECV_WAIT_EVENT_HEADER:
-+                                      eh = (hci_event_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = eh->plen;
-+                                      break;
-+
-+                              case RECV_WAIT_ACL_HEADER:
-+                                      ah = (hci_acl_hdr *)(info->rx_skb->data);
-+                                      dlen = __le16_to_cpu(ah->dlen);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_SCO_HEADER:
-+                                      sh = (hci_sco_hdr *)(info->rx_skb->data);
-+                                      info->rx_state = RECV_WAIT_DATA;
-+                                      info->rx_count = sh->dlen;
-+                                      break;
-+
-+                              case RECV_WAIT_DATA:
-+                                      hci_recv_frame(info->rx_skb);
-+                                      info->rx_skb = NULL;
-+                                      break;
-+
-+                              }
-+
-+                      }
-+
-+              }
-+
-+              /* Make sure we don't stay here to long */
-+              if (boguscount++ > 16)
-+                      break;
-+
-+      } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+      btuart_info_t *info = dev_inst;
-+      unsigned int iobase;
-+      int boguscount = 0;
-+      int iir, lsr;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      spin_lock(&(info->lock));
-+
-+      iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+      while (iir) {
-+
-+              /* Clear interrupt */
-+              lsr = inb(iobase + UART_LSR);
-+
-+              switch (iir) {
-+              case UART_IIR_RLSI:
-+                      printk(KERN_NOTICE "btuart_cs: RLSI\n");
-+                      break;
-+              case UART_IIR_RDI:
-+                      /* Receive interrupt */
-+                      btuart_receive(info);
-+                      break;
-+              case UART_IIR_THRI:
-+                      if (lsr & UART_LSR_THRE) {
-+                              /* Transmitter ready for data */
-+                              btuart_write_wakeup(info);
-+                      }
-+                      break;
-+              default:
-+                      printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
-+                      break;
-+              }
-+
-+              /* Make sure we don't stay here to long */
-+              if (boguscount++ > 100)
-+                      break;
-+
-+              iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+      }
-+
-+      spin_unlock(&(info->lock));
-+}
-+
-+
-+static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
-+{
-+      unsigned long flags;
-+      unsigned int iobase;
-+      int fcr;                /* FIFO control reg */
-+      int lcr;                /* Line control reg */
-+      int divisor;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      /* Turn off interrupts */
-+      outb(0, iobase + UART_IER);
-+
-+      divisor = SPEED_MAX / speed;
-+
-+      fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
-+
-+      /* 
-+       * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
-+       * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
-+       * about this timeout since it will always be fast enough. 
-+       */
-+
-+      if (speed < 38400)
-+              fcr |= UART_FCR_TRIGGER_1;
-+      else
-+              fcr |= UART_FCR_TRIGGER_14;
-+
-+      /* Bluetooth cards use 8N1 */
-+      lcr = UART_LCR_WLEN8;
-+
-+      outb(UART_LCR_DLAB | lcr, iobase + UART_LCR);   /* Set DLAB */
-+      outb(divisor & 0xff, iobase + UART_DLL);        /* Set speed */
-+      outb(divisor >> 8, iobase + UART_DLM);
-+      outb(lcr, iobase + UART_LCR);   /* Set 8N1  */
-+      outb(fcr, iobase + UART_FCR);   /* Enable FIFO's */
-+
-+      /* Turn on interrups */
-+      outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int btuart_hci_flush(struct hci_dev *hdev)
-+{
-+      btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
-+
-+      /* Drop TX queue */
-+      skb_queue_purge(&(info->txq));
-+
-+      return 0;
-+}
-+
-+
-+static int btuart_hci_open(struct hci_dev *hdev)
-+{
-+      set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+      return 0;
-+}
-+
-+
-+static int btuart_hci_close(struct hci_dev *hdev)
-+{
-+      if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+              return 0;
-+
-+      btuart_hci_flush(hdev);
-+
-+      return 0;
-+}
-+
-+
-+static int btuart_hci_send_frame(struct sk_buff *skb)
-+{
-+      btuart_info_t *info;
-+      struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+
-+      if (!hdev) {
-+              printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
-+              return -ENODEV;
-+      }
-+
-+      info = (btuart_info_t *)(hdev->driver_data);
-+
-+      switch (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;
-+      };
-+
-+      /* Prepend skb with frame type */
-+      memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
-+      skb_queue_tail(&(info->txq), skb);
-+
-+      btuart_write_wakeup(info);
-+
-+      return 0;
-+}
-+
-+
-+static void btuart_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
-+{
-+      return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int btuart_open(btuart_info_t *info)
-+{
-+      unsigned long flags;
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev;
-+
-+      spin_lock_init(&(info->lock));
-+
-+      skb_queue_head_init(&(info->txq));
-+
-+      info->rx_state = RECV_WAIT_PACKET_TYPE;
-+      info->rx_count = 0;
-+      info->rx_skb = NULL;
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      /* Reset UART */
-+      outb(0, iobase + UART_MCR);
-+
-+      /* Turn off interrupts */
-+      outb(0, iobase + UART_IER);
-+
-+      /* Initialize UART */
-+      outb(UART_LCR_WLEN8, iobase + UART_LCR);        /* Reset DLAB */
-+      outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+      /* Turn on interrupts */
-+      // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+
-+      btuart_change_speed(info, DEFAULT_BAUD_RATE);
-+
-+      /* Timeout before it is safe to send the first HCI packet */
-+      set_current_state(TASK_INTERRUPTIBLE);
-+      schedule_timeout(HZ);
-+
-+
-+      /* Initialize and register HCI device */
-+
-+      hdev = &(info->hdev);
-+
-+      hdev->type = HCI_PCCARD;
-+      hdev->driver_data = info;
-+
-+      hdev->open = btuart_hci_open;
-+      hdev->close = btuart_hci_close;
-+      hdev->flush = btuart_hci_flush;
-+      hdev->send = btuart_hci_send_frame;
-+      hdev->destruct = btuart_hci_destruct;
-+      hdev->ioctl = btuart_hci_ioctl;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
-+              return -ENODEV;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+int btuart_close(btuart_info_t *info)
-+{
-+      unsigned long flags;
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev = &(info->hdev);
-+
-+      btuart_hci_close(hdev);
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      /* Reset UART */
-+      outb(0, iobase + UART_MCR);
-+
-+      /* Turn off interrupts */
-+      outb(0, iobase + UART_IER);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+
-+      if (hci_unregister_dev(hdev) < 0)
-+              printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+      error_info_t err = { func, ret };
-+
-+      CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *btuart_attach(void)
-+{
-+      btuart_info_t *info;
-+      client_reg_t client_reg;
-+      dev_link_t *link;
-+      int i, ret;
-+
-+      /* Create new info device */
-+      info = kmalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return NULL;
-+      memset(info, 0, sizeof(*info));
-+
-+      link = &info->link;
-+      link->priv = info;
-+
-+      link->release.function = &btuart_release;
-+      link->release.data = (u_long)link;
-+      link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+      link->io.NumPorts1 = 8;
-+      link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+      link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+      if (irq_list[0] == -1)
-+              link->irq.IRQInfo2 = irq_mask;
-+      else
-+              for (i = 0; i < 4; i++)
-+                      link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+      link->irq.Handler = btuart_interrupt;
-+      link->irq.Instance = info;
-+
-+      link->conf.Attributes = CONF_ENABLE_IRQ;
-+      link->conf.Vcc = 50;
-+      link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+      /* Register with Card Services */
-+      link->next = dev_list;
-+      dev_list = link;
-+      client_reg.dev_info = &dev_info;
-+      client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+      client_reg.EventMask =
-+              CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+              CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+              CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+      client_reg.event_handler = &btuart_event;
-+      client_reg.Version = 0x0210;
-+      client_reg.event_callback_args.client_data = link;
-+
-+      ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+      if (ret != CS_SUCCESS) {
-+              cs_error(link->handle, RegisterClient, ret);
-+              btuart_detach(link);
-+              return NULL;
-+      }
-+
-+      return link;
-+}
-+
-+
-+void btuart_detach(dev_link_t *link)
-+{
-+      btuart_info_t *info = link->priv;
-+      dev_link_t **linkp;
-+      int ret;
-+
-+      /* Locate device structure */
-+      for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+              if (*linkp == link)
-+                      break;
-+
-+      if (*linkp == NULL)
-+              return;
-+
-+      del_timer(&link->release);
-+      if (link->state & DEV_CONFIG)
-+              btuart_release((u_long)link);
-+
-+      if (link->handle) {
-+              ret = CardServices(DeregisterClient, link->handle);
-+              if (ret != CS_SUCCESS)
-+                      cs_error(link->handle, DeregisterClient, ret);
-+      }
-+
-+      /* Unlink device structure, free bits */
-+      *linkp = link->next;
-+
-+      kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+      int i;
-+
-+      i = CardServices(fn, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return CS_NO_MORE_ITEMS;
-+
-+      i = CardServices(GetTupleData, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return i;
-+
-+      return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void btuart_config(dev_link_t *link)
-+{
-+      static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
-+      client_handle_t handle = link->handle;
-+      btuart_info_t *info = link->priv;
-+      tuple_t tuple;
-+      u_short buf[256];
-+      cisparse_t parse;
-+      cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+      config_info_t config;
-+      int i, j, try, last_ret, last_fn;
-+
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+
-+      /* Get configuration register information */
-+      tuple.DesiredTuple = CISTPL_CONFIG;
-+      last_ret = first_tuple(handle, &tuple, &parse);
-+      if (last_ret != CS_SUCCESS) {
-+              last_fn = ParseTuple;
-+              goto cs_failed;
-+      }
-+      link->conf.ConfigBase = parse.config.base;
-+      link->conf.Present = parse.config.rmask[0];
-+
-+      /* Configure card */
-+      link->state |= DEV_CONFIG;
-+      i = CardServices(GetConfigurationInfo, handle, &config);
-+      link->conf.Vcc = config.Vcc;
-+
-+      /* First pass: look for a config entry that looks normal. */
-+      tuple.TupleData = (cisdata_t *) buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+      tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+      /* Two tries: without IO aliases, then with aliases */
-+      for (try = 0; try < 2; try++) {
-+              i = first_tuple(handle, &tuple, &parse);
-+              while (i != CS_NO_MORE_ITEMS) {
-+                      if (i != CS_SUCCESS)
-+                              goto next_entry;
-+                      if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-+                              link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-+                      if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
-+                              link->conf.ConfigIndex = cf->index;
-+                              link->io.BasePort1 = cf->io.win[0].base;
-+                              link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
-+                              i = CardServices(RequestIO, link->handle, &link->io);
-+                              if (i == CS_SUCCESS)
-+                                      goto found_port;
-+                      }
-+next_entry:
-+                      i = next_tuple(handle, &tuple, &parse);
-+              }
-+      }
-+
-+      /* Second pass: try to find an entry that isn't picky about
-+         its base address, then try to grab any standard serial port
-+         address, and finally try to get any free port. */
-+      i = first_tuple(handle, &tuple, &parse);
-+      while (i != CS_NO_MORE_ITEMS) {
-+              if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
-+                  && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-+                      link->conf.ConfigIndex = cf->index;
-+                      for (j = 0; j < 5; j++) {
-+                              link->io.BasePort1 = base[j];
-+                              link->io.IOAddrLines = base[j] ? 16 : 3;
-+                              i = CardServices(RequestIO, link->handle, &link->io);
-+                              if (i == CS_SUCCESS)
-+                                      goto found_port;
-+                      }
-+              }
-+              i = next_tuple(handle, &tuple, &parse);
-+      }
-+
-+found_port:
-+      if (i != CS_SUCCESS) {
-+              printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
-+              cs_error(link->handle, RequestIO, i);
-+              goto failed;
-+      }
-+
-+      i = CardServices(RequestIRQ, link->handle, &link->irq);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIRQ, i);
-+              link->irq.AssignedIRQ = 0;
-+      }
-+
-+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestConfiguration, i);
-+              goto failed;
-+      }
-+
-+      MOD_INC_USE_COUNT;
-+
-+      if (btuart_open(info) != 0)
-+              goto failed;
-+
-+      strcpy(info->node.dev_name, info->hdev.name);
-+      link->dev = &info->node;
-+      link->state &= ~DEV_CONFIG_PENDING;
-+
-+      return;
-+
-+cs_failed:
-+      cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+      btuart_release((u_long) link);
-+}
-+
-+
-+void btuart_release(u_long arg)
-+{
-+      dev_link_t *link = (dev_link_t *)arg;
-+      btuart_info_t *info = link->priv;
-+
-+      if (link->state & DEV_PRESENT)
-+              btuart_close(info);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      link->dev = NULL;
-+
-+      CardServices(ReleaseConfiguration, link->handle);
-+      CardServices(ReleaseIO, link->handle, &link->io);
-+      CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+      link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int btuart_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+      dev_link_t *link = args->client_data;
-+      btuart_info_t *info = link->priv;
-+
-+      switch (event) {
-+      case CS_EVENT_CARD_REMOVAL:
-+              link->state &= ~DEV_PRESENT;
-+              if (link->state & DEV_CONFIG) {
-+                      btuart_close(info);
-+                      mod_timer(&link->release, jiffies + HZ / 20);
-+              }
-+              break;
-+      case CS_EVENT_CARD_INSERTION:
-+              link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+              btuart_config(link);
-+              break;
-+      case CS_EVENT_PM_SUSPEND:
-+              link->state |= DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_RESET_PHYSICAL:
-+              if (link->state & DEV_CONFIG)
-+                      CardServices(ReleaseConfiguration, link->handle);
-+              break;
-+      case CS_EVENT_PM_RESUME:
-+              link->state &= ~DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_CARD_RESET:
-+              if (DEV_OK(link))
-+                      CardServices(RequestConfiguration, link->handle, &link->conf);
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_btuart_cs(void)
-+{
-+      servinfo_t serv;
-+      int err;
-+
-+      CardServices(GetCardServicesInfo, &serv);
-+      if (serv.Revision != CS_RELEASE_CODE) {
-+              printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
-+              return -1;
-+      }
-+
-+      err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
-+
-+      return err;
-+}
-+
-+
-+void __exit exit_btuart_cs(void)
-+{
-+      unregister_pccard_driver(&dev_info);
-+
-+      while (dev_list != NULL)
-+              btuart_detach(dev_list);
-+}
-+
-+
-+module_init(init_btuart_cs);
-+module_exit(exit_btuart_cs);
-+
-+EXPORT_NO_SYMBOLS;
---- linux/drivers/bluetooth/Config.in~bluetooth-2.4.18-mh11    2001-09-07 18:28:38.000000000 +0200
-+++ linux/drivers/bluetooth/Config.in  2004-01-25 23:37:39.000000000 +0100
-@@ -1,8 +1,33 @@
-+#
-+# Bluetooth HCI device drivers configuration
-+#
-+
- mainmenu_option next_comment
- comment 'Bluetooth device drivers'
- dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
-+if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-+   bool '  SCO (voice) support'  CONFIG_BLUEZ_HCIUSB_SCO
-+fi
-+
- 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
-+   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
-+   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
-+fi
-+
-+dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
-+
-+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
-+
-+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
- endmenu
-+
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/dtl1_cs.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,858 @@
-+/*
-+ *
-+ *  A driver for Nokia Connectivity Card DTL-1 devices
-+ *
-+ *  Copyright (C) 2001-2002  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;
-+ *
-+ *  Software distributed under the License is distributed on an "AS
-+ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
-+ *  implied. See the License for the specific language governing
-+ *  rights and limitations under the License.
-+ *
-+ *  The initial developer of the original code is David A. Hinds
-+ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
-+ *
-+ */
-+
-+#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/sched.h>
-+#include <linux/timer.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/spinlock.h>
-+
-+#include <linux/skbuff.h>
-+#include <linux/string.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <asm/system.h>
-+#include <asm/bitops.h>
-+#include <asm/io.h>
-+
-+#include <pcmcia/version.h>
-+#include <pcmcia/cs_types.h>
-+#include <pcmcia/cs.h>
-+#include <pcmcia/cistpl.h>
-+#include <pcmcia/ciscode.h>
-+#include <pcmcia/ds.h>
-+#include <pcmcia/cisreg.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+
-+
-+/* ======================== Module parameters ======================== */
-+
-+
-+/* Bit map of interrupts to choose from */
-+static u_int irq_mask = 0xffff;
-+static int irq_list[4] = { -1 };
-+
-+MODULE_PARM(irq_mask, "i");
-+MODULE_PARM(irq_list, "1-4i");
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
-+MODULE_LICENSE("GPL");
-+
-+
-+
-+/* ======================== Local structures ======================== */
-+
-+
-+typedef struct dtl1_info_t {
-+      dev_link_t link;
-+      dev_node_t node;
-+
-+      struct hci_dev hdev;
-+
-+      spinlock_t lock;                /* For serializing operations */
-+
-+      unsigned long flowmask;         /* HCI flow mask */
-+      int ri_latch;
-+
-+      struct sk_buff_head txq;
-+      unsigned long tx_state;
-+
-+      unsigned long rx_state;
-+      unsigned long rx_count;
-+      struct sk_buff *rx_skb;
-+} dtl1_info_t;
-+
-+
-+void dtl1_config(dev_link_t *link);
-+void dtl1_release(u_long arg);
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args);
-+
-+static dev_info_t dev_info = "dtl1_cs";
-+
-+dev_link_t *dtl1_attach(void);
-+void dtl1_detach(dev_link_t *);
-+
-+static dev_link_t *dev_list = NULL;
-+
-+
-+/* Transmit states  */
-+#define XMIT_SENDING  1
-+#define XMIT_WAKEUP   2
-+#define XMIT_WAITING  8
-+
-+/* Receiver States */
-+#define RECV_WAIT_NSH   0
-+#define RECV_WAIT_DATA  1
-+
-+
-+typedef struct {
-+      u8 type;
-+      u8 zero;
-+      u16 len;
-+} __attribute__ ((packed)) nsh_t;     /* Nokia Specific Header */
-+
-+#define NSHL  4                               /* Nokia Specific Header Length */
-+
-+
-+
-+/* ======================== Interrupt handling ======================== */
-+
-+
-+static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
-+{
-+      int actual = 0;
-+
-+      /* Tx FIFO should be empty */
-+      if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
-+              return 0;
-+
-+      /* Fill FIFO with current frame */
-+      while ((fifo_size-- > 0) && (actual < len)) {
-+              /* Transmit next byte */
-+              outb(buf[actual], iobase + UART_TX);
-+              actual++;
-+      }
-+
-+      return actual;
-+}
-+
-+
-+static void dtl1_write_wakeup(dtl1_info_t *info)
-+{
-+      if (!info) {
-+              printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
-+              return;
-+      }
-+
-+      if (test_bit(XMIT_WAITING, &(info->tx_state))) {
-+              set_bit(XMIT_WAKEUP, &(info->tx_state));
-+              return;
-+      }
-+
-+      if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
-+              set_bit(XMIT_WAKEUP, &(info->tx_state));
-+              return;
-+      }
-+
-+      do {
-+              register unsigned int iobase = info->link.io.BasePort1;
-+              register struct sk_buff *skb;
-+              register int len;
-+
-+              clear_bit(XMIT_WAKEUP, &(info->tx_state));
-+
-+              if (!(info->link.state & DEV_PRESENT))
-+                      return;
-+
-+              if (!(skb = skb_dequeue(&(info->txq))))
-+                      break;
-+
-+              /* Send frame */
-+              len = dtl1_write(iobase, 32, skb->data, skb->len);
-+
-+              if (len == skb->len) {
-+                      set_bit(XMIT_WAITING, &(info->tx_state));
-+                      kfree_skb(skb);
-+              } else {
-+                      skb_pull(skb, len);
-+                      skb_queue_head(&(info->txq), skb);
-+              }
-+
-+              info->hdev.stat.byte_tx += len;
-+
-+      } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
-+
-+      clear_bit(XMIT_SENDING, &(info->tx_state));
-+}
-+
-+
-+static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
-+{
-+      u8 flowmask = *(u8 *)skb->data;
-+      int i;
-+
-+      printk(KERN_INFO "dtl1_cs: Nokia control data = ");
-+      for (i = 0; i < skb->len; i++) {
-+              printk("%02x ", skb->data[i]);
-+      }
-+      printk("\n");
-+
-+      /* transition to active state */
-+      if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
-+              clear_bit(XMIT_WAITING, &(info->tx_state));
-+              dtl1_write_wakeup(info);
-+      }
-+
-+      info->flowmask = flowmask;
-+
-+      kfree_skb(skb);
-+}
-+
-+
-+static void dtl1_receive(dtl1_info_t *info)
-+{
-+      unsigned int iobase;
-+      nsh_t *nsh;
-+      int boguscount = 0;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      do {
-+              info->hdev.stat.byte_rx++;
-+
-+              /* Allocate packet */
-+              if (info->rx_skb == NULL)
-+                      if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
-+                              printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
-+                              info->rx_state = RECV_WAIT_NSH;
-+                              info->rx_count = NSHL;
-+                              return;
-+                      }
-+
-+              *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-+              nsh = (nsh_t *)info->rx_skb->data;
-+
-+              info->rx_count--;
-+
-+              if (info->rx_count == 0) {
-+
-+                      switch (info->rx_state) {
-+                      case RECV_WAIT_NSH:
-+                              info->rx_state = RECV_WAIT_DATA;
-+                              info->rx_count = nsh->len + (nsh->len & 0x0001);
-+                              break;
-+                      case RECV_WAIT_DATA:
-+                              info->rx_skb->pkt_type = nsh->type;
-+
-+                              /* remove PAD byte if it exists */
-+                              if (nsh->len & 0x0001) {
-+                                      info->rx_skb->tail--;
-+                                      info->rx_skb->len--;
-+                              }
-+
-+                              /* remove NSH */
-+                              skb_pull(info->rx_skb, NSHL);
-+
-+                              switch (info->rx_skb->pkt_type) {
-+                              case 0x80:
-+                                      /* control data for the Nokia Card */
-+                                      dtl1_control(info, info->rx_skb);
-+                                      break;
-+                              case 0x82:
-+                              case 0x83:
-+                              case 0x84:
-+                                      /* send frame to the HCI layer */
-+                                      info->rx_skb->dev = (void *)&(info->hdev);
-+                                      info->rx_skb->pkt_type &= 0x0f;
-+                                      hci_recv_frame(info->rx_skb);
-+                                      break;
-+                              default:
-+                                      /* unknown packet */
-+                                      printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
-+                                      kfree_skb(info->rx_skb);
-+                                      break;
-+                              }
-+
-+                              info->rx_state = RECV_WAIT_NSH;
-+                              info->rx_count = NSHL;
-+                              info->rx_skb = NULL;
-+                              break;
-+                      }
-+
-+              }
-+
-+              /* Make sure we don't stay here to long */
-+              if (boguscount++ > 32)
-+                      break;
-+
-+      } while (inb(iobase + UART_LSR) & UART_LSR_DR);
-+}
-+
-+
-+void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
-+{
-+      dtl1_info_t *info = dev_inst;
-+      unsigned int iobase;
-+      unsigned char msr;
-+      int boguscount = 0;
-+      int iir, lsr;
-+
-+      if (!info) {
-+              printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
-+              return;
-+      }
-+
-+      iobase = info->link.io.BasePort1;
-+
-+      spin_lock(&(info->lock));
-+
-+      iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+      while (iir) {
-+
-+              /* Clear interrupt */
-+              lsr = inb(iobase + UART_LSR);
-+
-+              switch (iir) {
-+              case UART_IIR_RLSI:
-+                      printk(KERN_NOTICE "dtl1_cs: RLSI\n");
-+                      break;
-+              case UART_IIR_RDI:
-+                      /* Receive interrupt */
-+                      dtl1_receive(info);
-+                      break;
-+              case UART_IIR_THRI:
-+                      if (lsr & UART_LSR_THRE) {
-+                              /* Transmitter ready for data */
-+                              dtl1_write_wakeup(info);
-+                      }
-+                      break;
-+              default:
-+                      printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
-+                      break;
-+              }
-+
-+              /* Make sure we don't stay here to long */
-+              if (boguscount++ > 100)
-+                      break;
-+
-+              iir = inb(iobase + UART_IIR) & UART_IIR_ID;
-+
-+      }
-+
-+      msr = inb(iobase + UART_MSR);
-+
-+      if (info->ri_latch ^ (msr & UART_MSR_RI)) {
-+              info->ri_latch = msr & UART_MSR_RI;
-+              clear_bit(XMIT_WAITING, &(info->tx_state));
-+              dtl1_write_wakeup(info);
-+      }
-+
-+      spin_unlock(&(info->lock));
-+}
-+
-+
-+
-+/* ======================== HCI interface ======================== */
-+
-+
-+static int dtl1_hci_open(struct hci_dev *hdev)
-+{
-+      set_bit(HCI_RUNNING, &(hdev->flags));
-+
-+      return 0;
-+}
-+
-+
-+static int dtl1_hci_flush(struct hci_dev *hdev)
-+{
-+      dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
-+
-+      /* Drop TX queue */
-+      skb_queue_purge(&(info->txq));
-+
-+      return 0;
-+}
-+
-+
-+static int dtl1_hci_close(struct hci_dev *hdev)
-+{
-+      if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
-+              return 0;
-+
-+      dtl1_hci_flush(hdev);
-+
-+      return 0;
-+}
-+
-+
-+static int dtl1_hci_send_frame(struct sk_buff *skb)
-+{
-+      dtl1_info_t *info;
-+      struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
-+      struct sk_buff *s;
-+      nsh_t nsh;
-+
-+      if (!hdev) {
-+              printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
-+              return -ENODEV;
-+      }
-+
-+      info = (dtl1_info_t *)(hdev->driver_data);
-+
-+      switch (skb->pkt_type) {
-+      case HCI_COMMAND_PKT:
-+              hdev->stat.cmd_tx++;
-+              nsh.type = 0x81;
-+              break;
-+      case HCI_ACLDATA_PKT:
-+              hdev->stat.acl_tx++;
-+              nsh.type = 0x82;
-+              break;
-+      case HCI_SCODATA_PKT:
-+              hdev->stat.sco_tx++;
-+              nsh.type = 0x83;
-+              break;
-+      };
-+
-+      nsh.zero = 0;
-+      nsh.len = skb->len;
-+
-+      s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
-+      skb_reserve(s, NSHL);
-+      memcpy(skb_put(s, skb->len), skb->data, skb->len);
-+      if (skb->len & 0x0001)
-+              *skb_put(s, 1) = 0;     /* PAD */
-+
-+      /* Prepend skb with Nokia frame header and queue */
-+      memcpy(skb_push(s, NSHL), &nsh, NSHL);
-+      skb_queue_tail(&(info->txq), s);
-+
-+      dtl1_write_wakeup(info);
-+
-+      kfree_skb(skb);
-+
-+      return 0;
-+}
-+
-+
-+static void dtl1_hci_destruct(struct hci_dev *hdev)
-+{
-+}
-+
-+
-+static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
-+{
-+      return -ENOIOCTLCMD;
-+}
-+
-+
-+
-+/* ======================== Card services HCI interaction ======================== */
-+
-+
-+int dtl1_open(dtl1_info_t *info)
-+{
-+      unsigned long flags;
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev;
-+
-+      spin_lock_init(&(info->lock));
-+
-+      skb_queue_head_init(&(info->txq));
-+
-+      info->rx_state = RECV_WAIT_NSH;
-+      info->rx_count = NSHL;
-+      info->rx_skb = NULL;
-+
-+      set_bit(XMIT_WAITING, &(info->tx_state));
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      /* Reset UART */
-+      outb(0, iobase + UART_MCR);
-+
-+      /* Turn off interrupts */
-+      outb(0, iobase + UART_IER);
-+
-+      /* Initialize UART */
-+      outb(UART_LCR_WLEN8, iobase + UART_LCR);        /* Reset DLAB */
-+      outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
-+
-+      info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
-+
-+      /* Turn on interrupts */
-+      outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+
-+      /* Timeout before it is safe to send the first HCI packet */
-+      set_current_state(TASK_INTERRUPTIBLE);
-+      schedule_timeout(HZ * 2);
-+
-+
-+      /* Initialize and register HCI device */
-+
-+      hdev = &(info->hdev);
-+
-+      hdev->type = HCI_PCCARD;
-+      hdev->driver_data = info;
-+
-+      hdev->open = dtl1_hci_open;
-+      hdev->close = dtl1_hci_close;
-+      hdev->flush = dtl1_hci_flush;
-+      hdev->send = dtl1_hci_send_frame;
-+      hdev->destruct = dtl1_hci_destruct;
-+      hdev->ioctl = dtl1_hci_ioctl;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
-+              return -ENODEV;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+int dtl1_close(dtl1_info_t *info)
-+{
-+      unsigned long flags;
-+      unsigned int iobase = info->link.io.BasePort1;
-+      struct hci_dev *hdev = &(info->hdev);
-+
-+      dtl1_hci_close(hdev);
-+
-+      spin_lock_irqsave(&(info->lock), flags);
-+
-+      /* Reset UART */
-+      outb(0, iobase + UART_MCR);
-+
-+      /* Turn off interrupts */
-+      outb(0, iobase + UART_IER);
-+
-+      spin_unlock_irqrestore(&(info->lock), flags);
-+
-+      if (hci_unregister_dev(hdev) < 0)
-+              printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Card services ======================== */
-+
-+
-+static void cs_error(client_handle_t handle, int func, int ret)
-+{
-+      error_info_t err = { func, ret };
-+
-+      CardServices(ReportError, handle, &err);
-+}
-+
-+
-+dev_link_t *dtl1_attach(void)
-+{
-+      dtl1_info_t *info;
-+      client_reg_t client_reg;
-+      dev_link_t *link;
-+      int i, ret;
-+
-+      /* Create new info device */
-+      info = kmalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info)
-+              return NULL;
-+      memset(info, 0, sizeof(*info));
-+
-+      link = &info->link;
-+      link->priv = info;
-+
-+      link->release.function = &dtl1_release;
-+      link->release.data = (u_long)link;
-+      link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-+      link->io.NumPorts1 = 8;
-+      link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-+      link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-+
-+      if (irq_list[0] == -1)
-+              link->irq.IRQInfo2 = irq_mask;
-+      else
-+              for (i = 0; i < 4; i++)
-+                      link->irq.IRQInfo2 |= 1 << irq_list[i];
-+
-+      link->irq.Handler = dtl1_interrupt;
-+      link->irq.Instance = info;
-+
-+      link->conf.Attributes = CONF_ENABLE_IRQ;
-+      link->conf.Vcc = 50;
-+      link->conf.IntType = INT_MEMORY_AND_IO;
-+
-+      /* Register with Card Services */
-+      link->next = dev_list;
-+      dev_list = link;
-+      client_reg.dev_info = &dev_info;
-+      client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-+      client_reg.EventMask =
-+              CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-+              CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-+              CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-+      client_reg.event_handler = &dtl1_event;
-+      client_reg.Version = 0x0210;
-+      client_reg.event_callback_args.client_data = link;
-+
-+      ret = CardServices(RegisterClient, &link->handle, &client_reg);
-+      if (ret != CS_SUCCESS) {
-+              cs_error(link->handle, RegisterClient, ret);
-+              dtl1_detach(link);
-+              return NULL;
-+      }
-+
-+      return link;
-+}
-+
-+
-+void dtl1_detach(dev_link_t *link)
-+{
-+      dtl1_info_t *info = link->priv;
-+      dev_link_t **linkp;
-+      int ret;
-+
-+      /* Locate device structure */
-+      for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-+              if (*linkp == link)
-+                      break;
-+
-+      if (*linkp == NULL)
-+              return;
-+
-+      del_timer(&link->release);
-+      if (link->state & DEV_CONFIG)
-+              dtl1_release((u_long)link);
-+
-+      if (link->handle) {
-+              ret = CardServices(DeregisterClient, link->handle);
-+              if (ret != CS_SUCCESS)
-+                      cs_error(link->handle, DeregisterClient, ret);
-+      }
-+
-+      /* Unlink device structure, free bits */
-+      *linkp = link->next;
-+
-+      kfree(info);
-+}
-+
-+
-+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
-+{
-+      int i;
-+
-+      i = CardServices(fn, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return CS_NO_MORE_ITEMS;
-+
-+      i = CardServices(GetTupleData, handle, tuple);
-+      if (i != CS_SUCCESS)
-+              return i;
-+
-+      return CardServices(ParseTuple, handle, tuple, parse);
-+}
-+
-+
-+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
-+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
-+
-+void dtl1_config(dev_link_t *link)
-+{
-+      client_handle_t handle = link->handle;
-+      dtl1_info_t *info = link->priv;
-+      tuple_t tuple;
-+      u_short buf[256];
-+      cisparse_t parse;
-+      cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+      config_info_t config;
-+      int i, last_ret, last_fn;
-+
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+
-+      /* Get configuration register information */
-+      tuple.DesiredTuple = CISTPL_CONFIG;
-+      last_ret = first_tuple(handle, &tuple, &parse);
-+      if (last_ret != CS_SUCCESS) {
-+              last_fn = ParseTuple;
-+              goto cs_failed;
-+      }
-+      link->conf.ConfigBase = parse.config.base;
-+      link->conf.Present = parse.config.rmask[0];
-+
-+      /* Configure card */
-+      link->state |= DEV_CONFIG;
-+      i = CardServices(GetConfigurationInfo, handle, &config);
-+      link->conf.Vcc = config.Vcc;
-+
-+      tuple.TupleData = (cisdata_t *)buf;
-+      tuple.TupleOffset = 0;
-+      tuple.TupleDataMax = 255;
-+      tuple.Attributes = 0;
-+      tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-+
-+      /* Look for a generic full-sized window */
-+      link->io.NumPorts1 = 8;
-+      i = first_tuple(handle, &tuple, &parse);
-+      while (i != CS_NO_MORE_ITEMS) {
-+              if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-+                      link->conf.ConfigIndex = cf->index;
-+                      link->io.BasePort1 = cf->io.win[0].base;
-+                      link->io.NumPorts1 = cf->io.win[0].len; /*yo */
-+                      link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
-+                      i = CardServices(RequestIO, link->handle, &link->io);
-+                      if (i == CS_SUCCESS)
-+                              break;
-+              }
-+              i = next_tuple(handle, &tuple, &parse);
-+      }
-+
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIO, i);
-+              goto failed;
-+      }
-+
-+      i = CardServices(RequestIRQ, link->handle, &link->irq);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestIRQ, i);
-+              link->irq.AssignedIRQ = 0;
-+      }
-+
-+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
-+      if (i != CS_SUCCESS) {
-+              cs_error(link->handle, RequestConfiguration, i);
-+              goto failed;
-+      }
-+
-+      MOD_INC_USE_COUNT;
-+
-+      if (dtl1_open(info) != 0)
-+              goto failed;
-+
-+      strcpy(info->node.dev_name, info->hdev.name);
-+      link->dev = &info->node;
-+      link->state &= ~DEV_CONFIG_PENDING;
-+
-+      return;
-+
-+cs_failed:
-+      cs_error(link->handle, last_fn, last_ret);
-+
-+failed:
-+      dtl1_release((u_long)link);
-+}
-+
-+
-+void dtl1_release(u_long arg)
-+{
-+      dev_link_t *link = (dev_link_t *)arg;
-+      dtl1_info_t *info = link->priv;
-+
-+      if (link->state & DEV_PRESENT)
-+              dtl1_close(info);
-+
-+      MOD_DEC_USE_COUNT;
-+
-+      link->dev = NULL;
-+
-+      CardServices(ReleaseConfiguration, link->handle);
-+      CardServices(ReleaseIO, link->handle, &link->io);
-+      CardServices(ReleaseIRQ, link->handle, &link->irq);
-+
-+      link->state &= ~DEV_CONFIG;
-+}
-+
-+
-+int dtl1_event(event_t event, int priority, event_callback_args_t *args)
-+{
-+      dev_link_t *link = args->client_data;
-+      dtl1_info_t *info = link->priv;
-+
-+      switch (event) {
-+      case CS_EVENT_CARD_REMOVAL:
-+              link->state &= ~DEV_PRESENT;
-+              if (link->state & DEV_CONFIG) {
-+                      dtl1_close(info);
-+                      mod_timer(&link->release, jiffies + HZ / 20);
-+              }
-+              break;
-+      case CS_EVENT_CARD_INSERTION:
-+              link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-+              dtl1_config(link);
-+              break;
-+      case CS_EVENT_PM_SUSPEND:
-+              link->state |= DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_RESET_PHYSICAL:
-+              if (link->state & DEV_CONFIG)
-+                      CardServices(ReleaseConfiguration, link->handle);
-+              break;
-+      case CS_EVENT_PM_RESUME:
-+              link->state &= ~DEV_SUSPEND;
-+              /* Fall through... */
-+      case CS_EVENT_CARD_RESET:
-+              if (DEV_OK(link))
-+                      CardServices(RequestConfiguration, link->handle, &link->conf);
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+
-+
-+/* ======================== Module initialization ======================== */
-+
-+
-+int __init init_dtl1_cs(void)
-+{
-+      servinfo_t serv;
-+      int err;
-+
-+      CardServices(GetCardServicesInfo, &serv);
-+      if (serv.Revision != CS_RELEASE_CODE) {
-+              printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
-+              return -1;
-+      }
-+
-+      err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
-+
-+      return err;
-+}
-+
-+
-+void __exit exit_dtl1_cs(void)
-+{
-+      unregister_pccard_driver(&dev_info);
-+
-+      while (dev_list != NULL)
-+              dtl1_detach(dev_list);
-+}
-+
-+
-+module_init(init_dtl1_cs);
-+module_exit(exit_dtl1_cs);
-+
-+EXPORT_NO_SYMBOLS;
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_bcsp.c 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,710 @@
-+/* 
-+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+   Based on
-+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
-+       ABCSP     by Carl Orsborn <cjo@csr.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_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $
-+ */
-+
-+#define VERSION "0.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_bcsp.h"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#undef  BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+/* ---- BCSP CRC calculation ---- */
-+
-+/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
-+initial value 0xffff, bits shifted in reverse order. */
-+
-+static const u16 crc_table[] = {
-+      0x0000, 0x1081, 0x2102, 0x3183,
-+      0x4204, 0x5285, 0x6306, 0x7387,
-+      0x8408, 0x9489, 0xa50a, 0xb58b,
-+      0xc60c, 0xd68d, 0xe70e, 0xf78f
-+};
-+
-+/* Initialise the crc calculator */
-+#define BCSP_CRC_INIT(x) x = 0xffff
-+
-+/*
-+   Update crc with next data byte
-+
-+   Implementation note
-+        The data byte is treated as two nibbles.  The crc is generated
-+        in reverse, i.e., bits are fed into the register from the top.
-+*/
-+static void bcsp_crc_update(u16 *crc, u8 d)
-+{
-+      u16 reg = *crc;
-+
-+      reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
-+      reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
-+
-+      *crc = reg;
-+}
-+
-+/*
-+   Get reverse of generated crc
-+
-+   Implementation note
-+        The crc generator (bcsp_crc_init() and bcsp_crc_update())
-+        creates a reversed crc, so it needs to be swapped back before
-+        being passed on.
-+*/
-+static u16 bcsp_crc_reverse(u16 crc)
-+{
-+      u16 b, rev;
-+
-+      for (b = 0, rev = 0; b < 16; b++) {
-+              rev = rev << 1;
-+              rev |= (crc & 1);
-+              crc = crc >> 1;
-+      }
-+      return (rev);
-+}
-+
-+/* ---- BCSP core ---- */
-+
-+static void bcsp_slip_msgdelim(struct sk_buff *skb)
-+{
-+      const char pkt_delim = 0xc0;
-+      memcpy(skb_put(skb, 1), &pkt_delim, 1);
-+}
-+
-+static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
-+{
-+      const char esc_c0[2] = { 0xdb, 0xdc };
-+      const char esc_db[2] = { 0xdb, 0xdd };
-+
-+      switch (c) {
-+      case 0xc0:
-+              memcpy(skb_put(skb, 2), &esc_c0, 2);
-+              break;
-+      case 0xdb:
-+              memcpy(skb_put(skb, 2), &esc_db, 2);
-+              break;
-+      default:
-+              memcpy(skb_put(skb, 1), &c, 1);
-+      }
-+}
-+
-+static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+      struct bcsp_struct *bcsp = hu->priv;
-+
-+      if (skb->len > 0xFFF) {
-+              BT_ERR("Packet too long");
-+              kfree_skb(skb);
-+              return 0;
-+      }
-+
-+      switch (skb->pkt_type) {
-+      case HCI_ACLDATA_PKT:
-+      case HCI_COMMAND_PKT:
-+              skb_queue_tail(&bcsp->rel, skb);
-+              break;
-+
-+      case HCI_SCODATA_PKT:
-+              skb_queue_tail(&bcsp->unrel, skb);
-+              break;
-+              
-+      default:
-+              BT_ERR("Unknown packet type");
-+              kfree_skb(skb);
-+              break;
-+      }
-+      return 0;
-+}
-+
-+static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
-+              int len, int pkt_type)
-+{
-+      struct sk_buff *nskb;
-+      u8  hdr[4], chan;
-+      int rel, i;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+      u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
-+#endif
-+
-+      switch (pkt_type) {
-+      case HCI_ACLDATA_PKT:
-+              chan = 6;       /* BCSP ACL channel */
-+              rel = 1;        /* reliable channel */
-+              break;
-+      case HCI_COMMAND_PKT:
-+              chan = 5;       /* BCSP cmd/evt channel */
-+              rel = 1;        /* reliable channel */
-+              break;
-+      case HCI_SCODATA_PKT:
-+              chan = 7;       /* BCSP SCO channel */
-+              rel = 0;        /* unreliable channel */
-+              break;
-+      case BCSP_LE_PKT:
-+              chan = 1;       /* BCSP LE channel */
-+              rel = 0;        /* unreliable channel */
-+              break;
-+      case BCSP_ACK_PKT:
-+              chan = 0;       /* BCSP internal channel */
-+              rel = 0;        /* unreliable channel */
-+              break;
-+      default:
-+              BT_ERR("Unknown packet type");
-+              return NULL;
-+      }
-+
-+      /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
-+         (because bytes 0xc0 and 0xdb are escaped, worst case is
-+         when the packet is all made of 0xc0 and 0xdb :) )
-+         + 2 (0xc0 delimiters at start and end). */
-+
-+      nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
-+      if (!nskb)
-+              return NULL;
-+
-+      nskb->pkt_type = pkt_type;
-+
-+      bcsp_slip_msgdelim(nskb);
-+
-+      hdr[0] = bcsp->rxseq_txack << 3;
-+      bcsp->txack_req = 0;
-+      BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
-+
-+      if (rel) {
-+              hdr[0] |= 0x80 + bcsp->msgq_txseq;
-+              BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
-+              bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
-+      }
-+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+      hdr[0] |= 0x40;
-+#endif
-+
-+      hdr[1]  = (len << 4) & 0xFF;
-+      hdr[1] |= chan;
-+      hdr[2]  = len >> 4;
-+      hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
-+
-+      /* Put BCSP header */
-+      for (i = 0; i < 4; i++) {
-+              bcsp_slip_one_byte(nskb, hdr[i]);
-+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+              bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
-+#endif
-+      }
-+
-+      /* Put payload */
-+      for (i = 0; i < len; i++) {
-+              bcsp_slip_one_byte(nskb, data[i]);
-+#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+              bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
-+#endif
-+      }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
-+      /* Put CRC */
-+      bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
-+      bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
-+      bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
-+#endif
-+
-+      bcsp_slip_msgdelim(nskb);
-+      return nskb;
-+}
-+
-+/* This is a rewrite of pkt_avail in ABCSP */
-+static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
-+{
-+      struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+      unsigned long flags;
-+      struct sk_buff *skb;
-+      
-+      /* First of all, check for unreliable messages in the queue,
-+         since they have priority */
-+
-+      if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
-+              struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+              if (nskb) {
-+                      kfree_skb(skb);
-+                      return nskb;
-+              } else {
-+                      skb_queue_head(&bcsp->unrel, skb);
-+                      BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+              }
-+      }
-+
-+      /* Now, try to send a reliable pkt. We can only send a
-+         reliable packet if the number of packets sent but not yet ack'ed
-+         is < than the winsize */
-+
-+      spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+      if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
-+              struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
-+              if (nskb) {
-+                      __skb_queue_tail(&bcsp->unack, skb);
-+                      mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
-+                      spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+                      return nskb;
-+              } else {
-+                      skb_queue_head(&bcsp->rel, skb);
-+                      BT_ERR("Could not dequeue pkt because alloc_skb failed");
-+              }
-+      }
-+
-+      spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+
-+      /* We could not send a reliable packet, either because there are
-+         none or because there are too many unack'ed pkts. Did we receive
-+         any packets we have not acknowledged yet ? */
-+
-+      if (bcsp->txack_req) {
-+              /* if so, craft an empty ACK pkt and send it on BCSP unreliable
-+                 channel 0 */
-+              struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
-+              return nskb;
-+      }
-+
-+      /* We have nothing to send */
-+      return NULL;
-+}
-+
-+static int bcsp_flush(struct hci_uart *hu)
-+{
-+      BT_DBG("hu %p", hu);
-+      return 0;
-+}
-+
-+/* Remove ack'ed packets */
-+static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
-+{
-+      unsigned long flags;
-+      struct sk_buff *skb;
-+      int i, pkts_to_be_removed;
-+      u8 seqno;
-+
-+      spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+      pkts_to_be_removed = bcsp->unack.qlen;
-+      seqno = bcsp->msgq_txseq;
-+
-+      while (pkts_to_be_removed) {
-+              if (bcsp->rxack == seqno)
-+                      break;
-+              pkts_to_be_removed--;
-+              seqno = (seqno - 1) & 0x07;
-+      }
-+
-+      if (bcsp->rxack != seqno)
-+              BT_ERR("Peer acked invalid packet");
-+
-+      BT_DBG("Removing %u pkts out of %u, up to seqno %u",
-+             pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
-+
-+      for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
-+                      && skb != (struct sk_buff *) &bcsp->unack; i++) {
-+              struct sk_buff *nskb;
-+
-+              nskb = skb->next;
-+              __skb_unlink(skb, &bcsp->unack);
-+              kfree_skb(skb);
-+              skb = nskb;
-+      }
-+      if (bcsp->unack.qlen == 0)
-+              del_timer(&bcsp->tbcsp);
-+      spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+      if (i != pkts_to_be_removed)
-+              BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
-+}
-+
-+/* Handle BCSP link-establishment packets. When we
-+   detect a "sync" packet, symptom that the BT module has reset,
-+   we do nothing :) (yet) */
-+static void bcsp_handle_le_pkt(struct hci_uart *hu)
-+{
-+      struct bcsp_struct *bcsp = hu->priv;
-+      u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
-+      u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
-+      u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
-+
-+      /* spot "conf" pkts and reply with a "conf rsp" pkt */
-+      if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+                      !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
-+              struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
-+
-+              BT_DBG("Found a LE conf pkt");
-+              if (!nskb)
-+                      return;
-+              memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
-+              nskb->pkt_type = BCSP_LE_PKT;
-+
-+              skb_queue_head(&bcsp->unrel, nskb);
-+              hci_uart_tx_wakeup(hu);
-+      }
-+      /* Spot "sync" pkts. If we find one...disaster! */
-+      else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
-+                      !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
-+              BT_ERR("Found a LE sync pkt, card has reset");
-+      }
-+}
-+
-+static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
-+{
-+      const u8 c0 = 0xc0, db = 0xdb;
-+
-+      switch (bcsp->rx_esc_state) {
-+      case BCSP_ESCSTATE_NOESC:
-+              switch (byte) {
-+              case 0xdb:
-+                      bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
-+                      break;
-+              default:
-+                      memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
-+                      if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
-+                                      bcsp->rx_state != BCSP_W4_CRC)
-+                              bcsp_crc_update(&bcsp->message_crc, byte);
-+                      bcsp->rx_count--;
-+              }
-+              break;
-+
-+      case BCSP_ESCSTATE_ESC:
-+              switch (byte) {
-+              case 0xdc:
-+                      memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
-+                      if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
-+                                      bcsp->rx_state != BCSP_W4_CRC)
-+                              bcsp_crc_update(&bcsp-> message_crc, 0xc0);
-+                      bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+                      bcsp->rx_count--;
-+                      break;
-+
-+              case 0xdd:
-+                      memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
-+                      if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
-+                                      bcsp->rx_state != BCSP_W4_CRC) 
-+                              bcsp_crc_update(&bcsp-> message_crc, 0xdb);
-+                      bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+                      bcsp->rx_count--;
-+                      break;
-+
-+              default:
-+                      BT_ERR ("Invalid byte %02x after esc byte", byte);
-+                      kfree_skb(bcsp->rx_skb);
-+                      bcsp->rx_skb = NULL;
-+                      bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+                      bcsp->rx_count = 0;
-+              }
-+      }
-+}
-+
-+static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
-+{
-+      struct bcsp_struct *bcsp = hu->priv;
-+      int pass_up;
-+
-+      if (bcsp->rx_skb->data[0] & 0x80) {     /* reliable pkt */
-+              BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
-+              bcsp->rxseq_txack++;
-+              bcsp->rxseq_txack %= 0x8;
-+              bcsp->txack_req    = 1;
-+
-+              /* If needed, transmit an ack pkt */
-+              hci_uart_tx_wakeup(hu);
-+      }
-+
-+      bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
-+      BT_DBG("Request for pkt %u from card", bcsp->rxack);
-+
-+      bcsp_pkt_cull(bcsp);
-+      if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
-+                      bcsp->rx_skb->data[0] & 0x80) {
-+              bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
-+              pass_up = 1;
-+      } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
-+                      bcsp->rx_skb->data[0] & 0x80) {
-+              bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
-+              pass_up = 1;
-+      } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
-+              bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
-+              pass_up = 1;
-+      } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
-+                      !(bcsp->rx_skb->data[0] & 0x80)) {
-+              bcsp_handle_le_pkt(hu);
-+              pass_up = 0;
-+      } else
-+              pass_up = 0;
-+
-+      if (!pass_up) {
-+              if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
-+                      (bcsp->rx_skb->data[1] & 0x0f) != 1) {
-+                      BT_ERR ("Packet for unknown channel (%u %s)",
-+                              bcsp->rx_skb->data[1] & 0x0f,
-+                              bcsp->rx_skb->data[0] & 0x80 ? 
-+                              "reliable" : "unreliable");
-+              }
-+              kfree_skb(bcsp->rx_skb);
-+      } else {
-+              /* Pull out BCSP hdr */
-+              skb_pull(bcsp->rx_skb, 4);
-+
-+              hci_recv_frame(bcsp->rx_skb);
-+      }
-+      bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+      bcsp->rx_skb = NULL;
-+}
-+
-+/* Recv data */
-+static int bcsp_recv(struct hci_uart *hu, void *data, int count)
-+{
-+      struct bcsp_struct *bcsp = hu->priv;
-+      register unsigned char *ptr;
-+
-+      BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
-+              hu, count, bcsp->rx_state, bcsp->rx_count);
-+
-+      ptr = data;
-+      while (count) {
-+              if (bcsp->rx_count) {
-+                      if (*ptr == 0xc0) {
-+                              BT_ERR("Short BCSP packet");
-+                              kfree_skb(bcsp->rx_skb);
-+                              bcsp->rx_state = BCSP_W4_PKT_START;
-+                              bcsp->rx_count = 0;
-+                      } else
-+                              bcsp_unslip_one_byte(bcsp, *ptr);
-+
-+                      ptr++; count--;
-+                      continue;
-+              }
-+
-+              switch (bcsp->rx_state) {
-+              case BCSP_W4_BCSP_HDR:
-+                      if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
-+                                      bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
-+                              BT_ERR("Error in BCSP hdr checksum");
-+                              kfree_skb(bcsp->rx_skb);
-+                              bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+                              bcsp->rx_count = 0;
-+                              continue;
-+                      }
-+                      if (bcsp->rx_skb->data[0] & 0x80        /* reliable pkt */
-+                                      && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
-+                              BT_ERR ("Out-of-order packet arrived, got %u expected %u",
-+                                      bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
-+
-+                              kfree_skb(bcsp->rx_skb);
-+                              bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+                              bcsp->rx_count = 0;
-+                              continue;
-+                      }
-+                      bcsp->rx_state = BCSP_W4_DATA;
-+                      bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
-+                                      (bcsp->rx_skb->data[2] << 4);   /* May be 0 */
-+                      continue;
-+
-+              case BCSP_W4_DATA:
-+                      if (bcsp->rx_skb->data[0] & 0x40) {     /* pkt with crc */
-+                              bcsp->rx_state = BCSP_W4_CRC;
-+                              bcsp->rx_count = 2;
-+                      } else
-+                              bcsp_complete_rx_pkt(hu);
-+                      continue;
-+
-+              case BCSP_W4_CRC:
-+                      if (bcsp_crc_reverse(bcsp->message_crc) !=
-+                                      (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
-+                                      bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
-+
-+                              BT_ERR ("Checksum failed: computed %04x received %04x",
-+                                      bcsp_crc_reverse(bcsp->message_crc),
-+                                      (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
-+                                      bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
-+
-+                              kfree_skb(bcsp->rx_skb);
-+                              bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+                              bcsp->rx_count = 0;
-+                              continue;
-+                      }
-+                      skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
-+                      bcsp_complete_rx_pkt(hu);
-+                      continue;
-+
-+              case BCSP_W4_PKT_DELIMITER:
-+                      switch (*ptr) {
-+                      case 0xc0:
-+                              bcsp->rx_state = BCSP_W4_PKT_START;
-+                              break;
-+                      default:
-+                              /*BT_ERR("Ignoring byte %02x", *ptr);*/
-+                              break;
-+                      }
-+                      ptr++; count--;
-+                      break;
-+
-+              case BCSP_W4_PKT_START:
-+                      switch (*ptr) {
-+                      case 0xc0:
-+                              ptr++; count--;
-+                              break;
-+
-+                      default:
-+                              bcsp->rx_state = BCSP_W4_BCSP_HDR;
-+                              bcsp->rx_count = 4;
-+                              bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
-+                              BCSP_CRC_INIT(bcsp->message_crc);
-+                              
-+                              /* Do not increment ptr or decrement count
-+                               * Allocate packet. Max len of a BCSP pkt= 
-+                               * 0xFFF (payload) +4 (header) +2 (crc) */
-+
-+                              bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
-+                              if (!bcsp->rx_skb) {
-+                                      BT_ERR("Can't allocate mem for new packet");
-+                                      bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+                                      bcsp->rx_count = 0;
-+                                      return 0;
-+                              }
-+                              bcsp->rx_skb->dev = (void *) &hu->hdev;
-+                              break;
-+                      }
-+                      break;
-+              }
-+      }
-+      return count;
-+}
-+
-+      /* Arrange to retransmit all messages in the relq. */
-+static void bcsp_timed_event(unsigned long arg)
-+{
-+      struct hci_uart *hu = (struct hci_uart *) arg;
-+      struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
-+      struct sk_buff *skb;
-+      unsigned long flags;
-+
-+      BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
-+      spin_lock_irqsave(&bcsp->unack.lock, flags);
-+
-+      while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
-+              bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
-+              skb_queue_head(&bcsp->rel, skb);
-+      }
-+
-+      spin_unlock_irqrestore(&bcsp->unack.lock, flags);
-+
-+      hci_uart_tx_wakeup(hu);
-+}
-+
-+static int bcsp_open(struct hci_uart *hu)
-+{
-+      struct bcsp_struct *bcsp;
-+
-+      BT_DBG("hu %p", hu);
-+
-+      bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
-+      if (!bcsp)
-+              return -ENOMEM;
-+      memset(bcsp, 0, sizeof(*bcsp));
-+
-+      hu->priv = bcsp;
-+      skb_queue_head_init(&bcsp->unack);
-+      skb_queue_head_init(&bcsp->rel);
-+      skb_queue_head_init(&bcsp->unrel);
-+
-+      init_timer(&bcsp->tbcsp);
-+      bcsp->tbcsp.function = bcsp_timed_event;
-+      bcsp->tbcsp.data     = (u_long) hu;
-+
-+      bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
-+
-+      return 0;
-+}
-+
-+static int bcsp_close(struct hci_uart *hu)
-+{
-+      struct bcsp_struct *bcsp = hu->priv;
-+      hu->priv = NULL;
-+
-+      BT_DBG("hu %p", hu);
-+
-+      skb_queue_purge(&bcsp->unack);
-+      skb_queue_purge(&bcsp->rel);
-+      skb_queue_purge(&bcsp->unrel);
-+      del_timer(&bcsp->tbcsp);
-+
-+      kfree(bcsp);
-+      return 0;
-+}
-+
-+static struct hci_uart_proto bcsp = {
-+      id:      HCI_UART_BCSP,
-+      open:    bcsp_open,
-+      close:   bcsp_close,
-+      enqueue: bcsp_enqueue,
-+      dequeue: bcsp_dequeue,
-+      recv:    bcsp_recv,
-+      flush:   bcsp_flush
-+};
-+
-+int bcsp_init(void)
-+{
-+      return hci_uart_register_proto(&bcsp);
-+}
-+
-+int bcsp_deinit(void)
-+{
-+      return hci_uart_unregister_proto(&bcsp);
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_bcsp.h 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,70 @@
-+/* 
-+   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
-+   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
-+
-+   Based on
-+       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
-+       ABCSP     by Carl Orsborn <cjo@csr.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_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $
-+ */
-+
-+#ifndef __HCI_BCSP_H__
-+#define __HCI_BCSP_H__
-+
-+#define BCSP_TXWINSIZE  4
-+
-+#define BCSP_ACK_PKT    0x05
-+#define BCSP_LE_PKT     0x06
-+
-+struct bcsp_struct {
-+      struct sk_buff_head unack;      /* Unack'ed packets queue */
-+      struct sk_buff_head rel;        /* Reliable packets queue */
-+      struct sk_buff_head unrel;      /* Unreliable packets queue */
-+
-+      unsigned long rx_count;
-+      struct  sk_buff *rx_skb;
-+      u8      rxseq_txack;            /* rxseq == txack. */
-+      u8      rxack;                  /* Last packet sent by us that the peer ack'ed */
-+      struct  timer_list tbcsp;
-+      
-+      enum {
-+              BCSP_W4_PKT_DELIMITER,
-+              BCSP_W4_PKT_START,
-+              BCSP_W4_BCSP_HDR,
-+              BCSP_W4_DATA,
-+              BCSP_W4_CRC
-+      } rx_state;
-+
-+      enum {
-+              BCSP_ESCSTATE_NOESC,
-+              BCSP_ESCSTATE_ESC
-+      } rx_esc_state;
-+
-+      u16     message_crc;
-+      u8      txack_req;              /* Do we need to send ack's to the peer? */
-+
-+      /* Reliable packet sequence number - used to assign seq to each rel pkt. */
-+      u8      msgq_txseq;
-+};
-+
-+#endif        /* __HCI_BCSP_H__ */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_h4.c   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,277 @@
-+/* 
-+   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.3 2002/09/09 01:17:32 maxk Exp $    
-+ */
-+#define VERSION "1.2"
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/version.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 hci_uart *hu)
-+{
-+      struct h4_struct *h4;
-+      
-+      BT_DBG("hu %p", hu);
-+      
-+      h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
-+      if (!h4)
-+              return -ENOMEM;
-+      memset(h4, 0, sizeof(*h4));
-+
-+      skb_queue_head_init(&h4->txq);
-+
-+      hu->priv = h4;
-+      return 0;
-+}
-+
-+/* Flush protocol data */
-+static int h4_flush(struct hci_uart *hu)
-+{
-+      struct h4_struct *h4 = hu->priv;
-+
-+      BT_DBG("hu %p", hu);
-+      skb_queue_purge(&h4->txq);
-+      return 0;
-+}
-+
-+/* Close protocol */
-+static int h4_close(struct hci_uart *hu)
-+{
-+      struct h4_struct *h4 = hu->priv;
-+      hu->priv = NULL;
-+
-+      BT_DBG("hu %p", hu);
-+
-+      skb_queue_purge(&h4->txq);
-+      if (h4->rx_skb)
-+              kfree_skb(h4->rx_skb);
-+
-+      hu->priv = NULL;
-+      kfree(h4);
-+      return 0;
-+}
-+
-+/* Enqueue frame for transmittion (padding, crc, etc) */
-+static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
-+{
-+      struct h4_struct *h4 = hu->priv;
-+
-+      BT_DBG("hu %p skb %p", hu, skb);
-+
-+      /* Prepend skb with frame type */
-+      memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
-+      skb_queue_tail(&h4->txq, skb);
-+      return 0;
-+}
-+
-+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 too 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 hci_uart *hu, void *data, int count)
-+{
-+      struct h4_struct *h4 = hu->priv;
-+      register char *ptr;
-+      hci_event_hdr *eh;
-+      hci_acl_hdr   *ah;
-+      hci_sco_hdr   *sh;
-+      register int len, type, dlen;
-+
-+      BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
-+                      hu, 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);
-+                      hu->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 *) &hu->hdev;
-+              h4->rx_skb->pkt_type = type;
-+      }
-+      return count;
-+}
-+
-+static struct sk_buff *h4_dequeue(struct hci_uart *hu)
-+{
-+      struct h4_struct *h4 = hu->priv;
-+      return skb_dequeue(&h4->txq);
-+}
-+
-+static struct hci_uart_proto h4p = {
-+      id:      HCI_UART_H4,
-+      open:    h4_open,
-+      close:   h4_close,
-+      recv:    h4_recv,
-+      enqueue: h4_enqueue,
-+      dequeue: h4_dequeue,
-+      flush:   h4_flush,
-+};
-+            
-+int h4_init(void)
-+{
-+      return hci_uart_register_proto(&h4p);
-+}
-+
-+int h4_deinit(void)
-+{
-+      return hci_uart_unregister_proto(&h4p);
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_h4.h   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,44 @@
-+/* 
-+   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_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $
-+ */
-+
-+#ifdef __KERNEL__
-+struct h4_struct {
-+      unsigned long rx_state;
-+      unsigned long rx_count;
-+      struct sk_buff *rx_skb;
-+      struct sk_buff_head txq;
-+};
-+
-+/* H4 receiver States */
-+#define H4_W4_PACKET_TYPE 0
-+#define H4_W4_EVENT_HDR         1
-+#define H4_W4_ACL_HDR     2
-+#define H4_W4_SCO_HDR     3
-+#define H4_W4_DATA        4
-+
-+#endif /* __KERNEL__ */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_ldisc.c        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,580 @@
-+/* 
-+   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 driver.
-+ *
-+ * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $    
-+ */
-+#define VERSION "2.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"
-+
-+#ifndef HCI_UART_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#undef  BT_DMP
-+#define BT_DMP( A... )
-+#endif
-+
-+static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p)
-+{
-+      if (p->id >= HCI_UART_MAX_PROTO)
-+              return -EINVAL;
-+
-+      if (hup[p->id])
-+              return -EEXIST;
-+
-+      hup[p->id] = p;
-+      return 0;
-+}
-+
-+int hci_uart_unregister_proto(struct hci_uart_proto *p)
-+{
-+      if (p->id >= HCI_UART_MAX_PROTO)
-+              return -EINVAL;
-+
-+      if (!hup[p->id])
-+              return -EINVAL;
-+
-+      hup[p->id] = NULL;
-+      return 0;
-+}
-+
-+static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
-+{
-+      if (id >= HCI_UART_MAX_PROTO)
-+              return NULL;
-+      return hup[id];
-+}
-+
-+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
-+{
-+      struct hci_dev *hdev = &hu->hdev;
-+      
-+      /* Update HCI stat counters */
-+      switch (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.cmd_tx++;
-+              break;
-+      }
-+}
-+
-+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
-+{
-+      struct sk_buff *skb = hu->tx_skb;
-+      if (!skb)
-+              skb = hu->proto->dequeue(hu);
-+      else
-+              hu->tx_skb = NULL;
-+      return skb;
-+}
-+
-+int hci_uart_tx_wakeup(struct hci_uart *hu)
-+{
-+      struct tty_struct *tty = hu->tty;
-+      struct hci_dev *hdev = &hu->hdev;
-+      struct sk_buff *skb;
-+      
-+      if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
-+              set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+              return 0;
-+      }
-+
-+      BT_DBG("");
-+
-+restart:
-+      clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
-+
-+      while ((skb = hci_uart_dequeue(hu))) {
-+              int len;
-+      
-+              set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+              len = tty->driver.write(tty, 0, skb->data, skb->len);
-+              hdev->stat.byte_tx += len;
-+
-+              skb_pull(skb, len);
-+              if (skb->len) {
-+                      hu->tx_skb = skb;
-+                      break;
-+              }
-+      
-+              hci_uart_tx_complete(hu, skb->pkt_type);
-+              kfree_skb(skb);
-+      } 
-+      
-+      if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
-+              goto restart;
-+
-+      clear_bit(HCI_UART_SENDING, &hu->tx_state);
-+      return 0;
-+}
-+
-+/* ------- Interface to HCI layer ------ */
-+/* Initialize device */
-+static int hci_uart_open(struct hci_dev *hdev)
-+{
-+      BT_DBG("%s %p", hdev->name, hdev);
-+
-+      /* Nothing to do for UART driver */
-+
-+      set_bit(HCI_RUNNING, &hdev->flags);
-+      return 0;
-+}
-+
-+/* Reset device */
-+static int hci_uart_flush(struct hci_dev *hdev)
-+{
-+      struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
-+      struct tty_struct *tty = hu->tty;
-+
-+      BT_DBG("hdev %p tty %p", hdev, tty);
-+
-+      if (hu->tx_skb) {
-+              kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
-+      }
-+
-+      /* Flush any pending characters in the driver and discipline. */
-+      if (tty->ldisc.flush_buffer)
-+              tty->ldisc.flush_buffer(tty);
-+
-+      if (tty->driver.flush_buffer)
-+              tty->driver.flush_buffer(tty);
-+
-+      if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+              hu->proto->flush(hu);
-+
-+      return 0;
-+}
-+
-+/* Close device */
-+static int hci_uart_close(struct hci_dev *hdev)
-+{
-+      BT_DBG("hdev %p", hdev);
-+
-+      if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+              return 0;
-+
-+      hci_uart_flush(hdev);
-+      return 0;
-+}
-+
-+/* Send frames from HCI layer */
-+static int hci_uart_send_frame(struct sk_buff *skb)
-+{
-+      struct hci_dev* hdev = (struct hci_dev *) skb->dev;
-+      struct tty_struct *tty;
-+      struct hci_uart *hu;
-+
-+      if (!hdev) {
-+              BT_ERR("Frame for uknown device (hdev=NULL)");
-+              return -ENODEV;
-+      }
-+
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-+              return -EBUSY;
-+
-+      hu = (struct hci_uart *) hdev->driver_data;
-+      tty = hu->tty;
-+
-+      BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+      hu->proto->enqueue(hu, skb);
-+
-+      hci_uart_tx_wakeup(hu);
-+      return 0;
-+}
-+
-+static void hci_uart_destruct(struct hci_dev *hdev)
-+{
-+      struct hci_uart *hu;
-+
-+      if (!hdev) return;
-+
-+      BT_DBG("%s", hdev->name);
-+
-+      hu = (struct hci_uart *) hdev->driver_data;
-+      kfree(hu);
-+
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+/* ------ LDISC part ------ */
-+/* hci_uart_tty_open
-+ * 
-+ *     Called when line discipline changed to HCI_UART.
-+ *
-+ * Arguments:
-+ *     tty    pointer to tty info structure
-+ * Return Value:    
-+ *     0 if success, otherwise error code
-+ */
-+static int hci_uart_tty_open(struct tty_struct *tty)
-+{
-+      struct hci_uart *hu = (void *) tty->disc_data;
-+
-+      BT_DBG("tty %p", tty);
-+
-+      if (hu)
-+              return -EEXIST;
-+
-+      if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
-+              BT_ERR("Can't allocate controll structure");
-+              return -ENFILE;
-+      }
-+      memset(hu, 0, sizeof(struct hci_uart));
-+
-+      tty->disc_data = hu;
-+      hu->tty = tty;
-+
-+      spin_lock_init(&hu->rx_lock);
-+
-+      /* Flush any pending characters in the driver and line discipline */
-+      if (tty->ldisc.flush_buffer)
-+              tty->ldisc.flush_buffer(tty);
-+
-+      if (tty->driver.flush_buffer)
-+              tty->driver.flush_buffer(tty);
-+      
-+      MOD_INC_USE_COUNT;
-+      return 0;
-+}
-+
-+/* hci_uart_tty_close()
-+ *
-+ *    Called when the line discipline is changed to something
-+ *    else, the tty is closed, or the tty detects a hangup.
-+ */
-+static void hci_uart_tty_close(struct tty_struct *tty)
-+{
-+      struct hci_uart *hu = (void *)tty->disc_data;
-+
-+      BT_DBG("tty %p", tty);
-+
-+      /* Detach from the tty */
-+      tty->disc_data = NULL;
-+
-+      if (hu) {
-+              struct hci_dev *hdev = &hu->hdev;
-+              hci_uart_close(hdev);
-+
-+              if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+                      hu->proto->close(hu);
-+                      hci_unregister_dev(hdev);
-+              }
-+
-+              MOD_DEC_USE_COUNT;
-+      }
-+}
-+
-+/* hci_uart_tty_wakeup()
-+ *
-+ *    Callback for transmit wakeup. Called when low level
-+ *    device driver can accept more send data.
-+ *
-+ * Arguments:        tty    pointer to associated tty instance data
-+ * Return Value:    None
-+ */
-+static void hci_uart_tty_wakeup(struct tty_struct *tty)
-+{
-+      struct hci_uart *hu = (void *)tty->disc_data;
-+
-+      BT_DBG("");
-+
-+      if (!hu)
-+              return;
-+
-+      clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-+
-+      if (tty != hu->tty)
-+              return;
-+
-+      if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+              hci_uart_tx_wakeup(hu);
-+}
-+
-+/* hci_uart_tty_room()
-+ * 
-+ *    Callback function from tty driver. Return the amount of 
-+ *    space left in the receiver's buffer to decide if remote
-+ *    transmitter is to be throttled.
-+ *
-+ * Arguments:        tty    pointer to associated tty instance data
-+ * Return Value:    number of bytes left in receive buffer
-+ */
-+static int hci_uart_tty_room (struct tty_struct *tty)
-+{
-+      return 65536;
-+}
-+
-+/* hci_uart_tty_receive()
-+ * 
-+ *     Called by tty low level driver when receive data is
-+ *     available.
-+ *     
-+ * Arguments:  tty          pointer to tty isntance data
-+ *             data         pointer to received data
-+ *             flags        pointer to flags for data
-+ *             count        count of received data in bytes
-+ *     
-+ * Return Value:    None
-+ */
-+static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
-+{
-+      struct hci_uart *hu = (void *)tty->disc_data;
-+      
-+      if (!hu || tty != hu->tty)
-+              return;
-+
-+      if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+              return;
-+      
-+      spin_lock(&hu->rx_lock);
-+      hu->proto->recv(hu, (void *) data, count);
-+      hu->hdev.stat.byte_rx += count;
-+      spin_unlock(&hu->rx_lock);
-+
-+      if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
-+              tty->driver.unthrottle(tty);
-+}
-+
-+static int hci_uart_register_dev(struct hci_uart *hu)
-+{
-+      struct hci_dev *hdev;
-+
-+      BT_DBG("");
-+
-+      /* Initialize and register HCI device */
-+      hdev = &hu->hdev;
-+
-+      hdev->type = HCI_UART;
-+      hdev->driver_data = hu;
-+
-+      hdev->open  = hci_uart_open;
-+      hdev->close = hci_uart_close;
-+      hdev->flush = hci_uart_flush;
-+      hdev->send  = hci_uart_send_frame;
-+      hdev->destruct = hci_uart_destruct;
-+
-+      if (hci_register_dev(hdev) < 0) {
-+              BT_ERR("Can't register HCI device %s", hdev->name);
-+              return -ENODEV;
-+      }
-+      MOD_INC_USE_COUNT;
-+      return 0;
-+}
-+
-+static int hci_uart_set_proto(struct hci_uart *hu, int id)
-+{
-+      struct hci_uart_proto *p;
-+      int err;        
-+      
-+      p = hci_uart_get_proto(id);
-+      if (!p)
-+              return -EPROTONOSUPPORT;
-+
-+      err = p->open(hu);
-+      if (err)
-+              return err;
-+
-+      hu->proto = p;
-+
-+      err = hci_uart_register_dev(hu);
-+      if (err) {
-+              p->close(hu);
-+              return err;
-+      }
-+      return 0;
-+}
-+
-+/* hci_uart_tty_ioctl()
-+ *
-+ *    Process IOCTL system call for the tty device.
-+ *
-+ * Arguments:
-+ *
-+ *    tty        pointer to tty instance data
-+ *    file       pointer to open file object for device
-+ *    cmd        IOCTL command code
-+ *    arg        argument for IOCTL call (cmd dependent)
-+ *
-+ * Return Value:    Command dependent
-+ */
-+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
-+                            unsigned int cmd, unsigned long arg)
-+{
-+      struct hci_uart *hu = (void *)tty->disc_data;
-+      int err = 0;
-+
-+      BT_DBG("");
-+
-+      /* Verify the status of the device */
-+      if (!hu)
-+              return -EBADF;
-+
-+      switch (cmd) {
-+      case HCIUARTSETPROTO:
-+              if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
-+                      err = hci_uart_set_proto(hu, arg);
-+                      if (err) {
-+                              clear_bit(HCI_UART_PROTO_SET, &hu->flags);
-+                              return err;
-+                      }
-+                      tty->low_latency = 1;
-+              } else  
-+                      return -EBUSY;
-+
-+      case HCIUARTGETPROTO:
-+              if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
-+                      return hu->proto->id;
-+              return -EUNATCH;
-+              
-+      default:
-+              err = n_tty_ioctl(tty, file, cmd, arg);
-+              break;
-+      };
-+
-+      return err;
-+}
-+
-+/*
-+ * We don't provide read/write/poll interface for user space.
-+ */
-+static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
-+{
-+      return 0;
-+}
-+static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
-+{
-+      return 0;
-+}
-+static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
-+{
-+      return 0;
-+}
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+int h4_init(void);
-+int h4_deinit(void);
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+int bcsp_init(void);
-+int bcsp_deinit(void);
-+#endif
-+
-+int __init hci_uart_init(void)
-+{
-+      static struct tty_ldisc hci_uart_ldisc;
-+      int err;
-+
-+      BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
-+              VERSION);
-+      BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+
-+      /* Register the tty discipline */
-+
-+      memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
-+      hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
-+      hci_uart_ldisc.name        = "n_hci";
-+      hci_uart_ldisc.open        = hci_uart_tty_open;
-+      hci_uart_ldisc.close       = hci_uart_tty_close;
-+      hci_uart_ldisc.read        = hci_uart_tty_read;
-+      hci_uart_ldisc.write       = hci_uart_tty_write;
-+      hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
-+      hci_uart_ldisc.poll        = hci_uart_tty_poll;
-+      hci_uart_ldisc.receive_room= hci_uart_tty_room;
-+      hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
-+      hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
-+
-+      if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
-+              BT_ERR("Can't register HCI line discipline (%d)", err);
-+              return err;
-+      }
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+      h4_init();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+      bcsp_init();
-+#endif
-+      
-+      return 0;
-+}
-+
-+void hci_uart_cleanup(void)
-+{
-+      int err;
-+
-+#ifdef CONFIG_BLUEZ_HCIUART_H4
-+      h4_deinit();
-+#endif
-+#ifdef CONFIG_BLUEZ_HCIUART_BCSP
-+      bcsp_deinit();
-+#endif
-+
-+      /* Release tty registration of line discipline */
-+      if ((err = tty_register_ldisc(N_HCI, NULL)))
-+              BT_ERR("Can't unregister HCI line discipline (%d)", err);
-+}
-+
-+module_init(hci_uart_init);
-+module_exit(hci_uart_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
-+MODULE_LICENSE("GPL");
---- linux/drivers/bluetooth/hci_uart.c~bluetooth-2.4.18-mh11
-+++ linux/drivers/bluetooth/hci_uart.c
--/* 
--   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 driver.
-- *
-- * $Id: hci_uart.c,v 1.5 2001/07/05 18:42:44 maxk Exp $    
-- */
--#define VERSION "1.0"
--
--#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/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_uart.h>
--
--#ifndef HCI_UART_DEBUG
--#undef  DBG
--#define DBG( A... )
--#undef  DMP
--#define DMP( A... )
--#endif
--
--/* ------- Interface to HCI layer ------ */
--/* Initialize device */
--int n_hci_open(struct hci_dev *hdev)
--{
--      DBG("%s %p", hdev->name, hdev);
--
--      /* Nothing to do for UART driver */
--
--      hdev->flags |= HCI_RUNNING;
--
--      return 0;
--}
--
--/* Reset device */
--int n_hci_flush(struct hci_dev *hdev)
--{
--      struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
--      struct tty_struct *tty = n_hci->tty;
--
--      DBG("hdev %p tty %p", hdev, tty);
--
--      /* Drop TX queue */
--      skb_queue_purge(&n_hci->txq);
--
--      /* Flush any pending characters in the driver and discipline. */
--      if (tty->ldisc.flush_buffer)
--              tty->ldisc.flush_buffer(tty);
--
--      if (tty->driver.flush_buffer)
--              tty->driver.flush_buffer(tty);
--
--      return 0;
--}
--
--/* Close device */
--int n_hci_close(struct hci_dev *hdev)
--{
--      DBG("hdev %p", hdev);
--
--      hdev->flags &= ~HCI_RUNNING;
--
--      n_hci_flush(hdev);
--
--      return 0;
--}
--
--int n_hci_tx_wakeup(struct n_hci *n_hci)
--{
--      register struct tty_struct *tty = n_hci->tty;
--
--      if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
--              set_bit(TRANS_WAKEUP, &n_hci->tx_state);
--              return 0;
--      }
--
--      DBG("");
--      do {
--              register struct sk_buff *skb;
--              register int len;
--
--              clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
--
--              if (!(skb = skb_dequeue(&n_hci->txq)))
--                      break;
--
--              DMP(skb->data, skb->len);
--
--              /* Send frame to TTY driver */
--              tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
--              len = tty->driver.write(tty, 0, skb->data, skb->len);
--
--              n_hci->hdev.stat.byte_tx += len;
--
--              DBG("sent %d", len);
--
--              if (len == skb->len) {
--                      /* Full frame was sent */
--                      kfree_skb(skb);
--              } else {
--                      /* Subtract sent part and requeue  */
--                      skb_pull(skb, len);
--                      skb_queue_head(&n_hci->txq, skb);
--              }
--      } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
--      clear_bit(TRANS_SENDING, &n_hci->tx_state);
--
--      return 0;
--}
--
--/* Send frames from HCI layer */
--int n_hci_send_frame(struct sk_buff *skb)
--{
--      struct hci_dev* hdev = (struct hci_dev *) skb->dev;
--      struct tty_struct *tty;
--      struct n_hci *n_hci;
--
--      if (!hdev) {
--              ERR("Frame for uknown device (hdev=NULL)");
--              return -ENODEV;
--      }
--
--      if (!(hdev->flags & HCI_RUNNING))
--              return -EBUSY;
--
--      n_hci = (struct n_hci *) hdev->driver_data;
--      tty = n_hci2tty(n_hci);
--
--      DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
--      switch (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.cmd_tx++;
--                        break;
--      };
--
--      /* Prepend skb with frame type and queue */
--      memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
--      skb_queue_tail(&n_hci->txq, skb);
--
--      n_hci_tx_wakeup(n_hci);
--
--      return 0;
--}
--
--/* ------ LDISC part ------ */
--
--/* n_hci_tty_open
-- * 
-- *     Called when line discipline changed to N_HCI.
-- *     
-- * Arguments:    
-- *     tty    pointer to tty info structure
-- * Return Value:    
-- *     0 if success, otherwise error code
-- */
--static int n_hci_tty_open(struct tty_struct *tty)
--{
--      struct n_hci *n_hci = tty2n_hci(tty);
--      struct hci_dev *hdev;
--
--      DBG("tty %p", tty);
--
--      if (n_hci)
--              return -EEXIST;
--
--      if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
--              ERR("Can't allocate controll structure");
--              return -ENFILE;
--      }
--      memset(n_hci, 0, sizeof(struct n_hci));
--
--      /* Initialize and register HCI device */
--      hdev = &n_hci->hdev;
--
--      hdev->type = HCI_UART;
--      hdev->driver_data = n_hci;
--
--      hdev->open  = n_hci_open;
--      hdev->close = n_hci_close;
--      hdev->flush = n_hci_flush;
--      hdev->send  = n_hci_send_frame;
--
--      if (hci_register_dev(hdev) < 0) {
--              ERR("Can't register HCI device %s", hdev->name);
--              kfree(n_hci);
--              return -ENODEV;
--      }
--
--      tty->disc_data = n_hci;
--      n_hci->tty = tty;
--
--      spin_lock_init(&n_hci->rx_lock);
--      n_hci->rx_state = WAIT_PACKET_TYPE;
--
--      skb_queue_head_init(&n_hci->txq);
--
--      MOD_INC_USE_COUNT;
--
--      /* Flush any pending characters in the driver and discipline. */
--      if (tty->ldisc.flush_buffer)
--              tty->ldisc.flush_buffer(tty);
--
--      if (tty->driver.flush_buffer)
--              tty->driver.flush_buffer(tty);
--
--      return 0;
--}
--
--/* n_hci_tty_close()
-- *
-- *    Called when the line discipline is changed to something
-- *    else, the tty is closed, or the tty detects a hangup.
-- */
--static void n_hci_tty_close(struct tty_struct *tty)
--{
--      struct n_hci *n_hci = tty2n_hci(tty);
--      struct hci_dev *hdev = &n_hci->hdev;
--
--      DBG("tty %p hdev %p", tty, hdev);
--
--      if (n_hci != NULL) {
--              n_hci_close(hdev);
--
--              if (hci_unregister_dev(hdev) < 0) {
--                      ERR("Can't unregister HCI device %s",hdev->name);
--              }
--
--              hdev->driver_data = NULL;
--              tty->disc_data = NULL;
--              kfree(n_hci);
--
--              MOD_DEC_USE_COUNT;
--      }
--}
--
--/* n_hci_tty_wakeup()
-- *
-- *    Callback for transmit wakeup. Called when low level
-- *    device driver can accept more send data.
-- *
-- * Arguments:        tty    pointer to associated tty instance data
-- * Return Value:    None
-- */
--static void n_hci_tty_wakeup( struct tty_struct *tty )
--{
--      struct n_hci *n_hci = tty2n_hci(tty);
--
--      DBG("");
--
--      if (!n_hci)
--              return;
--
--      tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
--
--      if (tty != n_hci->tty)
--              return;
--
--      n_hci_tx_wakeup(n_hci);
--}
--
--/* n_hci_tty_room()
-- * 
-- *    Callback function from tty driver. Return the amount of 
-- *    space left in the receiver's buffer to decide if remote
-- *    transmitter is to be throttled.
-- *
-- * Arguments:        tty    pointer to associated tty instance data
-- * Return Value:    number of bytes left in receive buffer
-- */
--static int n_hci_tty_room (struct tty_struct *tty)
--{
--      return 65536;
--}
--
--static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
--{
--      register int room = skb_tailroom(n_hci->rx_skb);
--
--      DBG("len %d room %d", len, room);
--      if (!len) {
--              DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
--              hci_recv_frame(n_hci->rx_skb);
--      } else if (len > room) {
--              ERR("Data length is to large");
--              kfree_skb(n_hci->rx_skb);
--              n_hci->hdev.stat.err_rx++;
--      } else {
--              n_hci->rx_state = WAIT_DATA;
--              n_hci->rx_count = len;
--              return len;
--      }
--
--      n_hci->rx_state = WAIT_PACKET_TYPE;
--      n_hci->rx_skb   = NULL;
--      n_hci->rx_count = 0;
--      return 0;
--}
--
--static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
--{
--      register const char *ptr;
--      hci_event_hdr *eh;
--      hci_acl_hdr   *ah;
--      hci_sco_hdr   *sh;
--      register int len, type, dlen;
--
--      DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
--
--      n_hci->hdev.stat.byte_rx += count;
--
--      ptr = data;
--      while (count) {
--              if (n_hci->rx_count) {
--                      len = MIN(n_hci->rx_count, count);
--                      memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
--                      n_hci->rx_count -= len; count -= len; ptr += len;
--
--                      if (n_hci->rx_count)
--                              continue;
--
--                      switch (n_hci->rx_state) {
--                              case WAIT_DATA:
--                                      DBG("Complete data");
--
--                                      DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
--
--                                      hci_recv_frame(n_hci->rx_skb);
--
--                                      n_hci->rx_state = WAIT_PACKET_TYPE;
--                                      n_hci->rx_skb = NULL;
--                                      continue;
--
--                              case WAIT_EVENT_HDR:
--                                      eh = (hci_event_hdr *) n_hci->rx_skb->data;
--
--                                      DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
--
--                                      n_hci_check_data_len(n_hci, eh->plen);
--                                      continue;
--
--                              case WAIT_ACL_HDR:
--                                      ah = (hci_acl_hdr *) n_hci->rx_skb->data;
--                                      dlen = __le16_to_cpu(ah->dlen);
--
--                                      DBG("ACL header: dlen %d", dlen);
--
--                                      n_hci_check_data_len(n_hci, dlen);
--                                      continue;
--
--                              case WAIT_SCO_HDR:
--                                      sh = (hci_sco_hdr *) n_hci->rx_skb->data;
--
--                                      DBG("SCO header: dlen %d", sh->dlen);
--
--                                      n_hci_check_data_len(n_hci, sh->dlen);
--                                      continue;
--                      };
--              }
--
--              /* WAIT_PACKET_TYPE */
--              switch (*ptr) {
--                      case HCI_EVENT_PKT:
--                              DBG("Event packet");
--                              n_hci->rx_state = WAIT_EVENT_HDR;
--                              n_hci->rx_count = HCI_EVENT_HDR_SIZE;
--                              type = HCI_EVENT_PKT;
--                              break;
--
--                      case HCI_ACLDATA_PKT:
--                              DBG("ACL packet");
--                              n_hci->rx_state = WAIT_ACL_HDR;
--                              n_hci->rx_count = HCI_ACL_HDR_SIZE;
--                              type = HCI_ACLDATA_PKT;
--                              break;
--
--                      case HCI_SCODATA_PKT:
--                              DBG("SCO packet");
--                              n_hci->rx_state = WAIT_SCO_HDR;
--                              n_hci->rx_count = HCI_SCO_HDR_SIZE;
--                              type = HCI_SCODATA_PKT;
--                              break;
--
--                      default:
--                              ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
--                              n_hci->hdev.stat.err_rx++;
--                              ptr++; count--;
--                              continue;
--              };
--              ptr++; count--;
--
--              /* Allocate packet */
--              if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
--                      ERR("Can't allocate mem for new packet");
--
--                      n_hci->rx_state = WAIT_PACKET_TYPE;
--                      n_hci->rx_count = 0;
--                      return;
--              }
--              n_hci->rx_skb->dev = (void *) &n_hci->hdev;
--              n_hci->rx_skb->pkt_type = type;
--      }
--}
--
--/* n_hci_tty_receive()
-- * 
-- *     Called by tty low level driver when receive data is
-- *     available.
-- *     
-- * Arguments:  tty          pointer to tty isntance data
-- *             data         pointer to received data
-- *             flags        pointer to flags for data
-- *             count        count of received data in bytes
-- *     
-- * Return Value:    None
-- */
--static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
--{
--      struct n_hci *n_hci = tty2n_hci(tty);
--
--      if (!n_hci || tty != n_hci->tty)
--              return;
--
--      spin_lock(&n_hci->rx_lock);
--      n_hci_rx(n_hci, data, flags, count);
--      spin_unlock(&n_hci->rx_lock);
--
--      if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
--              tty->driver.unthrottle(tty);
--}
--
--/* n_hci_tty_ioctl()
-- *
-- *    Process IOCTL system call for the tty device.
-- *
-- * Arguments:
-- *
-- *    tty        pointer to tty instance data
-- *    file       pointer to open file object for device
-- *    cmd        IOCTL command code
-- *    arg        argument for IOCTL call (cmd dependent)
-- *
-- * Return Value:    Command dependent
-- */
--static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
--                            unsigned int cmd, unsigned long arg)
--{
--      struct n_hci *n_hci = tty2n_hci(tty);
--      int error = 0;
--
--      DBG("");
--
--      /* Verify the status of the device */
--      if (!n_hci)
--              return -EBADF;
--
--      switch (cmd) {
--              default:
--                      error = n_tty_ioctl(tty, file, cmd, arg);
--                      break;
--      };
--
--      return error;
--}
--
--/*
-- * We don't provide read/write/poll interface for user space.
-- */
--static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
--{
--      return 0;
--}
--static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
--{
--      return 0;
--}
--static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
--{
--      return 0;
--}
--
--int __init n_hci_init(void)
--{
--      static struct tty_ldisc n_hci_ldisc;
--      int err;
--
--      INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
--              VERSION);
--      INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
--      /* Register the tty discipline */
--
--      memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
--      n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
--      n_hci_ldisc.name        = "n_hci";
--      n_hci_ldisc.open        = n_hci_tty_open;
--      n_hci_ldisc.close       = n_hci_tty_close;
--      n_hci_ldisc.read        = n_hci_tty_read;
--      n_hci_ldisc.write       = n_hci_tty_write;
--      n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
--      n_hci_ldisc.poll        = n_hci_tty_poll;
--      n_hci_ldisc.receive_room= n_hci_tty_room;
--      n_hci_ldisc.receive_buf = n_hci_tty_receive;
--      n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
--
--      if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
--              ERR("Can't register HCI line discipline (%d)", err);
--              return err;
--      }
--
--      return 0;
--}
--
--void n_hci_cleanup(void)
--{
--      int err;
--
--      /* Release tty registration of line discipline */
--      if ((err = tty_register_ldisc(N_HCI, NULL)))
--              ERR("Can't unregister HCI line discipline (%d)", err);
--}
--
--module_init(n_hci_init);
--module_exit(n_hci_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
--MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_uart.h 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,81 @@
-+/* 
-+   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.2 2002/09/09 01:17:32 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 hci_uart;
-+
-+struct hci_uart_proto {
-+      unsigned int id;
-+      int (*open)(struct hci_uart *hu);
-+      int (*close)(struct hci_uart *hu);
-+      int (*flush)(struct hci_uart *hu);
-+      int (*recv)(struct hci_uart *hu, void *data, int len);
-+      int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
-+      struct sk_buff *(*dequeue)(struct hci_uart *hu);
-+};
-+
-+struct hci_uart {
-+      struct tty_struct  *tty;
-+      struct hci_dev     hdev;
-+      unsigned long      flags;
-+
-+      struct hci_uart_proto *proto;
-+      void               *priv;
-+      
-+      struct sk_buff     *tx_skb;
-+      unsigned long      tx_state;
-+      spinlock_t         rx_lock;
-+};
-+
-+/* HCI_UART flag bits */
-+#define HCI_UART_PROTO_SET            0
-+
-+/* TX states  */
-+#define HCI_UART_SENDING              1
-+#define HCI_UART_TX_WAKEUP            2
-+
-+int hci_uart_register_proto(struct hci_uart_proto *p);
-+int hci_uart_unregister_proto(struct hci_uart_proto *p);
-+int hci_uart_tx_wakeup(struct hci_uart *hu);
-+
-+#endif /* __KERNEL__ */
---- linux/drivers/bluetooth/hci_usb.c~bluetooth-2.4.18-mh11    2001-09-07 18:28:38.000000000 +0200
-+++ linux/drivers/bluetooth/hci_usb.c  2004-01-25 23:37:39.000000000 +0100
-@@ -1,9 +1,10 @@
- /* 
--   BlueZ - Bluetooth protocol stack for Linux
-+   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-    Copyright (C) 2000-2001 Qualcomm Incorporated
--
-    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2003 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;
-@@ -23,598 +24,914 @@
- */
- /*
-- * BlueZ HCI USB driver.
-  * Based on original USB Bluetooth driver for Linux kernel
-  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
-  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
-  *
-- * $Id: hci_usb.c,v 1.5 2001/07/05 18:42:44 maxk Exp $    
-+ * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
-  */
--#define VERSION "1.0"
-+#define VERSION "2.4"
- #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/unistd.h>
- #include <linux/types.h>
--#include <linux/fcntl.h>
- #include <linux/interrupt.h>
--#include <linux/ptrace.h>
--#include <linux/poll.h>
- #include <linux/slab.h>
--#include <linux/tty.h>
- #include <linux/errno.h>
- #include <linux/string.h>
--#include <linux/signal.h>
--#include <linux/ioctl.h>
- #include <linux/skbuff.h>
- #include <linux/usb.h>
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_usb.h>
-+
-+#include "hci_usb.h"
- #ifndef HCI_USB_DEBUG
--#undef  DBG
--#define DBG( A... )
--#undef  DMP
--#define DMP( A... )
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#undef  BT_DMP
-+#define BT_DMP( A... )
- #endif
--static struct usb_device_id usb_bluetooth_ids [] = {
-+#ifndef CONFIG_BLUEZ_HCIUSB_ZERO_PACKET
-+#undef  USB_ZERO_PACKET
-+#define USB_ZERO_PACKET 0
-+#endif
-+
-+static struct usb_driver hci_usb_driver; 
-+
-+static struct usb_device_id bluetooth_ids[] = {
-+      /* Digianswer device */
-+      { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER },
-+
-+      /* Generic Bluetooth USB device */
-       { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
-+
-+      /* Ericsson with non-standard id */
-+      { USB_DEVICE(0x0bdb, 0x1002) },
-+
-+      /* ALPS Module with non-standard id */
-+      { USB_DEVICE(0x044e, 0x3002) },
-+
-+      /* Bluetooth Ultraport Module from IBM */
-+      { USB_DEVICE(0x04bf, 0x030a) },
-+
-       { }     /* Terminating entry */
- };
--MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
-+MODULE_DEVICE_TABLE (usb, bluetooth_ids);
--static int hci_usb_ctrl_msg(struct hci_usb *husb,  struct sk_buff *skb);
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
-+static struct usb_device_id ignore_ids[] = {
-+      /* Broadcom BCM2033 without firmware */
-+      { USB_DEVICE(0x0a5c, 0x2033) },
--static void hci_usb_unlink_urbs(struct hci_usb *husb)
--{
--      usb_unlink_urb(husb->read_urb);
--      usb_unlink_urb(husb->intr_urb);
--      usb_unlink_urb(husb->ctrl_urb);
--      usb_unlink_urb(husb->write_urb);
--}
-+      { }     /* Terminating entry */
-+};
--static void hci_usb_free_bufs(struct hci_usb *husb)
-+struct _urb *_urb_alloc(int isoc, int gfp)
- {
--      if (husb->read_urb) {
--              if (husb->read_urb->transfer_buffer)
--                      kfree(husb->read_urb->transfer_buffer);
--              usb_free_urb(husb->read_urb);
-+      struct _urb *_urb = kmalloc(sizeof(struct _urb) +
-+                              sizeof(iso_packet_descriptor_t) * isoc, gfp);
-+      if (_urb) {
-+              memset(_urb, 0, sizeof(*_urb));
-+              spin_lock_init(&_urb->urb.lock);
-       }
-+      return _urb;
-+}
--      if (husb->intr_urb) {
--              if (husb->intr_urb->transfer_buffer)
--                      kfree(husb->intr_urb->transfer_buffer);
--              usb_free_urb(husb->intr_urb);
-+struct _urb *_urb_dequeue(struct _urb_queue *q)
-+{
-+      struct _urb *_urb = NULL;
-+        unsigned long flags;
-+        spin_lock_irqsave(&q->lock, flags);
-+      {
-+              struct list_head *head = &q->head;
-+              struct list_head *next = head->next;
-+              if (next != head) {
-+                      _urb = list_entry(next, struct _urb, list);
-+                      list_del(next); _urb->queue = NULL;
-+              }
-       }
-+      spin_unlock_irqrestore(&q->lock, flags);
-+      return _urb;
-+}
--      if (husb->ctrl_urb)
--              usb_free_urb(husb->ctrl_urb);
-+static void hci_usb_rx_complete(struct urb *urb);
-+static void hci_usb_tx_complete(struct urb *urb);
--      if (husb->write_urb)
--              usb_free_urb(husb->write_urb);
-+#define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
-+#define __pending_q(husb, type)   (&husb->pending_q[type-1])
-+#define __completed_q(husb, type) (&husb->completed_q[type-1])
-+#define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
-+#define __reassembly(husb, type)  (husb->reassembly[type-1])
--      if (husb->intr_skb)
--              kfree_skb(husb->intr_skb);
-+static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
-+{
-+      return _urb_dequeue(__completed_q(husb, type)); 
- }
--/* ------- Interface to HCI layer ------ */
--/* Initialize device */
--int hci_usb_open(struct hci_dev *hdev)
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
- {
--      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
--      int status;
--
--      DBG("%s", hdev->name);
--
--      husb->read_urb->dev = husb->udev;
--      if ((status = usb_submit_urb(husb->read_urb)))
--              DBG("read submit failed. %d", status);
--
--      husb->intr_urb->dev = husb->udev;
--      if ((status = usb_submit_urb(husb->intr_urb)))
--              DBG("interrupt submit failed. %d", status);
-+      int offset = 0, i;
--      hdev->flags |= HCI_RUNNING;
-+      BT_DBG("len %d mtu %d", len, mtu);
--      return 0;
-+      for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
-+              urb->iso_frame_desc[i].offset = offset;
-+              urb->iso_frame_desc[i].length = mtu;
-+              BT_DBG("desc %d offset %d len %d", i, offset, mtu);
-+      }
-+      if (len && i < HCI_MAX_ISOC_FRAMES) {
-+              urb->iso_frame_desc[i].offset = offset;
-+              urb->iso_frame_desc[i].length = len;
-+              BT_DBG("desc %d offset %d len %d", i, offset, len);
-+              i++;
-+      }
-+      urb->number_of_packets = i;
- }
-+#endif
--/* Reset device */
--int hci_usb_flush(struct hci_dev *hdev)
-+static int hci_usb_intr_rx_submit(struct hci_usb *husb)
- {
--      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+      struct _urb *_urb;
-+      struct urb *urb;
-+      int err, pipe, interval, size;
-+      void *buf;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", husb->hdev.name);
--      /* Drop TX queues */
--      skb_queue_purge(&husb->tx_ctrl_q);
--      skb_queue_purge(&husb->tx_write_q);
-+        size = husb->intr_in_ep->wMaxPacketSize;
--      return 0;
-+      buf = kmalloc(size, GFP_ATOMIC);
-+      if (!buf)
-+              return -ENOMEM;
-+
-+      _urb = _urb_alloc(0, GFP_ATOMIC);
-+      if (!_urb) {
-+              kfree(buf);
-+              return -ENOMEM;
-+      }
-+      _urb->type = HCI_EVENT_PKT;
-+      _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+
-+      urb = &_urb->urb;
-+      pipe     = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
-+      interval = husb->intr_in_ep->bInterval;
-+      FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
-+      
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s intr rx submit failed urb %p err %d",
-+                              husb->hdev.name, urb, err);
-+              _urb_unlink(_urb);
-+              _urb_free(_urb);
-+              kfree(buf);
-+      }
-+      return err;
- }
--/* Close device */
--int hci_usb_close(struct hci_dev *hdev)
-+static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
- {
--      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+      struct _urb *_urb;
-+      struct urb *urb;
-+      int err, pipe, size = HCI_MAX_FRAME_SIZE;
-+      void *buf;
--      DBG("%s", hdev->name);
-+      buf = kmalloc(size, GFP_ATOMIC);
-+      if (!buf)
-+              return -ENOMEM;
--      hdev->flags &= ~HCI_RUNNING;
--      hci_usb_unlink_urbs(husb);
-+      _urb = _urb_alloc(0, GFP_ATOMIC);
-+      if (!_urb) {
-+              kfree(buf);
-+              return -ENOMEM;
-+      }
-+      _urb->type = HCI_ACLDATA_PKT;
-+      _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
--      hci_usb_flush(hdev);
-+      urb  = &_urb->urb;
-+      pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
-+        FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
-+        urb->transfer_flags = USB_QUEUE_BULK;
--      return 0;
-+      BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s bulk rx submit failed urb %p err %d",
-+                              husb->hdev.name, urb, err);
-+              _urb_unlink(_urb);
-+              _urb_free(_urb);
-+              kfree(buf);
-+      }
-+      return err;
- }
--void hci_usb_ctrl_wakeup(struct hci_usb *husb)
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
- {
--      struct sk_buff *skb;
--
--      if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
--              return;
-+      struct _urb *_urb;
-+      struct urb *urb;
-+      int err, mtu, size;
-+      void *buf;
--      DBG("%s", husb->hdev.name);
-+      mtu  = husb->isoc_in_ep->wMaxPacketSize;
-+        size = mtu * HCI_MAX_ISOC_FRAMES;
--      if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
--              goto done;
-+      buf = kmalloc(size, GFP_ATOMIC);
-+      if (!buf)
-+              return -ENOMEM;
--      if (hci_usb_ctrl_msg(husb, skb)){
--              kfree_skb(skb);
--              goto done;
-+      _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+      if (!_urb) {
-+              kfree(buf);
-+              return -ENOMEM;
-       }
-+      _urb->type = HCI_SCODATA_PKT;
-+      _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
--      DMP(skb->data, skb->len);
-+      urb = &_urb->urb;
--      husb->hdev.stat.byte_tx += skb->len;
--      return;
-+      urb->context  = husb;
-+      urb->dev      = husb->udev;
-+      urb->pipe     = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
-+      urb->complete = hci_usb_rx_complete;
--done:
--      clear_bit(HCI_TX_CTRL, &husb->tx_state);
--      return;
-+      urb->transfer_buffer_length = size;
-+      urb->transfer_buffer = buf;
-+      urb->transfer_flags  = USB_ISO_ASAP;
-+
-+      __fill_isoc_desc(urb, size, mtu);
-+
-+      BT_DBG("%s urb %p", husb->hdev.name, urb);
-+
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s isoc rx submit failed urb %p err %d",
-+                              husb->hdev.name, urb, err);
-+              _urb_unlink(_urb);
-+              _urb_free(_urb);
-+              kfree(buf);
-+      }
-+      return err;
- }
-+#endif
--void hci_usb_write_wakeup(struct hci_usb *husb)
-+/* Initialize device */
-+static int hci_usb_open(struct hci_dev *hdev)
- {
--      struct sk_buff *skb;
-+      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+      int i, err;
-+      unsigned long flags;
--      if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
--              return;
-+      BT_DBG("%s", hdev->name);
--      DBG("%s", husb->hdev.name);
-+      if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
-+              return 0;
--      if (!(skb = skb_dequeue(&husb->tx_write_q)))
--              goto done;
-+      MOD_INC_USE_COUNT;
--      if (hci_usb_write_msg(husb, skb)) {
--              skb_queue_head(&husb->tx_write_q, skb);
--              goto done;
-+      write_lock_irqsave(&husb->completion_lock, flags);
-+
-+      err = hci_usb_intr_rx_submit(husb);
-+      if (!err) {
-+              for (i = 0; i < HCI_MAX_BULK_RX; i++)
-+                      hci_usb_bulk_rx_submit(husb);
-+
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+              if (husb->isoc_iface)
-+                      for (i = 0; i < HCI_MAX_ISOC_RX; i++)
-+                              hci_usb_isoc_rx_submit(husb);
-+#endif
-+      } else {
-+              clear_bit(HCI_RUNNING, &hdev->flags);
-+              MOD_DEC_USE_COUNT;
-       }
--      DMP(skb->data, skb->len);
-+      write_unlock_irqrestore(&husb->completion_lock, flags);
-+      return err;
-+}
--      husb->hdev.stat.byte_tx += skb->len;
--      return;
-+/* Reset device */
-+static int hci_usb_flush(struct hci_dev *hdev)
-+{
-+      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+      int i;
--done:
--      clear_bit(HCI_TX_WRITE, &husb->tx_state);
--      return;
-+      BT_DBG("%s", hdev->name);
-+
-+      for (i=0; i < 4; i++)
-+              skb_queue_purge(&husb->transmit_q[i]);
-+      return 0;
- }
--/* Send frames from HCI layer */
--int hci_usb_send_frame(struct sk_buff *skb)
-+static void hci_usb_unlink_urbs(struct hci_usb *husb)
- {
--      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--      struct hci_usb *husb;
-+      int i;
--      if (!hdev) {
--              ERR("frame for uknown device (hdev=NULL)");
--              return -ENODEV;
--      }
-+      BT_DBG("%s", husb->hdev.name);
--      if (!(hdev->flags & HCI_RUNNING))
--              return 0;
-+      for (i=0; i < 4; i++) {
-+              struct _urb *_urb;
-+              struct urb *urb;
--      husb = (struct hci_usb *) hdev->driver_data;
-+              /* Kill pending requests */
-+              while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
-+                      urb = &_urb->urb;
-+                      BT_DBG("%s unlinking _urb %p type %d urb %p", 
-+                                      husb->hdev.name, _urb, _urb->type, urb);
-+                      usb_unlink_urb(urb);
-+                      _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+              }
--      DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+              /* Release completed requests */
-+              while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
-+                      urb = &_urb->urb;
-+                      BT_DBG("%s freeing _urb %p type %d urb %p",
-+                                      husb->hdev.name, _urb, _urb->type, urb);
-+                      if (urb->setup_packet)
-+                              kfree(urb->setup_packet);
-+                      if (urb->transfer_buffer)
-+                              kfree(urb->transfer_buffer);
-+                      _urb_free(_urb);
-+              }
--      switch (skb->pkt_type) {
--              case HCI_COMMAND_PKT:
--                      skb_queue_tail(&husb->tx_ctrl_q, skb);
--                      hci_usb_ctrl_wakeup(husb);
--                      hdev->stat.cmd_tx++;
--                      return 0;
-+              /* Release reassembly buffers */
-+              if (husb->reassembly[i]) {
-+                      kfree_skb(husb->reassembly[i]);
-+                      husb->reassembly[i] = NULL;
-+              }
-+      }
-+}
--              case HCI_ACLDATA_PKT:
--                      skb_queue_tail(&husb->tx_write_q, skb);
--                      hci_usb_write_wakeup(husb);
--                      hdev->stat.acl_tx++;
--                      return 0;
-+/* Close device */
-+static int hci_usb_close(struct hci_dev *hdev)
-+{
-+      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+      unsigned long flags;
-+      
-+      if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
-+              return 0;
--              case HCI_SCODATA_PKT:
--                      return -EOPNOTSUPP;
--      };
-+      BT_DBG("%s", hdev->name);
-+
-+      write_lock_irqsave(&husb->completion_lock, flags);
-+      
-+      hci_usb_unlink_urbs(husb);
-+      hci_usb_flush(hdev);
-+
-+      write_unlock_irqrestore(&husb->completion_lock, flags);
-+      MOD_DEC_USE_COUNT;
-       return 0;
- }
--/* ---------- USB ------------- */
-+static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
-+{
-+      struct urb *urb = &_urb->urb;
-+      int err;
--static void hci_usb_ctrl(struct urb *urb)
-+      BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
-+      
-+      _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
-+      err = usb_submit_urb(urb);
-+      if (err) {
-+              BT_ERR("%s tx submit failed urb %p type %d err %d",
-+                              husb->hdev.name, urb, _urb->type, err);
-+              _urb_unlink(_urb);
-+              _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+      } else
-+              atomic_inc(__pending_tx(husb, _urb->type));
-+
-+      return err;
-+}
-+
-+static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
- {
--      struct sk_buff *skb = (struct sk_buff *) urb->context;
--      struct hci_dev *hdev;
--      struct hci_usb *husb;
-+      struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+      devrequest *dr;
-+      struct urb *urb;
--      if (!skb)
--              return;
--      hdev = (struct hci_dev *) skb->dev;
--      husb = (struct hci_usb *) hdev->driver_data;
-+      if (!_urb) {
-+              _urb = _urb_alloc(0, GFP_ATOMIC);
-+              if (!_urb)
-+                      return -ENOMEM;
-+              _urb->type = skb->pkt_type;
--      DBG("%s", hdev->name);
-+              dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
-+              if (!dr) {
-+                      _urb_free(_urb);
-+                      return -ENOMEM;
-+              }
-+      } else
-+              dr = (void *) _urb->urb.setup_packet;
--      if (urb->status)
--              DBG("%s ctrl status: %d", hdev->name, urb->status);
-+      dr->requesttype = husb->ctrl_req;
-+      dr->request = 0;
-+      dr->index   = 0;
-+      dr->value   = 0;
-+      dr->length  = __cpu_to_le16(skb->len);
--      clear_bit(HCI_TX_CTRL, &husb->tx_state);
--      kfree_skb(skb);
-+      urb = &_urb->urb;
-+      FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
-+              (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
--      /* Wake up device */
--      hci_usb_ctrl_wakeup(husb);
-+      BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
-+      
-+      _urb->priv = skb;
-+      return __tx_submit(husb, _urb);
- }
--static void hci_usb_bulk_write(struct urb *urb)
-+static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
- {
--      struct sk_buff *skb = (struct sk_buff *) urb->context;
--      struct hci_dev *hdev;
--      struct hci_usb *husb;
--
--      if (!skb)
--              return;
--      hdev = (struct hci_dev *) skb->dev;
--      husb = (struct hci_usb *) hdev->driver_data;
--
--      DBG("%s", hdev->name);
-+      struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+      struct urb *urb;
-+      int pipe;
--      if (urb->status)
--              DBG("%s bulk write status: %d", hdev->name, urb->status);
-+      if (!_urb) {
-+              _urb = _urb_alloc(0, GFP_ATOMIC);
-+              if (!_urb)
-+                      return -ENOMEM;
-+              _urb->type = skb->pkt_type;
-+      }
--      clear_bit(HCI_TX_WRITE, &husb->tx_state);
--      kfree_skb(skb);
-+      urb  = &_urb->urb;
-+      pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
-+      FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, 
-+                      hci_usb_tx_complete, husb);
-+      urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
--      /* Wake up device */
--      hci_usb_write_wakeup(husb);
-+      BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
--      return;
-+      _urb->priv = skb;
-+      return __tx_submit(husb, _urb);
- }
--static void hci_usb_intr(struct urb *urb)
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
- {
--      struct hci_usb *husb = (struct hci_usb *) urb->context;
--      unsigned char *data = urb->transfer_buffer;
--      register int count  = urb->actual_length;
--      register struct sk_buff *skb = husb->intr_skb;
--      hci_event_hdr *eh;
--      register int len;
-+      struct _urb *_urb = __get_completed(husb, skb->pkt_type);
-+      struct urb *urb;
-+      
-+      if (!_urb) {
-+              _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
-+              if (!_urb)
-+                      return -ENOMEM;
-+              _urb->type = skb->pkt_type;
-+      }
--      if (!husb)
--              return;
-+      BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
--      DBG("%s count %d", husb->hdev.name, count);
-+      urb = &_urb->urb;
-+      
-+      urb->context  = husb;
-+      urb->dev      = husb->udev;
-+      urb->pipe     = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
-+      urb->complete = hci_usb_tx_complete;
-+      urb->transfer_flags = USB_ISO_ASAP;
--      if (urb->status || !count) {
--              DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
--              return;
--      }
-+      urb->transfer_buffer = skb->data;
-+      urb->transfer_buffer_length = skb->len;
-+      
-+      __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
--      /* Do we really have to handle continuations here ? */
--      if (!skb) {
--              /* New frame */
--              if (count < HCI_EVENT_HDR_SIZE) {
--                      DBG("%s bad frame len %d", husb->hdev.name, count);
--                      return;
--              }
-+      _urb->priv = skb;
-+      return __tx_submit(husb, _urb);
-+}
-+#endif
--              eh = (hci_event_hdr *) data;
--              len = eh->plen + HCI_EVENT_HDR_SIZE;
-+static void hci_usb_tx_process(struct hci_usb *husb)
-+{
-+      struct sk_buff_head *q;
-+      struct sk_buff *skb;
--              if (count > len) {
--                      DBG("%s corrupted frame, len %d", husb->hdev.name, count);
--                      return;
-+      BT_DBG("%s", husb->hdev.name);
-+
-+      do {
-+              clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
-+
-+              /* Process command queue */
-+              q = __transmit_q(husb, HCI_COMMAND_PKT);
-+              if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
-+                              (skb = skb_dequeue(q))) {
-+                      if (hci_usb_send_ctrl(husb, skb) < 0)
-+                              skb_queue_head(q, skb);
-               }
--              /* Allocate skb */
--              if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
--                      ERR("Can't allocate mem for new packet");
--                      return;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+              /* Process SCO queue */
-+              q = __transmit_q(husb, HCI_SCODATA_PKT);
-+              if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
-+                              (skb = skb_dequeue(q))) {
-+                      if (hci_usb_send_isoc(husb, skb) < 0)
-+                              skb_queue_head(q, skb);
-               }
--              skb->dev = (void *) &husb->hdev;
--              skb->pkt_type = HCI_EVENT_PKT;
-+#endif
-+              
-+              /* Process ACL queue */
-+              q = __transmit_q(husb, HCI_ACLDATA_PKT);
-+              while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
-+                              (skb = skb_dequeue(q))) {
-+                      if (hci_usb_send_bulk(husb, skb) < 0) {
-+                              skb_queue_head(q, skb);
-+                              break;
-+                      }
-+              }
-+      } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
-+}
--              husb->intr_skb = skb;
--              husb->intr_count = len;
--      } else {
--              /* Continuation */
--              if (count > husb->intr_count) {
--                      ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
-+static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
-+{
-+      /* Serialize TX queue processing to avoid data reordering */
-+      if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
-+              hci_usb_tx_process(husb);
-+              clear_bit(HCI_USB_TX_PROCESS, &husb->state);
-+      } else
-+              set_bit(HCI_USB_TX_WAKEUP, &husb->state);
-+}
--                      kfree_skb(skb);
--                      husb->intr_skb = NULL;
--                      husb->intr_count = 0;
--                      return;
--              }
-+/* Send frames from HCI layer */
-+static int hci_usb_send_frame(struct sk_buff *skb)
-+{
-+      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
-+      struct hci_usb *husb;
-+
-+      if (!hdev) {
-+              BT_ERR("frame for uknown device (hdev=NULL)");
-+              return -ENODEV;
-       }
--      memcpy(skb_put(skb, count), data, count);
--      husb->intr_count -= count;
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-+              return -EBUSY;
--      DMP(data, count);
-+      BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--      if (!husb->intr_count) {
--              /* Got complete frame */
-+      husb = (struct hci_usb *) hdev->driver_data;
--              husb->hdev.stat.byte_rx += skb->len;
--              hci_recv_frame(skb);
-+      switch (skb->pkt_type) {
-+      case HCI_COMMAND_PKT:
-+              hdev->stat.cmd_tx++;
-+              break;
--              husb->intr_skb = NULL;
--      }
--}
-+      case HCI_ACLDATA_PKT:
-+              hdev->stat.acl_tx++;
-+              break;
--static void hci_usb_bulk_read(struct urb *urb)
--{
--      struct hci_usb *husb = (struct hci_usb *) urb->context;
--      unsigned char *data = urb->transfer_buffer;
--      int count = urb->actual_length, status;
--      struct sk_buff *skb;
--      hci_acl_hdr *ah;
--      register __u16 dlen;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+      case HCI_SCODATA_PKT:
-+              hdev->stat.sco_tx++;
-+              break;
-+#endif
--      if (!husb)
--              return;
-+      default:
-+              kfree_skb(skb);
-+              return 0;
-+      }
--      DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
-+      read_lock(&husb->completion_lock);
--      if (urb->status) {
--              /* Do not re-submit URB on critical errors */
--              switch (urb->status) {
--                      case -ENOENT:
--                              return;
--                      default:
--                              goto resubmit;
--              };
--      }
--      if (!count)
--              goto resubmit;
-+      skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
-+      hci_usb_tx_wakeup(husb);
--      DMP(data, count);
-+      read_unlock(&husb->completion_lock);
-+      return 0;
-+}
--      ah = (hci_acl_hdr *) data;
--      dlen = le16_to_cpu(ah->dlen);
-+static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
-+{
-+      BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
--      /* Verify frame len and completeness */
--      if ((count - HCI_ACL_HDR_SIZE) != dlen) {
--              ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
--              goto resubmit;
--      }
-+      husb->hdev.stat.byte_rx += count;
--      /* Allocate packet */
--      if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
--              ERR("Can't allocate mem for new packet");
--              goto resubmit;
--      }
-+      while (count) {
-+              struct sk_buff *skb = __reassembly(husb, type);
-+              struct { int expect; } *scb;
-+              int len = 0;
-+      
-+              if (!skb) {
-+                      /* Start of the frame */
--      memcpy(skb_put(skb, count), data, count);
--      skb->dev = (void *) &husb->hdev;
--      skb->pkt_type = HCI_ACLDATA_PKT;
-+                      switch (type) {
-+                      case HCI_EVENT_PKT:
-+                              if (count >= HCI_EVENT_HDR_SIZE) {
-+                                      hci_event_hdr *h = data;
-+                                      len = HCI_EVENT_HDR_SIZE + h->plen;
-+                              } else
-+                                      return -EILSEQ;
-+                              break;
--      husb->hdev.stat.byte_rx += skb->len;
-+                      case HCI_ACLDATA_PKT:
-+                              if (count >= HCI_ACL_HDR_SIZE) {
-+                                      hci_acl_hdr *h = data;
-+                                      len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
-+                              } else
-+                                      return -EILSEQ;
-+                              break;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+                      case HCI_SCODATA_PKT:
-+                              if (count >= HCI_SCO_HDR_SIZE) {
-+                                      hci_sco_hdr *h = data;
-+                                      len = HCI_SCO_HDR_SIZE + h->dlen;
-+                              } else 
-+                                      return -EILSEQ;
-+                              break;
-+#endif
-+                      }
-+                      BT_DBG("new packet len %d", len);
-+                              
-+                      skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+                      if (!skb) {
-+                              BT_ERR("%s no memory for the packet", husb->hdev.name);
-+                              return -ENOMEM;
-+                      }
-+                      skb->dev = (void *) &husb->hdev;
-+                      skb->pkt_type = type;
-+      
-+                      __reassembly(husb, type) = skb;
--      hci_recv_frame(skb);
-+                      scb = (void *) skb->cb;
-+                      scb->expect = len;
-+              } else {
-+                      /* Continuation */
-+                      scb = (void *) skb->cb;
-+                      len = scb->expect;
-+              }
--resubmit:
--      husb->read_urb->dev = husb->udev;
--      if ((status = usb_submit_urb(husb->read_urb)))
--              DBG("%s read URB submit failed %d", husb->hdev.name, status);
-+              len = min(len, count);
-+              
-+              memcpy(skb_put(skb, len), data, len);
--      DBG("%s read URB re-submited", husb->hdev.name);
-+              scb->expect -= len;
-+              if (!scb->expect) {
-+                      /* Complete frame */
-+                      __reassembly(husb, type) = NULL;
-+                      hci_recv_frame(skb);
-+              }
-+
-+              count -= len; data += len;
-+      }
-+      return 0;
- }
--static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
-+static void hci_usb_rx_complete(struct urb *urb)
- {
--      struct urb *urb = husb->ctrl_urb;
--      devrequest *dr  = &husb->dev_req;
--      int pipe, status;
-+      struct _urb *_urb = container_of(urb, struct _urb, urb);
-+      struct hci_usb *husb = (void *) urb->context;
-+      struct hci_dev *hdev = &husb->hdev;
-+      int    err, count = urb->actual_length;
--      DBG("%s len %d", husb->hdev.name, skb->len);
-+      BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
-+                      _urb->type, urb->status, count, urb->transfer_flags);
--      pipe = usb_sndctrlpipe(husb->udev, 0);
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-+              return;
--      dr->requesttype = HCI_CTRL_REQ;
--      dr->request = 0;
--      dr->index   = 0;
--      dr->value   = 0;
--      dr->length  = cpu_to_le16(skb->len);
-+      read_lock(&husb->completion_lock);
--      FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
--                       hci_usb_ctrl, skb);
-+      if (urb->status || !count)
-+              goto resubmit;
--      if ((status = usb_submit_urb(urb))) {
--              DBG("%s control URB submit failed %d", husb->hdev.name, status);
--              return status;
-+      if (_urb->type == HCI_SCODATA_PKT) {
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+              int i;
-+              for (i=0; i < urb->number_of_packets; i++) {
-+                      BT_DBG("desc %d status %d offset %d len %d", i,
-+                                      urb->iso_frame_desc[i].status,
-+                                      urb->iso_frame_desc[i].offset,
-+                                      urb->iso_frame_desc[i].actual_length);
-+      
-+                      if (!urb->iso_frame_desc[i].status)
-+                              __recv_frame(husb, _urb->type, 
-+                                      urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-+                                      urb->iso_frame_desc[i].actual_length);
-+              }
-+#else
-+              ;
-+#endif
-+      } else {
-+              err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
-+              if (err < 0) { 
-+                      BT_ERR("%s corrupted packet: type %d count %d",
-+                                      husb->hdev.name, _urb->type, count);
-+                      hdev->stat.err_rx++;
-+              }
-       }
--      return 0;
-+resubmit:
-+      if (_urb->type != HCI_EVENT_PKT) {
-+              urb->dev = husb->udev;
-+              err      = usb_submit_urb(urb);
-+              BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
-+                              _urb->type, err);
-+      }
-+      read_unlock(&husb->completion_lock);
- }
--static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
-+static void hci_usb_tx_complete(struct urb *urb)
- {
--      struct urb *urb = husb->write_urb;
--      int pipe, status;
-+      struct _urb *_urb = container_of(urb, struct _urb, urb);
-+      struct hci_usb *husb = (void *) urb->context;
-+      struct hci_dev *hdev = &husb->hdev;
--      DBG("%s len %d", husb->hdev.name, skb->len);
-+      BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
-+                      urb->status, urb->transfer_flags);
--      pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
-+      atomic_dec(__pending_tx(husb, _urb->type));
--      FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
--                    hci_usb_bulk_write, skb);
--      urb->transfer_flags |= USB_QUEUE_BULK;
-+      urb->transfer_buffer = NULL;
-+      kfree_skb((struct sk_buff *) _urb->priv);
--      if ((status = usb_submit_urb(urb))) {
--              DBG("%s write URB submit failed %d", husb->hdev.name, status);
--              return status;
--      }
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-+              return;
--      return 0;
-+      if (!urb->status)
-+              hdev->stat.byte_tx += urb->transfer_buffer_length;
-+      else
-+              hdev->stat.err_tx++;
-+
-+      read_lock(&husb->completion_lock);
-+
-+      _urb_unlink(_urb);
-+      _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
-+
-+      hci_usb_tx_wakeup(husb);
-+      
-+      read_unlock(&husb->completion_lock);
- }
--static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+static void hci_usb_destruct(struct hci_dev *hdev)
- {
--      struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
-+      struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
-+
-+      BT_DBG("%s", hdev->name);
-+
-+      kfree(husb);
-+}
-+
-+static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
-+{
-+      struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
-+      struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
-+      struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
-+      struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
-+      struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
-       struct usb_interface_descriptor *uif;
-       struct usb_endpoint_descriptor *ep;
-+      struct usb_interface *iface, *isoc_iface;
-       struct hci_usb *husb;
-       struct hci_dev *hdev;
--      int i, size, pipe;
--      __u8 * buf;
--
--      DBG("udev %p ifnum %d", udev, ifnum);
-+      int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
--      /* Check device signature */
--      if ((udev->descriptor.bDeviceClass    != HCI_DEV_CLASS)   ||
--          (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
--          (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
--              return NULL;
-+      BT_DBG("udev %p ifnum %d", udev, ifnum);
--      MOD_INC_USE_COUNT;
-+      iface = &udev->actconfig->interface[0];
--      uif = &udev->actconfig->interface[ifnum].altsetting[0];
-+      /* Check our black list */
-+      if (usb_match_id(udev, iface, ignore_ids))
-+              return NULL;
--      if (uif->bNumEndpoints != 3) {
--              DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
--              MOD_DEC_USE_COUNT;
-+      /* Check number of endpoints */
-+      if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
-               return NULL;
--      }
--      bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
-+      memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
-+      memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
-+      memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
-+      memset(isoc_in_ep,  0, sizeof(isoc_in_ep));
-+      memset(intr_in_ep,  0, sizeof(intr_in_ep));
-+      size = 0; 
-+      isoc_iface = NULL;
-+      isoc_alts  = isoc_ifnum = 0;
-+      
-       /* Find endpoints that we need */
--      for ( i = 0; i < uif->bNumEndpoints; ++i) {
--              ep = &uif->endpoint[i];
--              switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
--                      case USB_ENDPOINT_XFER_BULK:
--                              if (ep->bEndpointAddress & USB_DIR_IN)
--                                      bulk_in_ep  = ep;
--                              else
--                                      bulk_out_ep = ep;
--                              break;
--
--                      case USB_ENDPOINT_XFER_INT:
--                              intr_in_ep = ep;
--                              break;
--              };
--      }
-+      ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
-+      for (i = 0; i < ifn; i++) {
-+              iface = &udev->actconfig->interface[i];
-+              for (a = 0; a < iface->num_altsetting; a++) {
-+                      uif = &iface->altsetting[a];
-+                      for (e = 0; e < uif->bNumEndpoints; e++) {
-+                              ep = &uif->endpoint[e];
--      if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
--              DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
--              MOD_DEC_USE_COUNT;
--              return NULL;
--      }
-+                              switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-+                              case USB_ENDPOINT_XFER_INT:
-+                                      if (ep->bEndpointAddress & USB_DIR_IN)
-+                                              intr_in_ep[i] = ep;
-+                                      break;
--      if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
--              ERR("Can't allocate: control structure");
--              MOD_DEC_USE_COUNT;
--              return NULL;
--      }
-+                              case USB_ENDPOINT_XFER_BULK:
-+                                      if (ep->bEndpointAddress & USB_DIR_IN)
-+                                              bulk_in_ep[i]  = ep;
-+                                      else
-+                                              bulk_out_ep[i] = ep;
-+                                      break;
--      memset(husb, 0, sizeof(struct hci_usb));
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+                              case USB_ENDPOINT_XFER_ISOC:
-+                                      if (ep->wMaxPacketSize < size || a > 2)
-+                                              break;
-+                                      size = ep->wMaxPacketSize;
--      husb->udev = udev;
--      husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
-+                                      isoc_iface = iface;
-+                                      isoc_alts  = a;
-+                                      isoc_ifnum = i;
--      if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
--              ERR("Can't allocate: control URB");
--              goto probe_error;
-+                                      if (ep->bEndpointAddress & USB_DIR_IN)
-+                                              isoc_in_ep[i]  = ep;
-+                                      else
-+                                              isoc_out_ep[i] = ep;
-+                                      break;
-+#endif
-+                              }
-+                      }
-+              }
-       }
--      if (!(husb->write_urb = usb_alloc_urb(0))) {
--              ERR("Can't allocate: write URB");
--              goto probe_error;
-+      if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
-+              BT_DBG("Bulk endpoints not found");
-+              goto done;
-       }
--      if (!(husb->read_urb = usb_alloc_urb(0))) {
--              ERR("Can't allocate: read URB");
--              goto probe_error;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+      if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
-+              BT_DBG("Isoc endpoints not found");
-+              isoc_iface = NULL;
-       }
-+#endif
--      ep = bulk_in_ep;
--      pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
--      size = HCI_MAX_FRAME_SIZE;
--
--      if (!(buf = kmalloc(size, GFP_KERNEL))) {
--              ERR("Can't allocate: read buffer");
--              goto probe_error;
-+      if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
-+              BT_ERR("Can't allocate: control structure");
-+              goto done;
-       }
--      FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
--      husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
-+      memset(husb, 0, sizeof(struct hci_usb));
--      ep = intr_in_ep;
--      pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
--      size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-+      husb->udev = udev;
-+      husb->bulk_out_ep = bulk_out_ep[0];
-+      husb->bulk_in_ep  = bulk_in_ep[0];
-+      husb->intr_in_ep  = intr_in_ep[0];
--      if (!(husb->intr_urb = usb_alloc_urb(0))) {
--              ERR("Can't allocate: interrupt URB");
--              goto probe_error;
--      }
-+      if (id->driver_info & HCI_DIGIANSWER)
-+              husb->ctrl_req = HCI_DIGI_REQ;
-+      else
-+              husb->ctrl_req = HCI_CTRL_REQ;
--      if (!(buf = kmalloc(size, GFP_KERNEL))) {
--              ERR("Can't allocate: interrupt buffer");
--              goto probe_error;
-+#ifdef CONFIG_BLUEZ_HCIUSB_SCO
-+      if (isoc_iface) {
-+              BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
-+              if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-+                      BT_ERR("Can't set isoc interface settings");
-+                      isoc_iface = NULL;
-+              }
-+              usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
-+              husb->isoc_iface  = isoc_iface;
-+              husb->isoc_in_ep  = isoc_in_ep[isoc_ifnum];
-+              husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
-       }
-+#endif
-+      
-+      husb->completion_lock = RW_LOCK_UNLOCKED;
--      FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
--
--      skb_queue_head_init(&husb->tx_ctrl_q);
--      skb_queue_head_init(&husb->tx_write_q);
-+      for (i = 0; i < 4; i++) {       
-+              skb_queue_head_init(&husb->transmit_q[i]);
-+              _urb_queue_init(&husb->pending_q[i]);
-+              _urb_queue_init(&husb->completed_q[i]);
-+      }
-       /* Initialize and register HCI device */
-       hdev = &husb->hdev;
--      hdev->type = HCI_USB;
-+      hdev->type  = HCI_USB;
-       hdev->driver_data = husb;
-       hdev->open  = hci_usb_open;
-       hdev->close = hci_usb_close;
-       hdev->flush = hci_usb_flush;
--      hdev->send      = hci_usb_send_frame;
-+      hdev->send  = hci_usb_send_frame;
-+      hdev->destruct = hci_usb_destruct;
-       if (hci_register_dev(hdev) < 0) {
--              ERR("Can't register HCI device %s", hdev->name);
-+              BT_ERR("Can't register HCI device");
-               goto probe_error;
-       }
-       return husb;
- probe_error:
--      hci_usb_free_bufs(husb);
-       kfree(husb);
--      MOD_DEC_USE_COUNT;
-+
-+done:
-       return NULL;
- }
-@@ -626,38 +943,34 @@
-       if (!husb)
-               return;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", hdev->name);
-       hci_usb_close(hdev);
--      if (hci_unregister_dev(hdev) < 0) {
--              ERR("Can't unregister HCI device %s", hdev->name);
--      }
--
--      hci_usb_free_bufs(husb);
--      kfree(husb);
-+      if (husb->isoc_iface)
-+              usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
--      MOD_DEC_USE_COUNT;
-+      if (hci_unregister_dev(hdev) < 0)
-+              BT_ERR("Can't unregister HCI device %s", hdev->name);
- }
--static struct usb_driver hci_usb_driver =
--{
-+static struct usb_driver hci_usb_driver = {
-       name:           "hci_usb",
-       probe:          hci_usb_probe,
-       disconnect:     hci_usb_disconnect,
--      id_table:       usb_bluetooth_ids,
-+      id_table:       bluetooth_ids,
- };
- int hci_usb_init(void)
- {
-       int err;
--      INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
-+      BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
-               VERSION);
--      INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+      BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-       if ((err = usb_register(&hci_usb_driver)) < 0)
--              ERR("Failed to register HCI USB driver");
-+              BT_ERR("Failed to register HCI USB driver");
-       return err;
- }
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_usb.h  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,144 @@
-+/* 
-+   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
-+   Copyright (C) 2000-2001 Qualcomm Incorporated
-+   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
-+
-+   Copyright (C) 2003 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_usb.h,v 1.2 2002/03/18 19:10:04 maxk Exp $
-+ */
-+
-+#ifdef __KERNEL__
-+
-+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-+#define HCI_DEV_CLASS        0xe0     /* Wireless class */
-+#define HCI_DEV_SUBCLASS     0x01     /* RF subclass */
-+#define HCI_DEV_PROTOCOL     0x01     /* Bluetooth programming protocol */
-+
-+#define HCI_CTRL_REQ       0x20
-+#define HCI_DIGI_REQ       0x40
-+
-+#define HCI_DIGIANSWER       0x01
-+
-+#define HCI_MAX_IFACE_NUM     3 
-+
-+#define HCI_MAX_BULK_TX       4
-+#define HCI_MAX_BULK_RX       1
-+
-+#define HCI_MAX_ISOC_RX               2
-+#define HCI_MAX_ISOC_TX               2
-+
-+#define HCI_MAX_ISOC_FRAMES     10
-+
-+struct _urb_queue {
-+      struct list_head head;
-+      spinlock_t       lock;
-+};
-+
-+struct _urb {
-+      struct list_head  list;
-+      struct _urb_queue *queue;
-+      int               type;
-+      void              *priv;
-+      struct urb        urb;
-+};
-+
-+struct _urb *_urb_alloc(int isoc, int gfp);
-+
-+static inline void _urb_free(struct _urb *_urb)
-+{
-+      kfree(_urb);
-+}
-+
-+static inline void _urb_queue_init(struct _urb_queue *q)
-+{
-+      INIT_LIST_HEAD(&q->head);
-+      spin_lock_init(&q->lock);
-+}
-+
-+static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
-+{
-+        unsigned long flags;
-+        spin_lock_irqsave(&q->lock, flags);
-+      list_add(&_urb->list, &q->head); _urb->queue = q;
-+      spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
-+{
-+        unsigned long flags;
-+        spin_lock_irqsave(&q->lock, flags);
-+      list_add_tail(&_urb->list, &q->head); _urb->queue = q;
-+      spin_unlock_irqrestore(&q->lock, flags);
-+}
-+
-+static inline void _urb_unlink(struct _urb *_urb)
-+{
-+      struct _urb_queue *q = _urb->queue;
-+        unsigned long flags;
-+      if (q) {
-+              spin_lock_irqsave(&q->lock, flags);
-+              list_del(&_urb->list); _urb->queue = NULL;
-+              spin_unlock_irqrestore(&q->lock, flags);
-+      }
-+}
-+
-+struct _urb *_urb_dequeue(struct _urb_queue *q);
-+
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({                      \
-+                      const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-+                              (type *)( (char *)__mptr - offsetof(type,member) );})
-+#endif
-+
-+struct hci_usb {
-+      struct hci_dev          hdev;
-+
-+      unsigned long           state;
-+      
-+      struct usb_device       *udev;
-+      
-+      struct usb_endpoint_descriptor  *bulk_in_ep;
-+      struct usb_endpoint_descriptor  *bulk_out_ep;
-+      struct usb_endpoint_descriptor  *intr_in_ep;
-+
-+      struct usb_interface            *isoc_iface;
-+      struct usb_endpoint_descriptor  *isoc_out_ep;
-+      struct usb_endpoint_descriptor  *isoc_in_ep;
-+
-+      __u8                    ctrl_req;
-+
-+      struct sk_buff_head     transmit_q[4];
-+      struct sk_buff          *reassembly[4]; // Reassembly buffers
-+
-+      rwlock_t                completion_lock;
-+
-+      atomic_t                pending_tx[4];  // Number of pending requests 
-+      struct _urb_queue       pending_q[4];   // Pending requests
-+      struct _urb_queue       completed_q[4]; // Completed requests
-+};
-+
-+/* States  */
-+#define HCI_USB_TX_PROCESS    1
-+#define HCI_USB_TX_WAKEUP     2
-+
-+#endif /* __KERNEL__ */
---- linux/drivers/bluetooth/hci_vhci.c~bluetooth-2.4.18-mh11   2001-09-07 18:28:38.000000000 +0200
-+++ linux/drivers/bluetooth/hci_vhci.c 2004-01-25 23:37:39.000000000 +0100
-@@ -25,9 +25,9 @@
- /*
-  * 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/module.h>
-@@ -49,43 +49,56 @@
- #include <asm/uaccess.h>
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/hci_vhci.h>
-+#include "hci_vhci.h"
- /* 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;
- }
--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;
-       skb_queue_purge(&hci_vhci->readq);
-       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);
-       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_vhci_struct *hci_vhci;
-       if (!hdev) {
--              ERR("Frame for uknown device (hdev=NULL)");
-+              BT_ERR("Frame for uknown device (hdev=NULL)");
-               return -ENODEV;
-       }
--      if (!(hdev->flags & HCI_RUNNING))
-+      if (!test_bit(HCI_RUNNING, &hdev->flags))
-               return -EBUSY;
-       hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
-@@ -188,7 +201,7 @@
-       add_wait_queue(&hci_vhci->read_wait, &wait);
-       while (count) {
--              current->state = TASK_INTERRUPTIBLE;
-+              set_current_state(TASK_INTERRUPTIBLE);
-               /* Read frames from device queue */
-               if (!(skb = skb_dequeue(&hci_vhci->readq))) {
-@@ -214,8 +227,7 @@
-               kfree_skb(skb);
-               break;
-       }
--
--      current->state = TASK_RUNNING;
-+      set_current_state(TASK_RUNNING);
-       remove_wait_queue(&hci_vhci->read_wait, &wait);
-       return ret;
-@@ -270,11 +282,13 @@
-       hdev->close = hci_vhci_close;
-       hdev->flush = hci_vhci_flush;
-       hdev->send  = hci_vhci_send_frame;
-+      hdev->destruct = hci_vhci_destruct;
-       if (hci_register_dev(hdev) < 0) {
-               kfree(hci_vhci);
-               return -EBUSY;
-       }
-+      MOD_INC_USE_COUNT;
-       file->private_data = hci_vhci;
-       return 0;   
-@@ -285,12 +299,10 @@
-       struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
-       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;
--
-       return 0;
- }
-@@ -315,12 +327,12 @@
- 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);
--      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)) {
--              ERR("Can't register misc device %d\n", VHCI_MINOR);
-+              BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
-               return -EIO;
-       }
-@@ -337,4 +349,4 @@
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
- MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
--MODULE_LICENSE("GPL");
-+MODULE_LICENSE("GPL"); 
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/hci_vhci.h 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,50 @@
-+/* 
-+   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_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
-+ */
-+
-+#ifndef __HCI_VHCI_H
-+#define __HCI_VHCI_H
-+
-+#ifdef __KERNEL__
-+
-+struct hci_vhci_struct {
-+      struct hci_dev       hdev;
-+      __u32                flags;
-+      wait_queue_head_t    read_wait;
-+      struct sk_buff_head  readq;
-+      struct fasync_struct *fasync;
-+};
-+
-+/* VHCI device flags */
-+#define VHCI_FASYNC           0x0010
-+
-+#endif /* __KERNEL__ */
-+
-+#define VHCI_DEV      "/dev/vhci"
-+#define VHCI_MINOR    250
-+
-+#endif /* __HCI_VHCI_H */
---- linux/drivers/bluetooth/Makefile~bluetooth-2.4.18-mh11     2001-09-07 18:28:38.000000000 +0200
-+++ linux/drivers/bluetooth/Makefile   2004-01-25 23:37:39.000000000 +0100
-@@ -1,11 +1,27 @@
- #
--# Makefile for Bluetooth HCI device drivers.
-+# Makefile for the Linux Bluetooth HCI device drivers
- #
- O_TARGET      := bluetooth.o
-+list-multi    := hci_uart.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_HCIUART)           += hci_uart.o
-+uart-y                                        := hci_ldisc.o
-+uart-$(CONFIG_BLUEZ_HCIUART_H4)               += hci_h4.o
-+uart-$(CONFIG_BLUEZ_HCIUART_BCSP)     += hci_bcsp.o
-+
-+obj-$(CONFIG_BLUEZ_HCIBFUSB)  += bfusb.o
-+
-+obj-$(CONFIG_BLUEZ_HCIDTL1)   += dtl1_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBT3C)   += bt3c_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBLUECARD)       += bluecard_cs.o
-+obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o
-+
- include $(TOPDIR)/Rules.make
-+
-+hci_uart.o: $(uart-y)
-+      $(LD) -r -o $@ $(uart-y)
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/bluetooth/Makefile.lib       2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1 @@
-+obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
---- linux/drivers/char/pcmcia/serial_cs.c~bluetooth-2.4.18-mh11        2004-01-25 23:28:22.000000000 +0100
-+++ linux/drivers/char/pcmcia/serial_cs.c      2004-01-25 23:37:39.000000000 +0100
-@@ -72,14 +72,14 @@
- static int irq_list[4] = { -1 };
- MODULE_PARM(irq_list, "1-4i");
--/* Enable the speaker? */
--INT_MODULE_PARM(do_sound, 1);
-+INT_MODULE_PARM(do_sound, 1);         /* Enable the speaker? */
-+INT_MODULE_PARM(buggy_uart, 0);               /* Skip strict UART tests? */
- #ifdef PCMCIA_DEBUG
- INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
- #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
- static char *version =
--"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
-+"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
- #else
- #define DEBUG(n, args...)
- #endif
-@@ -98,6 +98,7 @@
-     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
-     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
-     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
-+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
-     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
-     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
-     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
-@@ -151,7 +152,7 @@
-     client_reg_t client_reg;
-     dev_link_t *link;
-     int i, ret;
--    
-+
-     DEBUG(0, "serial_attach()\n");
-     /* Create new serial device */
-@@ -163,7 +164,7 @@
-     link->release.function = &serial_release;
-     link->release.data = (u_long)link;
-     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
--    link->io.NumPorts1 = 8;
-+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
-     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
-     if (irq_list[0] == -1)
-@@ -172,13 +173,12 @@
-       for (i = 0; i < 4; i++)
-           link->irq.IRQInfo2 |= 1 << irq_list[i];
-     link->conf.Attributes = CONF_ENABLE_IRQ;
--    link->conf.Vcc = 50;
-     if (do_sound) {
-       link->conf.Attributes |= CONF_ENABLE_SPKR;
-       link->conf.Status = CCSR_AUDIO_ENA;
-     }
-     link->conf.IntType = INT_MEMORY_AND_IO;
--    
-+
-     /* Register with Card Services */
-     link->next = dev_list;
-     dev_list = link;
-@@ -197,7 +197,7 @@
-       serial_detach(link);
-       return NULL;
-     }
--    
-+
-     return link;
- } /* serial_attach */
-@@ -217,7 +217,7 @@
-     int ret;
-     DEBUG(0, "serial_detach(0x%p)\n", link);
--    
-+
-     /* Locate device structure */
-     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-       if (*linkp == link) break;
-@@ -227,17 +227,17 @@
-     del_timer(&link->release);
-     if (link->state & DEV_CONFIG)
-       serial_release((u_long)link);
--    
-+
-     if (link->handle) {
-       ret = CardServices(DeregisterClient, link->handle);
-       if (ret != CS_SUCCESS)
-           cs_error(link->handle, DeregisterClient, ret);
-     }
--    
-+
-     /* Unlink device structure, free bits */
-     *linkp = link->next;
-     kfree(info);
--    
-+
- } /* serial_detach */
- /*====================================================================*/
-@@ -246,18 +246,20 @@
- {
-     struct serial_struct serial;
-     int line;
--    
-+
-     memset(&serial, 0, sizeof(serial));
-     serial.port = port;
-     serial.irq = irq;
-     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-+    if (buggy_uart)
-+      serial.flags |= ASYNC_BUGGY_UART;
-     line = register_serial(&serial);
-     if (line < 0) {
-       printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
-              " irq %d failed\n", (u_long)serial.port, serial.irq);
-       return -1;
-     }
--    
-+
-     info->line[info->ndev] = line;
-     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
-     info->node[info->ndev].major = TTY_MAJOR;
-@@ -265,7 +267,7 @@
-     if (info->ndev > 0)
-       info->node[info->ndev-1].next = &info->node[info->ndev];
-     info->ndev++;
--    
-+
-     return 0;
- }
-@@ -316,7 +318,10 @@
-           return setup_serial(info, port, config.AssignedIRQ);
-     }
-     link->conf.Vcc = config.Vcc;
--    
-+
-+    link->io.NumPorts1 = 8;
-+    link->io.NumPorts2 = 0;
-+
-     /* First pass: look for a config entry that looks normal. */
-     tuple.TupleData = (cisdata_t *)buf;
-     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-@@ -343,7 +348,7 @@
-           i = next_tuple(handle, &tuple, &parse);
-       }
-     }
--    
-+
-     /* Second pass: try to find an entry that isn't picky about
-        its base address, then try to grab any standard serial port
-        address, and finally try to get any free port. */
-@@ -355,8 +360,7 @@
-           for (j = 0; j < 5; j++) {
-               link->io.BasePort1 = base[j];
-               link->io.IOAddrLines = base[j] ? 16 : 3;
--              i = CardServices(RequestIO, link->handle,
--                               &link->io);
-+              i = CardServices(RequestIO, link->handle, &link->io);
-               if (i == CS_SUCCESS) goto found_port;
-           }
-       }
-@@ -368,7 +372,7 @@
-       cs_error(link->handle, RequestIO, i);
-       return -1;
-     }
--    
-+
-     i = CardServices(RequestIRQ, link->handle, &link->irq);
-     if (i != CS_SUCCESS) {
-       cs_error(link->handle, RequestIRQ, i);
-@@ -393,8 +397,12 @@
-     u_char buf[256];
-     cisparse_t parse;
-     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
-+    config_info_t config;
-     int i, base2 = 0;
-+    CardServices(GetConfigurationInfo, handle, &config);
-+    link->conf.Vcc = config.Vcc;
-+
-     tuple.TupleData = (cisdata_t *)buf;
-     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-     tuple.Attributes = 0;
-@@ -436,12 +444,12 @@
-           i = next_tuple(handle, &tuple, &parse);
-       }
-     }
--    
-+
-     if (i != CS_SUCCESS) {
--      cs_error(link->handle, RequestIO, i);
--      return -1;
-+      /* At worst, try to configure as a single port */
-+      return simple_config(link);
-     }
--    
-+
-     i = CardServices(RequestIRQ, link->handle, &link->irq);
-     if (i != CS_SUCCESS) {
-       cs_error(link->handle, RequestIRQ, i);
-@@ -457,14 +465,27 @@
-       cs_error(link->handle, RequestConfiguration, i);
-       return -1;
-     }
--    
-+
-+    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
-+       8 registers are for the UART, the others are extra registers */
-+    if (info->manfid == MANFID_OXSEMI) {
-+      if (cf->index == 1 || cf->index == 3) {
-+          setup_serial(info, base2, link->irq.AssignedIRQ);
-+          outb(12,link->io.BasePort1+1);
-+      } else {
-+          setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
-+          outb(12,base2+1);
-+      }
-+      return 0;
-+    }
-+
-     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
-     /* The Nokia cards are not really multiport cards */
-     if (info->manfid == MANFID_NOKIA)
-       return 0;
-     for (i = 0; i < info->multi-1; i++)
-       setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
--    
-+
-     return 0;
- }
-@@ -490,7 +511,7 @@
-     int i, last_ret, last_fn;
-     DEBUG(0, "serial_config(0x%p)\n", link);
--      
-+
-     tuple.TupleData = (cisdata_t *)buf;
-     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
-     tuple.Attributes = 0;
-@@ -525,7 +546,7 @@
-     }
-     link->conf.ConfigBase = parse.config.base;
-     link->conf.Present = parse.config.rmask[0];
--    
-+
-     /* Configure card */
-     link->state |= DEV_CONFIG;
-@@ -533,8 +554,8 @@
-     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
-     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
-     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
--    
--    /* Is this a multiport card? */
-+
-+    /* Scan list of known multiport card ID's */
-     tuple.DesiredTuple = CISTPL_MANFID;
-     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
-       info->manfid = le16_to_cpu(buf[0]);
-@@ -589,15 +610,15 @@
-       }
- #endif
-     }
--    
-+
-     if (info->multi > 1)
-       multi_config(link);
-     else
-       simple_config(link);
--    
-+
-     if (info->ndev == 0)
-       goto failed;
--    
-+
-     if (info->manfid == MANFID_IBM) {
-       conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
-       CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
-@@ -614,6 +635,7 @@
-     cs_error(link->handle, last_fn, last_ret);
- failed:
-     serial_release((u_long)link);
-+    link->state &= ~DEV_CONFIG_PENDING;
- } /* serial_config */
-@@ -621,7 +643,7 @@
-     After a card is removed, serial_release() will unregister the net
-     device, and release the PCMCIA configuration.
--    
-+
- ======================================================================*/
- void serial_release(u_long arg)
-@@ -629,7 +651,7 @@
-     dev_link_t *link = (dev_link_t *)arg;
-     serial_info_t *info = link->priv;
-     int i;
--    
-+
-     DEBUG(0, "serial_release(0x%p)\n", link);
-     for (i = 0; i < info->ndev; i++) {
-@@ -642,7 +664,7 @@
-       CardServices(ReleaseIO, link->handle, &link->io);
-       CardServices(ReleaseIRQ, link->handle, &link->irq);
-     }
--    
-+
-     link->state &= ~DEV_CONFIG;
- } /* serial_release */
-@@ -653,7 +675,7 @@
-     stuff to run after an event is received.  A CARD_REMOVAL event
-     also sets some flags to discourage the serial drivers from
-     talking to the ports.
--    
-+
- ======================================================================*/
- static int serial_event(event_t event, int priority,
-@@ -661,9 +683,9 @@
- {
-     dev_link_t *link = args->client_data;
-     serial_info_t *info = link->priv;
--    
-+
-     DEBUG(1, "serial_event(0x%06x)\n", event);
--    
-+
-     switch (event) {
-     case CS_EVENT_CARD_REMOVAL:
-       link->state &= ~DEV_PRESENT;
-@@ -702,7 +724,7 @@
-     if (serv.Revision != CS_RELEASE_CODE) {
-       printk(KERN_NOTICE "serial_cs: Card Services release "
-              "does not match!\n");
--      return -1;
-+      return -EINVAL;
-     }
-     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
-     return 0;
---- linux/drivers/input/Config.in~bluetooth-2.4.18-mh11        2001-09-13 00:34:06.000000000 +0200
-+++ linux/drivers/input/Config.in      2004-01-25 23:37:39.000000000 +0100
-@@ -14,5 +14,6 @@
- fi
- dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
- dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
-+dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT
- endmenu
---- linux/drivers/input/keybdev.c~bluetooth-2.4.18-mh11        2001-10-11 18:14:32.000000000 +0200
-+++ linux/drivers/input/keybdev.c      2004-01-25 23:37:39.000000000 +0100
-@@ -154,16 +154,18 @@
- static struct input_handler keybdev_handler;
-+static unsigned int ledstate = 0xff;
-+
- void keybdev_ledfunc(unsigned int led)
- {
-       struct input_handle *handle;    
--      for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-+      ledstate = led;
-+      for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-               input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
-               input_event(handle->dev, EV_LED, LED_NUML,    !!(led & 0x02));
-               input_event(handle->dev, EV_LED, LED_CAPSL,   !!(led & 0x04));
--
-       }
- }
-@@ -202,6 +204,12 @@
- //    printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
-+      if (ledstate != 0xff) {
-+              input_event(dev, EV_LED, LED_SCROLLL, !!(ledstate & 0x01));
-+              input_event(dev, EV_LED, LED_NUML,    !!(ledstate & 0x02));
-+              input_event(dev, EV_LED, LED_CAPSL,   !!(ledstate & 0x04));
-+      }
-+
-       return handle;
- }
---- linux/drivers/input/Makefile~bluetooth-2.4.18-mh11 2000-12-29 23:07:22.000000000 +0100
-+++ linux/drivers/input/Makefile       2004-01-25 23:37:39.000000000 +0100
-@@ -24,6 +24,7 @@
- obj-$(CONFIG_INPUT_MOUSEDEV)  += mousedev.o
- obj-$(CONFIG_INPUT_JOYDEV)    += joydev.o
- obj-$(CONFIG_INPUT_EVDEV)     += evdev.o
-+obj-$(CONFIG_INPUT_UINPUT)    += uinput.o
- # The global Rules.make.
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/drivers/input/uinput.c       2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,428 @@
-+/*
-+ *  User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * 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
-+ *
-+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ * 
-+ * Changes/Revisions:
-+ *    0.1     20/06/2002
-+ *            - first public version
-+ */
-+
-+#include <linux/poll.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/input.h>
-+#include <linux/smp_lock.h>
-+#include <linux/fs.h>
-+#include <linux/miscdevice.h>
-+#include <linux/uinput.h>
-+
-+static int uinput_dev_open(struct input_dev *dev)
-+{
-+      return 0;
-+}
-+
-+static void uinput_dev_close(struct input_dev *dev)
-+{
-+}
-+
-+static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-+{
-+      struct uinput_device    *udev;
-+
-+      udev = (struct uinput_device *)dev->private;
-+
-+      udev->buff[udev->head].type = type;
-+      udev->buff[udev->head].code = code;
-+      udev->buff[udev->head].value = value;
-+      do_gettimeofday(&udev->buff[udev->head].time);
-+      udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
-+
-+      wake_up_interruptible(&udev->waitq);
-+
-+      return 0;
-+}
-+
-+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-+{
-+      return 0;
-+}
-+
-+static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
-+{
-+      return 0;
-+}                                     
-+
-+static int uinput_create_device(struct uinput_device *udev)
-+{
-+      if (!udev->dev->name) {
-+              printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
-+              return -EINVAL;
-+      }
-+
-+      udev->dev->open = uinput_dev_open;
-+      udev->dev->close = uinput_dev_close;
-+      udev->dev->event = uinput_dev_event;
-+      udev->dev->upload_effect = uinput_dev_upload_effect;
-+      udev->dev->erase_effect = uinput_dev_erase_effect;
-+      udev->dev->private = udev;
-+
-+      init_waitqueue_head(&(udev->waitq));
-+
-+      input_register_device(udev->dev);
-+
-+      set_bit(UIST_CREATED, &(udev->state));
-+
-+      return 0;
-+}
-+
-+static int uinput_destroy_device(struct uinput_device *udev)
-+{
-+      if (!test_bit(UIST_CREATED, &(udev->state))) {
-+              printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
-+              return -EINVAL;
-+      }
-+
-+      input_unregister_device(udev->dev);
-+
-+      clear_bit(UIST_CREATED, &(udev->state));
-+
-+      return 0;
-+}
-+
-+static int uinput_open(struct inode *inode, struct file *file)
-+{
-+      struct uinput_device    *newdev;
-+      struct input_dev        *newinput;
-+
-+      newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
-+      if (!newdev)
-+              goto error;
-+      memset(newdev, 0, sizeof(struct uinput_device));
-+
-+      newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
-+      if (!newinput)
-+              goto cleanup;
-+      memset(newinput, 0, sizeof(struct input_dev));
-+
-+      newdev->dev = newinput;
-+      
-+      file->private_data = newdev;
-+
-+      return 0;
-+cleanup:
-+      kfree(newdev);
-+error:
-+      return -ENOMEM;
-+}
-+
-+static int uinput_validate_absbits(struct input_dev *dev)
-+{
-+      unsigned int cnt;
-+      int retval = 0;
-+      
-+      for (cnt = 0; cnt < ABS_MAX; cnt++) {
-+              if (!test_bit(cnt, dev->absbit)) 
-+                      continue;
-+              
-+              if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
-+                  (dev->absmax[cnt] <= dev->absmin[cnt])) {
-+                      printk(KERN_DEBUG 
-+                              "%s: invalid abs[%02x] min:%d max:%d\n",
-+                              UINPUT_NAME, cnt, 
-+                              dev->absmin[cnt], dev->absmax[cnt]);
-+                      retval = -EINVAL;
-+                      break;
-+              }
-+
-+              if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
-+                  (dev->absflat[cnt] > dev->absmax[cnt])) {
-+                      printk(KERN_DEBUG 
-+                              "%s: absflat[%02x] out of range: %d "
-+                              "(min:%d/max:%d)\n",
-+                              UINPUT_NAME, cnt, dev->absflat[cnt],
-+                              dev->absmin[cnt], dev->absmax[cnt]);
-+                      retval = -EINVAL;
-+                      break;
-+              }
-+      }
-+      return retval;
-+}
-+
-+static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
-+{
-+      struct uinput_user_dev  *user_dev;
-+      struct input_dev        *dev;
-+      struct uinput_device    *udev;
-+      int                     size,
-+                              retval;
-+
-+      retval = count;
-+
-+      udev = (struct uinput_device *)file->private_data;
-+      dev = udev->dev;
-+
-+      user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
-+      if (!user_dev) {
-+              retval = -ENOMEM;
-+              goto exit;
-+      }
-+
-+      if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
-+              retval = -EFAULT;
-+              goto exit;
-+      }
-+
-+      if (NULL != dev->name) 
-+              kfree(dev->name);
-+
-+      size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-+      dev->name = kmalloc(size, GFP_KERNEL);
-+      if (!dev->name) {
-+              retval = -ENOMEM;
-+              goto exit;
-+      }
-+
-+      strncpy(dev->name, user_dev->name, size);
-+      dev->idbus      = user_dev->idbus;
-+      dev->idvendor   = user_dev->idvendor;
-+      dev->idproduct  = user_dev->idproduct;
-+      dev->idversion  = user_dev->idversion;
-+      dev->ff_effects_max = user_dev->ff_effects_max;
-+
-+      size = sizeof(int) * (ABS_MAX + 1);
-+      memcpy(dev->absmax, user_dev->absmax, size);
-+      memcpy(dev->absmin, user_dev->absmin, size);
-+      memcpy(dev->absfuzz, user_dev->absfuzz, size);
-+      memcpy(dev->absflat, user_dev->absflat, size);
-+
-+      /* check if absmin/absmax/absfuzz/absflat are filled as
-+       * told in Documentation/input/input-programming.txt */
-+      if (test_bit(EV_ABS, dev->evbit)) {
-+              retval = uinput_validate_absbits(dev);
-+              if (retval < 0)
-+                      kfree(dev->name);
-+      }
-+
-+exit:
-+      kfree(user_dev);
-+      return retval;
-+}
-+
-+static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
-+{
-+      struct uinput_device    *udev = file->private_data;
-+      
-+      if (test_bit(UIST_CREATED, &(udev->state))) {
-+              struct input_event      ev;
-+
-+              if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
-+                      return -EFAULT;
-+              input_event(udev->dev, ev.type, ev.code, ev.value);
-+      }
-+      else
-+              count = uinput_alloc_device(file, buffer, count);
-+
-+      return count;
-+}
-+
-+static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-+{
-+      struct uinput_device *udev = file->private_data;
-+      int retval = 0;
-+      
-+      if (!test_bit(UIST_CREATED, &(udev->state)))
-+              return -ENODEV;
-+
-+      if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
-+              return -EAGAIN;
-+
-+      retval = wait_event_interruptible(udev->waitq,
-+                      (udev->head != udev->tail) || 
-+                      !test_bit(UIST_CREATED, &(udev->state)));
-+      
-+      if (retval)
-+              return retval;
-+
-+      if (!test_bit(UIST_CREATED, &(udev->state)))
-+              return -ENODEV;
-+
-+      while ((udev->head != udev->tail) && 
-+          (retval + sizeof(struct input_event) <= count)) {
-+              if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-+                  sizeof(struct input_event))) return -EFAULT;
-+              udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
-+              retval += sizeof(struct input_event);
-+      }
-+
-+      return retval;
-+}
-+
-+static unsigned int uinput_poll(struct file *file, poll_table *wait)
-+{
-+      struct uinput_device *udev = file->private_data;
-+
-+      poll_wait(file, &udev->waitq, wait);
-+
-+      if (udev->head != udev->tail)
-+              return POLLIN | POLLRDNORM;
-+
-+      return 0;                       
-+}
-+
-+static int uinput_burn_device(struct uinput_device *udev)
-+{
-+      if (test_bit(UIST_CREATED, &(udev->state)))
-+              uinput_destroy_device(udev);
-+
-+      kfree(udev->dev);
-+      kfree(udev);
-+
-+      return 0;
-+}
-+
-+static int uinput_close(struct inode *inode, struct file *file)
-+{
-+      return uinput_burn_device((struct uinput_device *)file->private_data);
-+}
-+
-+static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-+{
-+      int                     retval = 0;
-+      struct uinput_device    *udev;
-+
-+      udev = (struct uinput_device *)file->private_data;
-+
-+      /* device attributes can not be changed after the device is created */
-+      if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
-+              return -EINVAL;
-+
-+      switch (cmd) {
-+              case UI_DEV_CREATE:
-+                      retval = uinput_create_device(udev);
-+                      break;
-+                      
-+              case UI_DEV_DESTROY:
-+                      retval = uinput_destroy_device(udev);
-+                      break;
-+
-+              case UI_SET_EVBIT:
-+                      if (arg > EV_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->evbit);
-+                      break;
-+                      
-+              case UI_SET_KEYBIT:
-+                      if (arg > KEY_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->keybit);
-+                      break;
-+                      
-+              case UI_SET_RELBIT:
-+                      if (arg > REL_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->relbit);
-+                      break;
-+                      
-+              case UI_SET_ABSBIT:
-+                      if (arg > ABS_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->absbit);
-+                      break;
-+                      
-+              case UI_SET_MSCBIT:
-+                      if (arg > MSC_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->mscbit);
-+                      break;
-+                      
-+              case UI_SET_LEDBIT:
-+                      if (arg > LED_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->ledbit);
-+                      break;
-+                      
-+              case UI_SET_SNDBIT:
-+                      if (arg > SND_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->sndbit);
-+                      break;
-+                      
-+              case UI_SET_FFBIT:
-+                      if (arg > FF_MAX) {
-+                              retval = -EINVAL;
-+                              break;
-+                      }
-+                      set_bit(arg, udev->dev->ffbit);
-+                      break;
-+                      
-+              default:
-+                      retval = -EFAULT;
-+      }
-+      return retval;
-+}
-+
-+struct file_operations uinput_fops = {
-+      owner:          THIS_MODULE,
-+      open:           uinput_open,
-+      release:        uinput_close,
-+      read:           uinput_read,
-+      write:          uinput_write,
-+      poll:           uinput_poll,
-+      ioctl:          uinput_ioctl,
-+};
-+
-+static struct miscdevice uinput_misc = {
-+      fops:           &uinput_fops,
-+      minor:          UINPUT_MINOR,
-+      name:           UINPUT_NAME,
-+};
-+
-+static int __init uinput_init(void)
-+{
-+      return misc_register(&uinput_misc);
-+}
-+
-+static void __exit uinput_exit(void)
-+{
-+      misc_deregister(&uinput_misc);
-+}
-+
-+MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
-+MODULE_DESCRIPTION("User level driver support for input subsystem");
-+MODULE_LICENSE("GPL");
-+
-+module_init(uinput_init);
-+module_exit(uinput_exit);
-+
---- linux/drivers/isdn/avmb1/capidrv.c~bluetooth-2.4.18-mh11   2001-12-21 18:41:54.000000000 +0100
-+++ linux/drivers/isdn/avmb1/capidrv.c 2004-01-25 23:37:39.000000000 +0100
-@@ -514,13 +514,25 @@
- static void send_message(capidrv_contr * card, _cmsg * cmsg)
- {
--      struct sk_buff *skb;
--      size_t len;
-+      struct sk_buff  *skb;
-+      size_t          len;
-+      u16             err;
-+
-       capi_cmsg2message(cmsg, cmsg->buf);
-       len = CAPIMSG_LEN(cmsg->buf);
-       skb = alloc_skb(len, GFP_ATOMIC);
-+      if(!skb) {
-+              printk(KERN_ERR "no skb len(%d) memory\n", len);
-+              return;
-+      }
-       memcpy(skb_put(skb, len), cmsg->buf, len);
--      (*capifuncs->capi_put_message) (global.appid, skb);
-+      err = (*capifuncs->capi_put_message) (global.appid, skb);
-+      if (err) {
-+              printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
-+                      __FUNCTION__, err);
-+              kfree_skb(skb);
-+              return;
-+      }
-       global.nsentctlpkt++;
- }
-@@ -2179,10 +2191,10 @@
-                       free_ncci(card, card->bchans[card->nbchan-1].nccip);
-               if (card->bchans[card->nbchan-1].plcip)
-                       free_plci(card, card->bchans[card->nbchan-1].plcip);
--              if (card->plci_list)
--                      printk(KERN_ERR "capidrv: bug in free_plci()\n");
-               card->nbchan--;
-       }
-+      if (card->plci_list)
-+              printk(KERN_ERR "capidrv: bug in free_plci()\n");
-       kfree(card->bchans);
-       card->bchans = 0;
---- linux/drivers/isdn/avmb1/kcapi.c~bluetooth-2.4.18-mh11     2001-12-21 18:41:54.000000000 +0100
-+++ linux/drivers/isdn/avmb1/kcapi.c   2004-01-25 23:37:39.000000000 +0100
-@@ -545,7 +545,13 @@
- static void notify_up(__u32 contr)
- {
-       struct capi_interface_user *p;
-+      __u16 appl;
-+      for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
-+              if (!VALID_APPLID(appl)) continue;
-+              if (APPL(appl)->releasing) continue;
-+              CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam);
-+      }
-         printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
-       spin_lock(&capi_users_lock);
-       for (p = capi_users; p; p = p->next) {
-@@ -705,12 +711,16 @@
-                       nextpp = &(*pp)->next;
-               }
-       }
--      APPL(appl)->releasing--;
--      if (APPL(appl)->releasing <= 0) {
--              APPL(appl)->signal = 0;
--              APPL_MARK_FREE(appl);
--              printk(KERN_INFO "kcapi: appl %d down\n", appl);
--      }
-+      if (APPL(appl)->releasing) { /* only release if the application was marked for release */
-+              printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing);
-+              APPL(appl)->releasing--;
-+              if (APPL(appl)->releasing <= 0) {
-+                      APPL(appl)->signal = 0;
-+                      APPL_MARK_FREE(appl);
-+                      printk(KERN_INFO "kcapi: appl %d down\n", appl);
-+              }
-+      } else
-+              printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr);
- }
- /*
-  * ncci management
-@@ -863,16 +873,7 @@
- static void controllercb_ready(struct capi_ctr * card)
- {
--      __u16 appl;
--
-       card->cardstate = CARD_RUNNING;
--
--      for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
--              if (!VALID_APPLID(appl)) continue;
--              if (APPL(appl)->releasing) continue;
--              card->driver->register_appl(card, appl, &APPL(appl)->rparam);
--      }
--
-         printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
-               CARDNR(card), card->name);
---- linux/drivers/usb/Config.in~bluetooth-2.4.18-mh11  2004-01-25 23:28:22.000000000 +0100
-+++ linux/drivers/usb/Config.in        2004-01-25 23:37:39.000000000 +0100
-@@ -39,7 +39,13 @@
- comment 'USB Device Class drivers'
- dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
--dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+   if [ "$CONFIG_BLUEZ" = "n" ]; then
-+      dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
-+   else
-+      comment '  USB Bluetooth can only be used with disabled Bluetooth subsystem'
-+   fi
-+fi
- if [ "$CONFIG_SCSI" = "n" ]; then
-    comment '  SCSI support is needed for USB Storage'
- fi
---- linux/drivers/usb/hid-core.c~bluetooth-2.4.18-mh11 2001-12-21 18:41:55.000000000 +0100
-+++ linux/drivers/usb/hid-core.c       2004-01-25 23:37:39.000000000 +0100
-@@ -217,6 +217,8 @@
-       offset = report->size;
-       report->size += parser->global.report_size * parser->global.report_count;
-+      if (usages < parser->global.report_count)
-+              usages = parser->global.report_count;
-       if (usages == 0)
-               return 0; /* ignore padding fields */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/firmware.h     2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,20 @@
-+#ifndef _LINUX_FIRMWARE_H
-+#define _LINUX_FIRMWARE_H
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#define FIRMWARE_NAME_MAX 30 
-+struct firmware {
-+      size_t size;
-+      u8 *data;
-+};
-+int request_firmware (const struct firmware **fw, const char *name,
-+                    const char *device);
-+int request_firmware_nowait (
-+      struct module *module,
-+      const char *name, const char *device, void *context,
-+      void (*cont)(const struct firmware *fw, void *context));
-+/* On 2.5 'device' is 'struct device *' */
-+
-+void release_firmware (const struct firmware *fw);
-+void register_firmware (const char *name, const u8 *data, size_t size);
-+#endif
---- linux/include/linux/input.h~bluetooth-2.4.18-mh11  2001-09-13 00:34:06.000000000 +0200
-+++ linux/include/linux/input.h        2004-01-25 23:37:39.000000000 +0100
-@@ -468,6 +468,8 @@
- #define BUS_PCI                       0x01
- #define BUS_ISAPNP            0x02
- #define BUS_USB                       0x03
-+#define BUS_HIL                       0x04
-+#define BUS_BLUETOOTH         0x05
- #define BUS_ISA                       0x10
- #define BUS_I8042             0x11
---- linux/include/linux/kernel.h~bluetooth-2.4.18-mh11 2002-02-25 20:38:13.000000000 +0100
-+++ linux/include/linux/kernel.h       2004-01-25 23:37:39.000000000 +0100
-@@ -11,6 +11,7 @@
- #include <linux/linkage.h>
- #include <linux/stddef.h>
- #include <linux/types.h>
-+#include <linux/compiler.h>
- /* Optimization barrier */
- /* The "volatile" is due to gcc bugs */
-@@ -181,4 +182,6 @@
-       char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
- };
--#endif
-+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-+
-+#endif /* _LINUX_KERNEL_H */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/linux/uinput.h       2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,79 @@
-+/*
-+ *  User level driver support for input subsystem
-+ *
-+ * Heavily based on evdev.c by Vojtech Pavlik
-+ *
-+ * 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
-+ *
-+ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
-+ * 
-+ * Changes/Revisions:
-+ *    0.1     20/06/2002
-+ *            - first public version
-+ */
-+
-+#ifndef __UINPUT_H_
-+#define __UINPUT_H_
-+
-+#ifdef __KERNEL__
-+#define UINPUT_MINOR          223
-+#define UINPUT_NAME           "uinput"
-+#define UINPUT_BUFFER_SIZE    16
-+
-+/* state flags => bit index for {set|clear|test}_bit ops */
-+#define UIST_CREATED          0
-+
-+struct uinput_device {
-+      struct input_dev        *dev;
-+      unsigned long           state;
-+      wait_queue_head_t       waitq;
-+      unsigned char           ready,
-+                              head,
-+                              tail;
-+      struct input_event      buff[UINPUT_BUFFER_SIZE];
-+};
-+#endif        /* __KERNEL__ */
-+
-+/* ioctl */
-+#define UINPUT_IOCTL_BASE     'U'
-+#define UI_DEV_CREATE         _IO(UINPUT_IOCTL_BASE, 1)
-+#define UI_DEV_DESTROY                _IO(UINPUT_IOCTL_BASE, 2)
-+#define UI_SET_EVBIT          _IOW(UINPUT_IOCTL_BASE, 100, int)
-+#define UI_SET_KEYBIT         _IOW(UINPUT_IOCTL_BASE, 101, int)
-+#define UI_SET_RELBIT         _IOW(UINPUT_IOCTL_BASE, 102, int)
-+#define UI_SET_ABSBIT         _IOW(UINPUT_IOCTL_BASE, 103, int)
-+#define UI_SET_MSCBIT         _IOW(UINPUT_IOCTL_BASE, 104, int)
-+#define UI_SET_LEDBIT         _IOW(UINPUT_IOCTL_BASE, 105, int)
-+#define UI_SET_SNDBIT         _IOW(UINPUT_IOCTL_BASE, 106, int)
-+#define UI_SET_FFBIT          _IOW(UINPUT_IOCTL_BASE, 107, int)
-+
-+#ifndef NBITS
-+#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
-+#endif        /* NBITS */
-+
-+#define UINPUT_MAX_NAME_SIZE  80
-+struct uinput_user_dev {
-+      char name[UINPUT_MAX_NAME_SIZE];
-+      unsigned short idbus;
-+      unsigned short idvendor;
-+      unsigned short idproduct;
-+      unsigned short idversion;
-+      int ff_effects_max;
-+      int absmax[ABS_MAX + 1];
-+      int absmin[ABS_MAX + 1];
-+      int absfuzz[ABS_MAX + 1];
-+      int absflat[ABS_MAX + 1];
-+};
-+#endif        /* __UINPUT_H_ */
---- linux/include/net/bluetooth/bluetooth.h~bluetooth-2.4.18-mh11      2001-09-07 18:28:38.000000000 +0200
-+++ linux/include/net/bluetooth/bluetooth.h    2004-01-25 23:37:39.000000000 +0100
-@@ -23,7 +23,7 @@
- */
- /*
-- *  $Id: bluetooth.h,v 1.6 2001/08/03 04:19:49 maxk Exp $
-+ *  $Id: bluetooth.h,v 1.9 2002/05/06 21:11:55 maxk Exp $
-  */
- #ifndef __BLUETOOTH_H
-@@ -31,17 +31,63 @@
- #include <asm/types.h>
- #include <asm/byteorder.h>
-+#include <linux/poll.h>
-+#include <net/sock.h>
- #ifndef AF_BLUETOOTH
- #define AF_BLUETOOTH  31
- #define PF_BLUETOOTH  AF_BLUETOOTH
- #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_HCI     1
-+#define BTPROTO_SCO           2
-+#define BTPROTO_RFCOMM        3
-+#define BTPROTO_BNEP  4
-+#define BTPROTO_CMTP  5
- #define SOL_HCI     0
- #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 */
- enum {
-@@ -50,6 +96,7 @@
-       BT_BOUND,
-       BT_LISTEN,
-       BT_CONNECT,
-+      BT_CONNECT2,
-       BT_CONFIG,
-       BT_DISCONN,
-       BT_CLOSED
-@@ -66,7 +113,8 @@
-       __u8 b[6];
- } __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 */
- static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
-@@ -82,6 +130,91 @@
- char *batostr(bdaddr_t *ba);
- bdaddr_t *strtoba(char *str);
-+/* Common socket structures and functions */
-+
-+#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
-+#define bluez_sk(pi) ((struct sock *) \
-+      ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
-+
-+struct bluez_pinfo {
-+      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);
-+void bluez_sock_init(struct socket *sock, struct sock *sk);
-+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_wait_state(struct sock *sk, int state, unsigned long timeo);
-+
-+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);
-+#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 */
---- linux/include/net/bluetooth/bluez.h~bluetooth-2.4.18-mh11
-+++ linux/include/net/bluetooth/bluez.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 */
---- linux/include/net/bluetooth/hci_core.h~bluetooth-2.4.18-mh11       2001-09-07 18:28:38.000000000 +0200
-+++ linux/include/net/bluetooth/hci_core.h     2004-01-25 23:37:39.000000000 +0100
-@@ -23,7 +23,7 @@
- */
- /* 
-- * $Id: hci_core.h,v 1.11 2001/08/05 06:02:15 maxk Exp $ 
-+ * $Id: hci_core.h,v 1.5 2002/06/27 04:56:30 maxk Exp $ 
-  */
- #ifndef __HCI_CORE_H
-@@ -32,14 +32,12 @@
- #include <net/bluetooth/hci.h>
- /* HCI upper protocols */
--#define HCI_MAX_PROTO         1
- #define HCI_PROTO_L2CAP       0
-+#define HCI_PROTO_SCO 1
- #define HCI_INIT_TIMEOUT (HZ * 10)
--/* ----- Inquiry cache ----- */
--#define INQUIRY_CACHE_AGE_MAX   (HZ*5)    // 5 seconds
--#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
-+/* HCI Core structures */
- struct inquiry_entry {
-       struct inquiry_entry    *next;
-@@ -53,111 +51,186 @@
-       struct inquiry_entry    *list;
- };
--static inline void inquiry_cache_init(struct inquiry_cache *cache)
--{
--      spin_lock_init(&cache->lock);
--      cache->list = NULL;
--}
-+struct conn_hash {
-+      struct list_head list;
-+      spinlock_t       lock;
-+      unsigned int     num;
-+};
--static inline void inquiry_cache_lock(struct inquiry_cache *cache)
--{
--      spin_lock(&cache->lock);
--}
-+struct hci_dev {
-+      struct list_head list;
-+      spinlock_t      lock;
-+      atomic_t        refcnt;
--static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
--{
--      spin_unlock(&cache->lock);
--}
-+      char            name[8];
-+      unsigned long   flags;
-+      __u16           id;
-+      __u8            type;
-+      bdaddr_t        bdaddr;
-+      __u8            features[8];
--static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
--{
--      spin_lock_bh(&cache->lock);
--}
-+      __u16           pkt_type;
-+      __u16           link_policy;
-+      __u16           link_mode;
-+      
-+      atomic_t        cmd_cnt;
-+      unsigned int    acl_cnt;
-+      unsigned int    sco_cnt;
--static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
--{
--      spin_unlock_bh(&cache->lock);
--}
-+      unsigned int    acl_mtu;
-+      unsigned int    sco_mtu;
-+      unsigned int    acl_pkts;
-+      unsigned int    sco_pkts;
--static inline long inquiry_cache_age(struct inquiry_cache *cache)
--{
--      return jiffies - cache->timestamp;
--}
-+      unsigned long   cmd_last_tx;
-+      unsigned long   acl_last_tx;
-+      unsigned long   sco_last_tx;
-+      
-+      struct tasklet_struct   cmd_task;
-+      struct tasklet_struct   rx_task;
-+      struct tasklet_struct   tx_task;
--static inline long inquiry_entry_age(struct inquiry_entry *e)
--{
--      return jiffies - e->timestamp;
--}
--extern void inquiry_cache_flush(struct inquiry_cache *cache);
-+      struct sk_buff_head     rx_q;
-+      struct sk_buff_head     raw_q;
-+      struct sk_buff_head     cmd_q;
--struct hci_dev;
-+      struct sk_buff          *sent_cmd;
-+
-+      struct semaphore        req_lock;
-+      wait_queue_head_t       req_wait_q;
-+      __u32                   req_status;
-+      __u32                   req_result;
-+
-+      struct inquiry_cache    inq_cache;
-+      struct conn_hash        conn_hash;
-+
-+      struct hci_dev_stats    stat;
-+
-+      void                    *driver_data;
-+      void                    *core_data;
-+
-+      atomic_t                promisc;
-+
-+      int (*open)(struct hci_dev *hdev);
-+      int (*close)(struct hci_dev *hdev);
-+      int (*flush)(struct hci_dev *hdev);
-+      int (*send)(struct sk_buff *skb);
-+      void (*destruct)(struct hci_dev *hdev);
-+      int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
-+};
--/* ----- HCI Connections ----- */
- struct hci_conn {
-       struct list_head list;
-+
-+      atomic_t         refcnt;
-+      spinlock_t       lock;
-+
-       bdaddr_t         dst;
-       __u16            handle;
-+      __u16            state;
-       __u8             type;
--      unsigned int     sent;
-+      __u8             out;
-+      __u32            link_mode;
-+      unsigned long    pend;
-+      
-+      unsigned int     sent;
-+      
-+      struct sk_buff_head data_q;
-+      struct timer_list timer;
-+      
-       struct hci_dev  *hdev;
-       void            *l2cap_data;
-+      void            *sco_data;
-       void            *priv;
--      struct sk_buff_head data_q;
-+      struct hci_conn *link;
- };
--struct conn_hash {
--      struct list_head list;
--      spinlock_t       lock;
--      unsigned int     num;
--};
-+extern struct hci_proto *hci_proto[];
-+extern struct list_head hdev_list;
-+extern rwlock_t hdev_list_lock;
--static inline void conn_hash_init(struct conn_hash *h)
-+/* ----- Inquiry cache ----- */
-+#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
-+#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
-+
-+#define inquiry_cache_lock(c)         spin_lock(&c->lock)
-+#define inquiry_cache_unlock(c)               spin_unlock(&c->lock)
-+#define inquiry_cache_lock_bh(c)      spin_lock_bh(&c->lock)
-+#define inquiry_cache_unlock_bh(c)    spin_unlock_bh(&c->lock)
-+
-+static inline void inquiry_cache_init(struct hci_dev *hdev)
- {
--      INIT_LIST_HEAD(&h->list);
--      spin_lock_init(&h->lock);
--      h->num = 0;     
-+      struct inquiry_cache *c = &hdev->inq_cache;
-+      spin_lock_init(&c->lock);
-+      c->list = NULL;
- }
--static inline void conn_hash_lock(struct conn_hash *h)
-+static inline int inquiry_cache_empty(struct hci_dev *hdev)
- {
--      spin_lock(&h->lock);
-+      struct inquiry_cache *c = &hdev->inq_cache;
-+      return (c->list == NULL);
- }
--static inline void conn_hash_unlock(struct conn_hash *h)
-+static inline long inquiry_cache_age(struct hci_dev *hdev)
- {
--      spin_unlock(&h->lock);
-+      struct inquiry_cache *c = &hdev->inq_cache;
-+      return jiffies - c->timestamp;
- }
--static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+static inline long inquiry_entry_age(struct inquiry_entry *e)
- {
--      list_add(&c->list, &h->list);
--      h->num++;
-+      return jiffies - e->timestamp;
- }
--static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
-+void inquiry_cache_flush(struct hci_dev *hdev);
-+int  inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
-+
-+/* ----- HCI Connections ----- */
-+enum {
-+      HCI_CONN_AUTH_PEND,
-+      HCI_CONN_ENCRYPT_PEND
-+};
-+
-+#define hci_conn_lock(c)      spin_lock(&c->lock)
-+#define hci_conn_unlock(c)    spin_unlock(&c->lock)
-+#define hci_conn_lock_bh(c)   spin_lock_bh(&c->lock)
-+#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock)
-+
-+#define conn_hash_lock(d)     spin_lock(&d->conn_hash->lock)
-+#define conn_hash_unlock(d)   spin_unlock(&d->conn_hash->lock)
-+#define conn_hash_lock_bh(d)  spin_lock_bh(&d->conn_hash->lock)
-+#define conn_hash_unlock_bh(d)        spin_unlock_bh(&d->conn_hash->lock)
-+
-+static inline void conn_hash_init(struct hci_dev *hdev)
- {
--      conn_hash_lock(h);
--      __conn_hash_add(h, handle, c);
--      conn_hash_unlock(h);
-+      struct conn_hash *h = &hdev->conn_hash;
-+      INIT_LIST_HEAD(&h->list);
-+      spin_lock_init(&h->lock);
-+      h->num = 0;     
- }
--static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-+static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
- {
--      list_del(&c->list);
--      h->num--;
-+      struct conn_hash *h = &hdev->conn_hash;
-+      list_add(&c->list, &h->list);
-+      h->num++;
- }
--static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
-+static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
- {
--      conn_hash_lock(h);
--      __conn_hash_del(h, c);
--      conn_hash_unlock(h);
-+      struct conn_hash *h = &hdev->conn_hash;
-+      list_del(&c->list);
-+      h->num--;
- }
--static inline  struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
-+                                      __u16 handle)
- {
-+      register struct conn_hash *h = &hdev->conn_hash;
-       register struct list_head *p;
-       register struct hci_conn  *c;
-@@ -169,101 +242,97 @@
-         return NULL;
- }
--static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
-+static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
-+                                      __u8 type, bdaddr_t *ba)
- {
--      struct hci_conn *conn;
-+      register struct conn_hash *h = &hdev->conn_hash;
-+      register struct list_head *p;
-+      register struct hci_conn  *c;
--      conn_hash_lock(h);
--      conn = __conn_hash_lookup(h, handle);
--      conn_hash_unlock(h);
--      return conn;
-+      list_for_each(p, &h->list) {
-+              c = list_entry(p, struct hci_conn, list);
-+              if (c->type == type && !bacmp(&c->dst, ba))
-+                      return c;
-+      }
-+        return NULL;
- }
--/* ----- HCI Devices ----- */
--struct hci_dev {
--      atomic_t        refcnt;
--
--      char            name[8];
--      __u32           flags;
--      __u16           id;
--      __u8            type;
--      bdaddr_t        bdaddr;
--      __u8            features[8];
--
--      __u16           pkt_type;
--
--      atomic_t        cmd_cnt;
--      unsigned int    acl_cnt;
--      unsigned int    sco_cnt;
--
--      unsigned int    acl_mtu;
--      unsigned int    sco_mtu;
--      unsigned int    acl_max;
--      unsigned int    sco_max;
--
--      void            *driver_data;
--      void            *l2cap_data;
--      void            *priv;
--
--      struct tasklet_struct   cmd_task;
--      struct tasklet_struct   rx_task;
--      struct tasklet_struct   tx_task;
--
--      struct sk_buff_head     rx_q;
--      struct sk_buff_head     raw_q;
--      struct sk_buff_head     cmd_q;
--
--      struct sk_buff          *sent_cmd;
--
--      struct semaphore        req_lock;
--      wait_queue_head_t       req_wait_q;
--      __u32                   req_status;
--      __u32                   req_result;
-+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);
--      struct inquiry_cache    inq_cache;
-+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);
--      struct conn_hash        conn_hash;
-+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
-+int hci_conn_auth(struct hci_conn *conn);
-+int hci_conn_encrypt(struct hci_conn *conn);
--      struct hci_dev_stats    stat;
-+static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
-+{
-+      mod_timer(&conn->timer, jiffies + timeout);
-+}
--      int (*open)(struct hci_dev *hdev);
--      int (*close)(struct hci_dev *hdev);
--      int (*flush)(struct hci_dev *hdev);
--      int (*send)(struct sk_buff *skb);
--};
-+static inline void hci_conn_del_timer(struct hci_conn *conn)
-+{
-+      del_timer(&conn->timer);
-+}
--static inline void hci_dev_hold(struct hci_dev *hdev)
-+static inline void hci_conn_hold(struct hci_conn *conn)
- {
--      atomic_inc(&hdev->refcnt);
-+      atomic_inc(&conn->refcnt);
-+      hci_conn_del_timer(conn);
- }
--static inline void hci_dev_put(struct hci_dev *hdev)
-+static inline void hci_conn_put(struct hci_conn *conn)
- {
--      atomic_dec(&hdev->refcnt);
-+      if (atomic_dec_and_test(&conn->refcnt)) {
-+              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);
-+      }
- }
--extern struct hci_dev *hci_dev_get(int index);
--extern int hci_register_dev(struct hci_dev *hdev);
--extern int hci_unregister_dev(struct hci_dev *hdev);
--extern int hci_dev_open(__u16 dev);
--extern int hci_dev_close(__u16 dev);
--extern int hci_dev_reset(__u16 dev);
--extern int hci_dev_reset_stat(__u16 dev);
--extern int hci_dev_info(unsigned long arg);
--extern int hci_dev_list(unsigned long arg);
--extern int hci_dev_setscan(unsigned long arg);
--extern int hci_dev_setauth(unsigned long arg);
--extern int hci_dev_setptype(unsigned long arg);
--extern int hci_conn_list(unsigned long arg);
--extern int hci_inquiry(unsigned long arg);
-+/* ----- HCI Devices ----- */
-+static inline void hci_dev_put(struct hci_dev *d)
-+{ 
-+      if (atomic_dec_and_test(&d->refcnt))
-+              d->destruct(d);
-+}
-+#define hci_dev_hold(d)               atomic_inc(&d->refcnt)
--extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
--extern __u32 hci_dev_getmode(struct hci_dev *hdev);
-+#define hci_dev_lock(d)               spin_lock(&d->lock)
-+#define hci_dev_unlock(d)     spin_unlock(&d->lock)
-+#define hci_dev_lock_bh(d)    spin_lock_bh(&d->lock)
-+#define hci_dev_unlock_bh(d)  spin_unlock_bh(&d->lock)
--extern int hci_recv_frame(struct sk_buff *skb);
-+struct hci_dev *hci_dev_get(int index);
-+struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
-+int hci_register_dev(struct hci_dev *hdev);
-+int hci_unregister_dev(struct hci_dev *hdev);
-+int hci_suspend_dev(struct hci_dev *hdev);
-+int hci_resume_dev(struct hci_dev *hdev);
-+int hci_dev_open(__u16 dev);
-+int hci_dev_close(__u16 dev);
-+int hci_dev_reset(__u16 dev);
-+int hci_dev_reset_stat(__u16 dev);
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg);
-+int hci_get_dev_list(unsigned long arg);
-+int hci_get_dev_info(unsigned long arg);
-+int hci_get_conn_list(unsigned long arg);
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
-+int hci_inquiry(unsigned long arg);
-+
-+int  hci_recv_frame(struct sk_buff *skb);
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
- /* ----- LMP capabilities ----- */
- #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
-+#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
- /* ----- HCI tasks ----- */
- static inline void hci_sched_cmd(struct hci_dev *hdev)
-@@ -284,43 +353,130 @@
- /* ----- HCI protocols ----- */
- struct hci_proto {
-       char            *name;
--      __u32           id;
--      __u32           flags;
-+      unsigned int    id;
-+      unsigned long   flags;
-       void            *priv;
--      int (*connect_ind)      (struct hci_dev *hdev, bdaddr_t *bdaddr);
--      int (*connect_cfm)      (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
-+      int (*connect_ind)      (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
-+      int (*connect_cfm)      (struct hci_conn *conn, __u8 status);
-       int (*disconn_ind)      (struct hci_conn *conn, __u8 reason);
--      int (*recv_acldata)     (struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
-+      int (*recv_acldata)     (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
-       int (*recv_scodata)     (struct hci_conn *conn, struct sk_buff *skb);
-+      int (*auth_cfm)         (struct hci_conn *conn, __u8 status);
-+      int (*encrypt_cfm)      (struct hci_conn *conn, __u8 status);
- };
--extern int hci_register_proto(struct hci_proto *hproto);
--extern int hci_unregister_proto(struct hci_proto *hproto);
--extern int hci_register_notifier(struct notifier_block *nb);
--extern int hci_unregister_notifier(struct notifier_block *nb);
--extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
--extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
--extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
--extern int hci_send_raw(struct sk_buff *skb);
--extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
--extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
-+static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+      register struct hci_proto *hp;
-+      int mask = 0;
-+      
-+      hp = hci_proto[HCI_PROTO_L2CAP];
-+      if (hp && hp->connect_ind)
-+              mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+      hp = hci_proto[HCI_PROTO_SCO];
-+      if (hp && hp->connect_ind)
-+              mask |= hp->connect_ind(hdev, bdaddr, type);
-+
-+      return mask;
-+}
-+
-+static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
-+{
-+      register struct hci_proto *hp;
-+
-+      hp = hci_proto[HCI_PROTO_L2CAP];
-+      if (hp && hp->connect_cfm)
-+              hp->connect_cfm(conn, status);
-+
-+      hp = hci_proto[HCI_PROTO_SCO];
-+      if (hp && hp->connect_cfm)
-+              hp->connect_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
-+{
-+      register struct hci_proto *hp;
-+
-+      hp = hci_proto[HCI_PROTO_L2CAP];
-+      if (hp && hp->disconn_ind)
-+              hp->disconn_ind(conn, reason);
-+
-+      hp = hci_proto[HCI_PROTO_SCO];
-+      if (hp && hp->disconn_ind)
-+              hp->disconn_ind(conn, reason);
-+}
-+
-+static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
-+{
-+      register struct hci_proto *hp;
-+
-+      hp = hci_proto[HCI_PROTO_L2CAP];
-+      if (hp && hp->auth_cfm)
-+              hp->auth_cfm(conn, status);
-+
-+      hp = hci_proto[HCI_PROTO_SCO];
-+      if (hp && hp->auth_cfm)
-+              hp->auth_cfm(conn, status);
-+}
-+
-+static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
-+{
-+      register struct hci_proto *hp;
-+
-+      hp = hci_proto[HCI_PROTO_L2CAP];
-+      if (hp && hp->encrypt_cfm)
-+              hp->encrypt_cfm(conn, status);
-+
-+      hp = hci_proto[HCI_PROTO_SCO];
-+      if (hp && hp->encrypt_cfm)
-+              hp->encrypt_cfm(conn, status);
-+}
-+
-+int hci_register_proto(struct hci_proto *hproto);
-+int hci_unregister_proto(struct hci_proto *hproto);
-+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_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_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
- /* ----- HCI Sockets ----- */
--extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
-+void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
- /* HCI info for socket */
--#define hci_pi(sk)    ((struct hci_pinfo *) &sk->protinfo)
-+#define hci_pi(sk)    ((struct hci_pinfo *) &sk->tp_pinfo)
- struct hci_pinfo {
-       struct hci_dev    *hdev;
-       struct hci_filter filter;
-       __u32             cmsg_mask;
- };
-+/* HCI security filter */
-+#define HCI_SFLT_MAX_OGF  5
-+
-+struct hci_sec_filter {
-+      __u32 type_mask;
-+      __u32 event_mask[2];
-+      __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
-+};
-+
- /* ----- HCI requests ----- */
- #define HCI_REQ_DONE    0
- #define HCI_REQ_PEND    1
- #define HCI_REQ_CANCELED  2
-+#define hci_req_lock(d)               down(&d->req_lock)
-+#define hci_req_unlock(d)     up(&d->req_lock)
-+
-+void hci_req_complete(struct hci_dev *hdev, int result);
-+void hci_req_cancel(struct hci_dev *hdev, int err);
-+
- #endif /* __HCI_CORE_H */
---- linux/include/net/bluetooth/hci.h~bluetooth-2.4.18-mh11    2001-09-07 18:28:38.000000000 +0200
-+++ linux/include/net/bluetooth/hci.h  2004-01-25 23:37:39.000000000 +0100
-@@ -23,59 +23,75 @@
- */
- /*
-- *  $Id: hci.h,v 1.15 2001/08/05 06:02:15 maxk Exp $
-+ *  $Id: hci.h,v 1.5 2002/06/27 17:29:30 maxk Exp $
-  */
- #ifndef __HCI_H
- #define __HCI_H
--#include <asm/byteorder.h>
--
--#define HCI_MAX_DEV   8
--#define HCI_MAX_FRAME_SIZE    2048
-+#define HCI_MAX_ACL_SIZE      1024
-+#define HCI_MAX_SCO_SIZE      255
-+#define HCI_MAX_EVENT_SIZE    260
-+#define HCI_MAX_FRAME_SIZE    (HCI_MAX_ACL_SIZE + 4)
- /* HCI dev events */
- #define HCI_DEV_REG   1
- #define HCI_DEV_UNREG   2
- #define HCI_DEV_UP    3
- #define HCI_DEV_DOWN  4
-+#define HCI_DEV_SUSPEND       5
-+#define HCI_DEV_RESUME        6
- /* HCI device types */
--#define HCI_UART      0
-+#define HCI_VHCI      0
- #define HCI_USB               1
--#define HCI_VHCI      2
-+#define HCI_PCCARD    2
-+#define HCI_UART      3
-+#define HCI_RS232     4
-+#define HCI_PCI               5
--/* HCI device modes */
--#define HCI_NORMAL    0x0001
--#define HCI_RAW               0x0002
--#define HCI_MODE_MASK   (HCI_NORMAL | HCI_RAW)
--#define HCI_SOCK      0x1000
-+/* HCI device flags */
-+enum {
-+      HCI_UP,
-+      HCI_INIT,
-+      HCI_RUNNING,
--/* HCI device states */
--#define HCI_INIT      0x0010
--#define HCI_UP                0x0020
--#define HCI_RUNNING   0x0040
-+      HCI_PSCAN,
-+      HCI_ISCAN,
-+      HCI_AUTH,
-+      HCI_ENCRYPT,
-+      HCI_INQUIRY,
--/* HCI device flags */
--#define HCI_PSCAN     0x0100
--#define HCI_ISCAN     0x0200
--#define HCI_AUTH      0x0400
-+      HCI_RAW
-+};
--/* HCI Ioctl defines */
-+/* HCI ioctl defines */
- #define HCIDEVUP        _IOW('H', 201, int)
- #define HCIDEVDOWN      _IOW('H', 202, int)
- #define HCIDEVRESET     _IOW('H', 203, int)
--#define HCIRESETSTAT    _IOW('H', 204, int)
--#define HCIGETINFO      _IOR('H', 205, int)
--#define HCIGETDEVLIST   _IOR('H', 206, int)
--#define HCISETRAW       _IOW('H', 207, int)
--#define HCISETSCAN      _IOW('H', 208, int)
--#define HCISETAUTH      _IOW('H', 209, int)
--#define HCIINQUIRY      _IOR('H', 210, int)
--#define HCISETPTYPE     _IOW('H', 211, int)
-+#define HCIDEVRESTAT    _IOW('H', 204, int)
-+
-+#define HCIGETDEVLIST   _IOR('H', 210, int)
-+#define HCIGETDEVINFO   _IOR('H', 211, int)
- #define HCIGETCONNLIST  _IOR('H', 212, int)
-+#define HCIGETCONNINFO  _IOR('H', 213, int)
--#ifndef __NO_HCI_DEFS
-+#define HCISETRAW       _IOW('H', 220, int)
-+#define HCISETSCAN      _IOW('H', 221, int)
-+#define HCISETAUTH      _IOW('H', 222, int)
-+#define HCISETENCRYPT   _IOW('H', 223, int)
-+#define HCISETPTYPE     _IOW('H', 224, int)
-+#define HCISETLINKPOL   _IOW('H', 225, int)
-+#define HCISETLINKMODE  _IOW('H', 226, int)
-+#define HCISETACLMTU    _IOW('H', 227, int)
-+#define HCISETSCOMTU    _IOW('H', 228, int)
-+
-+#define HCIINQUIRY      _IOR('H', 240, int)
-+
-+/* HCI timeouts */
-+#define HCI_CONN_TIMEOUT      (HZ * 40)
-+#define HCI_DISCONN_TIMEOUT   (HZ * 2)
-+#define HCI_CONN_IDLE_TIMEOUT (HZ * 60)
- /* HCI Packet types */
- #define HCI_COMMAND_PKT               0x01
-@@ -92,11 +108,18 @@
- #define HCI_DH3       0x0800
- #define HCI_DH5       0x8000
-+#define HCI_HV1               0x0020
-+#define HCI_HV2               0x0040
-+#define HCI_HV3               0x0080
-+
-+#define SCO_PTYPE_MASK        (HCI_HV1 | HCI_HV2 | HCI_HV3)
-+#define ACL_PTYPE_MASK        (~SCO_PTYPE_MASK)
-+
- /* ACL flags */
--#define ACL_CONT              0x0001
--#define ACL_START             0x0002
--#define ACL_ACTIVE_BCAST      0x0010
--#define ACL_PICO_BCAST                0x0020
-+#define ACL_CONT              0x01
-+#define ACL_START             0x02
-+#define ACL_ACTIVE_BCAST      0x04
-+#define ACL_PICO_BCAST                0x08
- /* Baseband links */
- #define SCO_LINK      0x00
-@@ -125,6 +148,20 @@
- #define LMP_PSCHEME   0x02
- #define LMP_PCONTROL  0x04
-+/* Link policies */
-+#define HCI_LP_RSWITCH        0x0001
-+#define HCI_LP_HOLD   0x0002
-+#define HCI_LP_SNIFF  0x0004
-+#define HCI_LP_PARK   0x0008
-+
-+/* Link mode */
-+#define HCI_LM_ACCEPT 0x8000
-+#define HCI_LM_MASTER 0x0001
-+#define HCI_LM_AUTH   0x0002
-+#define HCI_LM_ENCRYPT        0x0004
-+#define HCI_LM_TRUSTED        0x0008
-+#define HCI_LM_RELIABLE       0x0010
-+
- /* -----  HCI Commands ----- */
- /* OGF & OCF values */
-@@ -137,9 +174,10 @@
-       __u8  hci_ver;
-       __u16 hci_rev;
-       __u8  lmp_ver;
--      __u16 man_name;
--      __u16 lmp_sub;
-+      __u16 manufacturer;
-+      __u16 lmp_subver;
- } __attribute__ ((packed)) read_local_version_rp;
-+#define READ_LOCAL_VERSION_RP_SIZE 9
- #define OCF_READ_LOCAL_FEATURES       0x0003
- typedef struct {
-@@ -165,18 +203,24 @@
- /* 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 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 SCANS_DISABLED          0x00
--      #define IS_ENA_PS_DIS           0x01
--      #define IS_DIS_PS_ENA           0x02
--      #define IS_ENA_PS_ENA           0x03
-+      #define SCAN_DISABLED           0x00
-+      #define SCAN_INQUIRY            0x01
-+      #define SCAN_PAGE               0x02
- #define OCF_SET_EVENT_FLT     0x0005
- typedef struct {
-@@ -226,9 +270,18 @@
- } __attribute__ ((packed)) write_class_of_dev_cp;
- #define WRITE_CLASS_OF_DEV_CP_SIZE 3
-+#define OCF_HOST_BUFFER_SIZE  0x0033
-+typedef struct {
-+      __u16   acl_mtu;
-+      __u8    sco_mtu;
-+      __u16   acl_max_pkt;
-+      __u16   sco_max_pkt;
-+} __attribute__ ((packed)) host_buffer_size_cp;
-+#define HOST_BUFFER_SIZE_CP_SIZE 7
-+
- /* Link Control */
- #define OGF_LINK_CTL  0x01 
--#define OCF_CREATE_CONN       0x0005
-+#define OCF_CREATE_CONN               0x0005
- typedef struct {
-       bdaddr_t bdaddr;
-       __u16   pkt_type;
-@@ -246,6 +299,13 @@
- } __attribute__ ((packed)) accept_conn_req_cp;
- #define ACCEPT_CONN_REQ_CP_SIZE       7
-+#define OCF_REJECT_CONN_REQ   0x000a
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8    reason;
-+} __attribute__ ((packed)) reject_conn_req_cp;
-+#define REJECT_CONN_REQ_CP_SIZE       7
-+
- #define OCF_DISCONNECT        0x0006
- typedef struct {
-       __u16   handle;
-@@ -253,17 +313,142 @@
- } __attribute__ ((packed)) disconnect_cp;
- #define DISCONNECT_CP_SIZE 3
-+#define OCF_ADD_SCO   0x0007
-+typedef struct {
-+      __u16   handle;
-+      __u16   pkt_type;
-+} __attribute__ ((packed)) add_sco_cp;
-+#define ADD_SCO_CP_SIZE 4
-+
- #define OCF_INQUIRY           0x0001
- typedef struct {
-       __u8    lap[3];
--      __u8    lenght;
-+      __u8    length;
-       __u8    num_rsp;
- } __attribute__ ((packed)) inquiry_cp;
- #define INQUIRY_CP_SIZE 5
--#define OGF_LINK_POLICY               0x02   /* Link Policy */
-+typedef struct {
-+      __u8     status;
-+      bdaddr_t bdaddr;
-+} __attribute__ ((packed)) status_bdaddr_rp;
-+#define STATUS_BDADDR_RP_SIZE 7
--/* --------- HCI Events --------- */
-+#define OCF_INQUIRY_CANCEL    0x0002
-+
-+#define OCF_LINK_KEY_REPLY    0x000B
-+#define OCF_LINK_KEY_NEG_REPLY        0x000C
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8     link_key[16];
-+} __attribute__ ((packed)) link_key_reply_cp;
-+#define LINK_KEY_REPLY_CP_SIZE 22
-+
-+#define OCF_PIN_CODE_REPLY    0x000D
-+#define OCF_PIN_CODE_NEG_REPLY        0x000E
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8     pin_len;
-+      __u8     pin_code[16];
-+} __attribute__ ((packed)) pin_code_reply_cp;
-+#define PIN_CODE_REPLY_CP_SIZE 23
-+
-+#define OCF_CHANGE_CONN_PTYPE 0x000F
-+typedef struct {
-+      __u16    handle;
-+      __u16    pkt_type;
-+} __attribute__ ((packed)) change_conn_ptype_cp;
-+#define CHANGE_CONN_PTYPE_CP_SIZE 4
-+
-+#define OCF_AUTH_REQUESTED    0x0011
-+typedef struct {
-+      __u16    handle;
-+} __attribute__ ((packed)) auth_requested_cp;
-+#define AUTH_REQUESTED_CP_SIZE 2
-+
-+#define OCF_SET_CONN_ENCRYPT  0x0013
-+typedef struct {
-+      __u16    handle;
-+      __u8     encrypt;
-+} __attribute__ ((packed)) set_conn_encrypt_cp;
-+#define SET_CONN_ENCRYPT_CP_SIZE 3
-+
-+#define OCF_REMOTE_NAME_REQ   0x0019
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8     pscan_rep_mode;
-+      __u8     pscan_mode;
-+      __u16    clock_offset;
-+} __attribute__ ((packed)) remote_name_req_cp;
-+#define REMOTE_NAME_REQ_CP_SIZE 10
-+
-+#define OCF_READ_REMOTE_FEATURES 0x001B
-+typedef struct {
-+      __u16   handle;
-+} __attribute__ ((packed)) read_remote_features_cp;
-+#define READ_REMOTE_FEATURES_CP_SIZE 2
-+
-+#define OCF_READ_REMOTE_VERSION 0x001D
-+typedef struct {
-+      __u16   handle;
-+} __attribute__ ((packed)) read_remote_version_cp;
-+#define READ_REMOTE_VERSION_CP_SIZE 2
-+
-+/* Link Policy */
-+#define OGF_LINK_POLICY        0x02   
-+#define OCF_ROLE_DISCOVERY    0x0009
-+typedef struct {
-+      __u16   handle;
-+} __attribute__ ((packed)) role_discovery_cp;
-+#define ROLE_DISCOVERY_CP_SIZE 2
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      __u8    role;
-+} __attribute__ ((packed)) role_discovery_rp;
-+#define ROLE_DISCOVERY_RP_SIZE 4
-+
-+#define OCF_READ_LINK_POLICY  0x000C
-+typedef struct {
-+      __u16   handle;
-+} __attribute__ ((packed)) read_link_policy_cp;
-+#define READ_LINK_POLICY_CP_SIZE 2
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      __u16   policy;
-+} __attribute__ ((packed)) read_link_policy_rp;
-+#define READ_LINK_POLICY_RP_SIZE 5
-+
-+#define OCF_SWITCH_ROLE       0x000B
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8     role;
-+} __attribute__ ((packed)) switch_role_cp;
-+#define SWITCH_ROLE_CP_SIZE 7
-+
-+#define OCF_WRITE_LINK_POLICY 0x000D
-+typedef struct {
-+      __u16   handle;
-+      __u16   policy;
-+} __attribute__ ((packed)) write_link_policy_cp;
-+#define WRITE_LINK_POLICY_CP_SIZE 4
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+} __attribute__ ((packed)) write_link_policy_rp;
-+#define WRITE_LINK_POLICY_RP_SIZE 3
-+
-+/* Status params */
-+#define OGF_STATUS_PARAM      0x05
-+
-+/* Testing commands */
-+#define OGF_TESTING_CMD       0x3e
-+
-+/* Vendor specific commands */
-+#define OGF_VENDOR_CMD        0x3f
-+
-+/* ---- HCI Events ---- */
- #define EVT_INQUIRY_COMPLETE  0x01
- #define EVT_INQUIRY_RESULT    0x02
-@@ -272,11 +457,22 @@
-       __u8    pscan_rep_mode;
-       __u8    pscan_period_mode;
-       __u8    pscan_mode;
--      __u8    class[3];
-+      __u8    dev_class[3];
-       __u16   clock_offset;
- } __attribute__ ((packed)) inquiry_info;
- #define INQUIRY_INFO_SIZE 14
-+#define EVT_INQUIRY_RESULT_WITH_RSSI  0x22
-+typedef struct {
-+      bdaddr_t        bdaddr;
-+      __u8    pscan_rep_mode;
-+      __u8    pscan_period_mode;
-+      __u8    dev_class[3];
-+      __u16   clock_offset;
-+      __u8    rssi;
-+} __attribute__ ((packed)) inquiry_info_with_rssi;
-+#define INQUIRY_INFO_WITH_RSSI_SIZE 14
-+
- #define EVT_CONN_COMPLETE     0x03
- typedef struct {
-       __u8    status;
-@@ -303,6 +499,44 @@
- } __attribute__ ((packed)) evt_disconn_complete;
- #define EVT_DISCONN_COMPLETE_SIZE 4
-+#define EVT_AUTH_COMPLETE     0x06
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+} __attribute__ ((packed)) evt_auth_complete;
-+#define EVT_AUTH_COMPLETE_SIZE 3
-+
-+#define EVT_REMOTE_NAME_REQ_COMPLETE  0x07
-+typedef struct {
-+      __u8     status;
-+      bdaddr_t bdaddr;
-+      __u8     name[248];
-+} __attribute__ ((packed)) evt_remote_name_req_complete;
-+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
-+
-+#define EVT_ENCRYPT_CHANGE    0x08
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      __u8    encrypt;
-+} __attribute__ ((packed)) evt_encrypt_change;
-+#define EVT_ENCRYPT_CHANGE_SIZE 5
-+
-+#define EVT_QOS_SETUP_COMPLETE 0x0D
-+typedef struct {
-+      __u8    service_type;
-+      __u32   token_rate;
-+      __u32   peak_bandwidth;
-+      __u32   latency;
-+      __u32   delay_variation;
-+} __attribute__ ((packed)) hci_qos;
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      hci_qos qos;
-+} __attribute__ ((packed)) evt_qos_setup_complete;
-+#define EVT_QOS_SETUP_COMPLETE_SIZE 20
-+
- #define EVT_CMD_COMPLETE      0x0e
- typedef struct {
-       __u8    ncmd;
-@@ -321,16 +555,78 @@
- #define EVT_NUM_COMP_PKTS     0x13
- typedef struct {
-       __u8    num_hndl;
--      /* variable lenght part */
-+      /* variable length part */
- } __attribute__ ((packed)) evt_num_comp_pkts;
- #define EVT_NUM_COMP_PKTS_SIZE 1
--#define EVT_HCI_DEV_EVENT     0xfd
-+#define EVT_ROLE_CHANGE               0x12
-+typedef struct {
-+      __u8     status;
-+      bdaddr_t bdaddr;
-+      __u8     role;
-+} __attribute__ ((packed)) evt_role_change;
-+#define EVT_ROLE_CHANGE_SIZE 8
-+
-+#define EVT_PIN_CODE_REQ        0x16
-+typedef struct {
-+      bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_pin_code_req;
-+#define EVT_PIN_CODE_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_REQ        0x17
-+typedef struct {
-+      bdaddr_t bdaddr;
-+} __attribute__ ((packed)) evt_link_key_req;
-+#define EVT_LINK_KEY_REQ_SIZE 6
-+
-+#define EVT_LINK_KEY_NOTIFY   0x18
-+typedef struct {
-+      bdaddr_t bdaddr;
-+      __u8     link_key[16];
-+      __u8     key_type;
-+} __attribute__ ((packed)) evt_link_key_notify;
-+#define EVT_LINK_KEY_NOTIFY_SIZE 23
-+
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      __u8    features[8];
-+} __attribute__ ((packed)) evt_read_remote_features_complete;
-+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
-+
-+#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
-+typedef struct {
-+      __u8    status;
-+      __u16   handle;
-+      __u8    lmp_ver;
-+      __u16   manufacturer;
-+      __u16   lmp_subver;
-+} __attribute__ ((packed)) evt_read_remote_version_complete;
-+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
-+
-+/* Internal events generated by BlueZ stack */
-+#define EVT_STACK_INTERNAL    0xfd
-+typedef struct {
-+      __u16   type;
-+      __u8    data[0];
-+} __attribute__ ((packed)) evt_stack_internal;
-+#define EVT_STACK_INTERNAL_SIZE 2
-+
-+#define EVT_SI_DEVICE         0x01
-+typedef struct {
-+      __u16   event;
-+      __u16   dev_id;
-+} __attribute__ ((packed)) evt_si_device;
-+#define EVT_SI_DEVICE_SIZE 4
-+
-+#define EVT_SI_SECURITY       0x02
- typedef struct {
-       __u16   event;
--      __u16   param;
--} __attribute__ ((packed)) evt_hci_dev_event;
--#define EVT_HCI_DEV_EVENT_SIZE 4
-+      __u16   proto;
-+      __u16   subproto;
-+      __u8    incomming;
-+} __attribute__ ((packed)) evt_si_security;
- /* --------  HCI Packet structures  -------- */
- #define HCI_TYPE_LEN  1
-@@ -369,14 +665,14 @@
- #define acl_handle(h)         (h & 0x0fff)
- #define acl_flags(h)          (h >> 12)
--#endif /* _NO_HCI_DEFS */
--
- /* HCI Socket options */
--#define HCI_DATA_DIR  0x0001
--#define HCI_FILTER    0x0002
-+#define HCI_DATA_DIR  1
-+#define HCI_FILTER    2
-+#define HCI_TIME_STAMP        3
- /* HCI CMSG flags */
- #define HCI_CMSG_DIR  0x0001
-+#define HCI_CMSG_TSTAMP       0x0002
- struct sockaddr_hci {
-       sa_family_t    hci_family;
-@@ -387,27 +683,29 @@
- struct hci_filter {
-       __u32 type_mask;
-       __u32 event_mask[2];
-+      __u16 opcode;
- };
--struct hci_dev_req {
--      __u16 dev_id;
--      __u32 dev_opt;
--};
--
--struct hci_dev_list_req {
--      __u16  dev_num;
--      struct hci_dev_req dev_req[0];  /* hci_dev_req structures */
--};
-+#define HCI_FLT_TYPE_BITS     31
-+#define HCI_FLT_EVENT_BITS    63
-+#define HCI_FLT_OGF_BITS      63
-+#define HCI_FLT_OCF_BITS      127
--struct hci_inquiry_req {
--      __u16 dev_id;
--      __u16 flags;
--      __u8  lap[3];
--      __u8  length;
--      __u8  num_rsp;
--};
--#define IREQ_CACHE_FLUSH 0x0001
-+#if BITS_PER_LONG == 64
-+static inline void hci_set_bit(int nr, void *addr)
-+{
-+      *((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
-+}
-+static inline int hci_test_bit(int nr, void *addr)
-+{
-+      return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
-+}
-+#else
-+#define hci_set_bit   set_bit
-+#define hci_test_bit  test_bit
-+#endif
-+/* Ioctl requests structures */
- struct hci_dev_stats {
-       __u32 err_rx;
-       __u32 err_tx;
-@@ -433,11 +731,13 @@
-       __u8  features[8];
-       __u32 pkt_type;
-+      __u32 link_policy;
-+      __u32 link_mode;
-       __u16 acl_mtu;
--      __u16 acl_max;
-+      __u16 acl_pkts;
-       __u16 sco_mtu;
--      __u16 sco_max;
-+      __u16 sco_pkts;
-       struct hci_dev_stats stat;
- };
-@@ -445,6 +745,20 @@
- struct hci_conn_info {
-       __u16    handle;
-       bdaddr_t bdaddr;
-+      __u8     type;
-+      __u8     out;
-+      __u16    state;
-+      __u32    link_mode;
-+};
-+
-+struct hci_dev_req {
-+      __u16 dev_id;
-+      __u32 dev_opt;
-+};
-+
-+struct hci_dev_list_req {
-+      __u16  dev_num;
-+      struct hci_dev_req dev_req[0];  /* hci_dev_req structures */
- };
- struct hci_conn_list_req {
-@@ -453,4 +767,26 @@
-       struct hci_conn_info conn_info[0];
- };
-+struct hci_conn_info_req {
-+      bdaddr_t bdaddr;
-+      __u8     type;
-+      struct   hci_conn_info conn_info[0];
-+};
-+
-+struct hci_inquiry_req {
-+      __u16 dev_id;
-+      __u16 flags;
-+      __u8  lap[3];
-+      __u8  length;
-+      __u8  num_rsp;
-+};
-+#define IREQ_CACHE_FLUSH 0x0001
-+
-+struct hci_remotename_req {
-+      __u16 dev_id;
-+      __u16 flags;
-+      bdaddr_t bdaddr;
-+      __u8  name[248];
-+};
-+
- #endif /* __HCI_H */
---- linux/include/net/bluetooth/hci_uart.h~bluetooth-2.4.18-mh11
-+++ linux/include/net/bluetooth/hci_uart.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: hci_uart.h,v 1.2 2001/06/02 01:40:08 maxk Exp $
-- */
--
--#ifndef N_HCI
--#define N_HCI 15
--#endif
--
--#ifdef __KERNEL__
--
--#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_count;
--      struct sk_buff *rx_skb;
--};
--
--/* Transmit states  */
--#define TRANS_SENDING         1
--#define TRANS_WAKEUP          2
--
--/* Receiver States */
--#define WAIT_PACKET_TYPE      0
--#define WAIT_EVENT_HDR                1
--#define WAIT_ACL_HDR          2
--#define WAIT_SCO_HDR          3
--#define WAIT_DATA             4
--
--#endif /* __KERNEL__ */
---- linux/include/net/bluetooth/hci_usb.h~bluetooth-2.4.18-mh11
-+++ linux/include/net/bluetooth/hci_usb.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: hci_usb.h,v 1.3 2001/06/02 01:40:08 maxk Exp $
-- */
--
--#ifdef __KERNEL__
--
--/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
--#define HCI_DEV_CLASS        0xe0     /* Wireless class */
--#define HCI_DEV_SUBCLASS     0x01     /* RF subclass */
--#define HCI_DEV_PROTOCOL     0x01     /* Bluetooth programming protocol */
--
--#define HCI_CTRL_REQ       0x20
--
--struct hci_usb {
--      struct usb_device       *udev;
--
--      devrequest              dev_req;
--      struct urb              *ctrl_urb;
--      struct urb              *intr_urb;
--      struct urb              *read_urb;
--      struct urb              *write_urb;
--
--      __u8                    *read_buf;
--      __u8                    *intr_buf;
--      struct sk_buff          *intr_skb;
--      int                     intr_count;
--
--      __u8                    bulk_out_ep_addr;
--      __u8                    bulk_in_ep_addr;
--      __u8                    intr_in_ep_addr;
--      __u8                    intr_in_interval;
--
--      struct hci_dev          hdev;
--
--      unsigned long           tx_state;
--      struct sk_buff_head     tx_ctrl_q;
--      struct sk_buff_head     tx_write_q;
--};
--
--/* Transmit states  */
--#define HCI_TX_CTRL   1
--#define HCI_TX_WRITE  2
--
--#endif /* __KERNEL__ */
---- linux/include/net/bluetooth/hci_vhci.h~bluetooth-2.4.18-mh11
-+++ linux/include/net/bluetooth/hci_vhci.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: hci_vhci.h,v 1.2 2001/08/01 01:02:20 maxk Exp $
-- */
--
--#ifndef __HCI_VHCI_H
--#define __HCI_VHCI_H
--
--#ifdef __KERNEL__
--
--struct hci_vhci_struct {
--      struct hci_dev       hdev;
--      __u32                flags;
--      wait_queue_head_t    read_wait;
--      struct sk_buff_head  readq;
--      struct fasync_struct *fasync;
--};
--
--/* VHCI device flags */
--#define VHCI_FASYNC           0x0010
--
--#endif /* __KERNEL__ */
--
--#define VHCI_DEV      "/dev/vhci"
--#define VHCI_MINOR    250
--
--#endif /* __HCI_VHCI_H */
---- linux/include/net/bluetooth/l2cap_core.h~bluetooth-2.4.18-mh11
-+++ linux/include/net/bluetooth/l2cap_core.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: l2cap_core.h,v 1.6 2001/08/03 04:19:49 maxk Exp $
-- */
--
--#ifndef __L2CAP_CORE_H
--#define __L2CAP_CORE_H
--
--#ifdef __KERNEL__
--
--/* ----- L2CAP interface ----- */
--struct l2cap_iff {
--      struct list_head list;
--      struct hci_dev   *hdev;
--      bdaddr_t         *bdaddr;
--      __u16            mtu;
--      spinlock_t       lock;
--      struct list_head conn_list;
--};
--
--static inline void l2cap_iff_lock(struct l2cap_iff *iff)
--{
--      spin_lock(&iff->lock);
--}
--
--static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
--{
--      spin_unlock(&iff->lock);
--}
--
--/* ----- L2CAP connections ----- */
--struct l2cap_chan_list {
--      struct sock     *head;
--      rwlock_t        lock;
--      long            num;
--};
--
--struct l2cap_conn {
--      struct l2cap_iff *iff;
--      struct list_head list;
--
--      struct hci_conn  *hconn;
--
--      __u16           state;
--      __u8            out;
--      bdaddr_t        src;
--      bdaddr_t        dst;
--
--      spinlock_t      lock;
--      atomic_t        refcnt;
--
--      struct sk_buff *rx_skb;
--      __u32           rx_len;
--      __u8            rx_ident;
--      __u8            tx_ident;
--
--      struct l2cap_chan_list chan_list;
--
--      struct timer_list timer;
--};
--
--static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
--      list_add(&c->list, &iff->conn_list);
--}
--
--static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
--{
--      list_del(&c->list);
--}
--
--/* ----- L2CAP channel and socket info ----- */
--#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->protinfo)
--
--struct l2cap_accept_q {
--      struct sock     *head;
--      struct sock     *tail;
--};
--
--struct l2cap_pinfo {
--      bdaddr_t        src;
--      bdaddr_t        dst;
--      __u16           psm;
--      __u16           dcid;
--      __u16           scid;
--      __u32           flags;
--
--      __u16           imtu;
--      __u16           omtu;
--      __u16           flush_to;
--
--      __u8            conf_state;
--      __u16           conf_mtu;
--
--      __u8            ident;
--
--      struct l2cap_conn       *conn;
--      struct sock             *next_c;
--      struct sock             *prev_c;
--
--      struct sock *parent;
--      struct sock *next_q;
--      struct sock *prev_q;
--
--      struct l2cap_accept_q accept_q;
--};
--
--#define CONF_REQ_SENT    0x01
--#define CONF_INPUT_DONE  0x02
--#define CONF_OUTPUT_DONE 0x04
--
--extern struct bluez_sock_list l2cap_sk_list;
--extern struct list_head  l2cap_iff_list;
--extern rwlock_t l2cap_rt_lock;
--
--extern void l2cap_register_proc(void);
--extern void l2cap_unregister_proc(void);
--
--#endif /* __KERNEL__ */
--
--#endif /* __L2CAP_CORE_H */
---- linux/include/net/bluetooth/l2cap.h~bluetooth-2.4.18-mh11  2001-09-07 18:28:38.000000000 +0200
-+++ linux/include/net/bluetooth/l2cap.h        2004-01-25 23:37:39.000000000 +0100
-@@ -23,22 +23,17 @@
- */
- /*
-- *  $Id: l2cap.h,v 1.5 2001/06/14 21:28:26 maxk Exp $
-+ *  $Id: l2cap.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
-  */
- #ifndef __L2CAP_H
- #define __L2CAP_H
--#include <asm/types.h>
--#include <asm/byteorder.h>
--
- /* L2CAP defaults */
- #define L2CAP_DEFAULT_MTU     672
- #define L2CAP_DEFAULT_FLUSH_TO        0xFFFF
- #define L2CAP_CONN_TIMEOUT    (HZ * 40)
--#define L2CAP_DISCONN_TIMEOUT         (HZ * 2)
--#define L2CAP_CONN_IDLE_TIMEOUT       (HZ * 60)
- /* L2CAP socket address */
- struct sockaddr_l2 {
-@@ -47,17 +42,12 @@
-       bdaddr_t        l2_bdaddr;
- };
--/* set/get sockopt defines */
--#define L2CAP_OPTIONS  0x01
-+/* Socket options */
-+#define L2CAP_OPTIONS 0x01
- struct l2cap_options {
-       __u16 omtu;
-       __u16 imtu;
-       __u16 flush_to;
--      __u32 token_rate;
--      __u32 bucket_size;
--      __u32 pick_band;
--      __u32 latency;
--      __u32 delay_var;
- };
- #define L2CAP_CONNINFO  0x02
-@@ -65,6 +55,27 @@
-       __u16 hci_handle;
- };
-+#define L2CAP_LM      0x03
-+#define L2CAP_LM_MASTER               0x0001
-+#define L2CAP_LM_AUTH         0x0002
-+#define L2CAP_LM_ENCRYPT      0x0004
-+#define L2CAP_LM_TRUSTED      0x0008
-+#define L2CAP_LM_RELIABLE     0x0010
-+
-+#define L2CAP_QOS     0x04
-+struct l2cap_qos {
-+      __u16 service_type;
-+      __u32 token_rate;
-+      __u32 token_bucket_size;
-+      __u32 peak_bandwidth;
-+      __u32 latency;
-+      __u32 delay_variation;
-+};
-+
-+#define L2CAP_SERV_NO_TRAFFIC 0x00
-+#define L2CAP_SERV_BEST_EFFORT        0x01
-+#define L2CAP_SERV_GUARANTEED 0x02
-+
- /* L2CAP command codes */
- #define L2CAP_COMMAND_REJ 0x01
- #define L2CAP_CONN_REQ    0x02
-@@ -79,7 +90,6 @@
- #define L2CAP_INFO_RSP    0x0b
- /* L2CAP structures */
--
- typedef struct {
-       __u16      len;
-       __u16      cid;
-@@ -112,11 +122,17 @@
- } __attribute__ ((packed))    l2cap_conn_rsp;
- #define L2CAP_CONN_RSP_SIZE   8
--#define L2CAP_CONN_SUCCESS    0x0000
--#define L2CAP_CONN_PEND       0x0001
--#define L2CAP_CONN_BAD_PSM    0x0002
--#define L2CAP_CONN_SEC_BLOCK  0x0003
--#define L2CAP_CONN_NO_MEM     0x0004
-+/* connect result */
-+#define L2CAP_CR_SUCCESS    0x0000
-+#define L2CAP_CR_PEND       0x0001
-+#define L2CAP_CR_BAD_PSM    0x0002
-+#define L2CAP_CR_SEC_BLOCK  0x0003
-+#define L2CAP_CR_NO_MEM     0x0004
-+
-+/* connect status */
-+#define L2CAP_CS_NO_INFO      0x0000
-+#define L2CAP_CS_AUTHEN_PEND  0x0001
-+#define L2CAP_CS_AUTHOR_PEND  0x0002
- typedef struct {
-       __u16      dcid;
-@@ -147,6 +163,8 @@
- #define L2CAP_CONF_FLUSH_TO   0x02
- #define L2CAP_CONF_QOS                0x03
-+#define L2CAP_CONF_MAX_SIZE   22
-+
- typedef struct {
-       __u16      dcid;
-       __u16      scid;
-@@ -159,4 +177,74 @@
- } __attribute__ ((packed))    l2cap_disconn_rsp;
- #define L2CAP_DISCONN_RSP_SIZE        4
-+typedef struct {
-+      __u16       type;
-+      __u8        data[0];
-+} __attribute__ ((packed))    l2cap_info_req;
-+#define L2CAP_INFO_REQ_SIZE   2
-+
-+typedef struct {
-+      __u16       type;
-+      __u16       result;
-+      __u8        data[0];
-+} __attribute__ ((packed))    l2cap_info_rsp;
-+#define L2CAP_INFO_RSP_SIZE   4
-+
-+/* ----- L2CAP connections ----- */
-+struct l2cap_chan_list {
-+      struct sock     *head;
-+      rwlock_t        lock;
-+      long            num;
-+};
-+
-+struct l2cap_conn {
-+      struct hci_conn *hcon;
-+
-+      bdaddr_t        *dst;
-+      bdaddr_t        *src;
-+      
-+      unsigned int    mtu;
-+
-+      spinlock_t      lock;
-+      
-+      struct sk_buff *rx_skb;
-+      __u32           rx_len;
-+      __u8            rx_ident;
-+      __u8            tx_ident;
-+
-+      struct l2cap_chan_list chan_list;
-+};
-+
-+/* ----- L2CAP channel and socket info ----- */
-+#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->tp_pinfo)
-+
-+struct l2cap_pinfo {
-+      __u16           psm;
-+      __u16           dcid;
-+      __u16           scid;
-+
-+      __u16           imtu;
-+      __u16           omtu;
-+      __u16           flush_to;
-+      
-+      __u32           link_mode;
-+
-+      __u8            conf_state;
-+      __u8            conf_retry;
-+      __u16           conf_mtu;
-+
-+      __u8            ident;
-+
-+      struct l2cap_conn       *conn;
-+      struct sock             *next_c;
-+      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
-+
-+void l2cap_load(void);
-+
- #endif /* __L2CAP_H */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/net/bluetooth/rfcomm.h       2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,361 @@
-+/* 
-+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2002 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.
-+*/
-+
-+/* 
-+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * $Id: rfcomm.h,v 1.31 2002/10/18 20:12:11 maxk Exp $
-+ */
-+
-+#ifndef __RFCOMM_H
-+#define __RFCOMM_H
-+
-+#define RFCOMM_PSM 3
-+
-+#define RFCOMM_CONN_TIMEOUT (HZ * 30)
-+#define RFCOMM_DISC_TIMEOUT (HZ * 20)
-+
-+#define RFCOMM_DEFAULT_MTU    127
-+#define RFCOMM_DEFAULT_CREDITS        7
-+
-+#define RFCOMM_MAX_L2CAP_MTU  1024
-+#define RFCOMM_MAX_CREDITS    40
-+
-+#define RFCOMM_SKB_HEAD_RESERVE       8
-+#define RFCOMM_SKB_TAIL_RESERVE       2
-+#define RFCOMM_SKB_RESERVE    (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
-+
-+#define RFCOMM_SABM   0x2f
-+#define RFCOMM_DISC   0x43
-+#define RFCOMM_UA     0x63
-+#define RFCOMM_DM     0x0f
-+#define RFCOMM_UIH    0xef
-+
-+#define RFCOMM_TEST   0x08
-+#define RFCOMM_FCON   0x28
-+#define RFCOMM_FCOFF  0x18
-+#define RFCOMM_MSC    0x38
-+#define RFCOMM_RPN    0x24
-+#define RFCOMM_RLS    0x14
-+#define RFCOMM_PN     0x20
-+#define RFCOMM_NSC    0x04
-+
-+#define RFCOMM_V24_FC 0x02
-+#define RFCOMM_V24_RTC        0x04
-+#define RFCOMM_V24_RTR        0x08
-+#define RFCOMM_V24_IC 0x40
-+#define RFCOMM_V24_DV 0x80
-+
-+#define RFCOMM_RPN_BR_2400    0x0
-+#define RFCOMM_RPN_BR_4800    0x1
-+#define RFCOMM_RPN_BR_7200    0x2
-+#define RFCOMM_RPN_BR_9600    0x3
-+#define RFCOMM_RPN_BR_19200   0x4
-+#define RFCOMM_RPN_BR_38400   0x5
-+#define RFCOMM_RPN_BR_57600   0x6
-+#define RFCOMM_RPN_BR_115200  0x7
-+#define RFCOMM_RPN_BR_230400  0x8
-+
-+#define RFCOMM_RPN_DATA_5     0x0
-+#define RFCOMM_RPN_DATA_6     0x1
-+#define RFCOMM_RPN_DATA_7     0x2
-+#define RFCOMM_RPN_DATA_8     0x3
-+
-+#define RFCOMM_RPN_STOP_1     0
-+#define RFCOMM_RPN_STOP_15    1
-+
-+#define RFCOMM_RPN_PARITY_NONE        0x0
-+#define RFCOMM_RPN_PARITY_ODD 0x4
-+#define RFCOMM_RPN_PARITY_EVEN        0x5
-+#define RFCOMM_RPN_PARITY_MARK        0x6
-+#define RFCOMM_RPN_PARITY_SPACE       0x7
-+
-+#define RFCOMM_RPN_FLOW_NONE  0x00
-+
-+#define RFCOMM_RPN_XON_CHAR   0x11
-+#define RFCOMM_RPN_XOFF_CHAR  0x13
-+
-+#define RFCOMM_RPN_PM_BITRATE         0x0001
-+#define RFCOMM_RPN_PM_DATA            0x0002
-+#define RFCOMM_RPN_PM_STOP            0x0004
-+#define RFCOMM_RPN_PM_PARITY          0x0008
-+#define RFCOMM_RPN_PM_PARITY_TYPE     0x0010
-+#define RFCOMM_RPN_PM_XON             0x0020
-+#define RFCOMM_RPN_PM_XOFF            0x0040
-+#define RFCOMM_RPN_PM_FLOW            0x3F00
-+
-+#define RFCOMM_RPN_PM_ALL             0x3F7F
-+
-+struct rfcomm_hdr {
-+      u8 addr;
-+      u8 ctrl;
-+      u8 len;    // Actual size can be 2 bytes
-+} __attribute__ ((packed));
-+
-+struct rfcomm_cmd {
-+      u8 addr;
-+      u8 ctrl;
-+      u8 len;
-+      u8 fcs;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_mcc {
-+      u8 type;
-+      u8 len;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_pn {
-+      u8  dlci;
-+      u8  flow_ctrl;
-+      u8  priority;
-+      u8  ack_timer;
-+      u16 mtu;
-+      u8  max_retrans;
-+      u8  credits;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rpn {
-+      u8  dlci;
-+      u8  bit_rate;
-+      u8  line_settings;
-+      u8  flow_ctrl;
-+      u8  xon_char;
-+      u8  xoff_char;
-+      u16 param_mask;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_rls {
-+      u8  dlci;
-+      u8  status;
-+} __attribute__ ((packed));
-+
-+struct rfcomm_msc {
-+      u8  dlci;
-+      u8  v24_sig;
-+} __attribute__ ((packed));
-+
-+/* ---- Core structures, flags etc ---- */
-+
-+struct rfcomm_session {
-+      struct list_head list;
-+      struct socket   *sock;
-+      unsigned long    state;
-+      unsigned long    flags;
-+      atomic_t         refcnt;
-+      int              initiator;
-+
-+      /* Default DLC parameters */
-+      int    cfc;
-+      uint   mtu;
-+
-+      struct list_head dlcs;
-+};
-+
-+struct rfcomm_dlc {
-+      struct list_head      list;
-+      struct rfcomm_session *session;
-+      struct sk_buff_head   tx_queue;
-+      struct timer_list     timer;
-+
-+      spinlock_t    lock;
-+      unsigned long state;
-+      unsigned long flags;
-+      atomic_t      refcnt;
-+      u8            dlci;
-+      u8            addr;
-+      u8            priority;
-+      u8            v24_sig;
-+      u8            mscex;
-+
-+      uint          mtu;
-+      uint          cfc;
-+      uint          rx_credits;
-+      uint          tx_credits;
-+
-+      void          *owner;
-+
-+      void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
-+      void (*state_change)(struct rfcomm_dlc *d, int err);
-+      void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
-+};
-+
-+/* DLC and session flags */
-+#define RFCOMM_RX_THROTTLED 0
-+#define RFCOMM_TX_THROTTLED 1
-+#define RFCOMM_MSC_PENDING  2
-+#define RFCOMM_TIMED_OUT    3
-+
-+/* Scheduling flags and events */
-+#define RFCOMM_SCHED_STATE  0
-+#define RFCOMM_SCHED_RX     1
-+#define RFCOMM_SCHED_TX     2
-+#define RFCOMM_SCHED_TIMEO  3
-+#define RFCOMM_SCHED_WAKEUP 31
-+
-+/* MSC exchange flags */
-+#define RFCOMM_MSCEX_TX     1
-+#define RFCOMM_MSCEX_RX     2
-+#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 unsigned long rfcomm_event;
-+
-+static inline void rfcomm_schedule(uint event)
-+{
-+      if (!rfcomm_thread)
-+              return;
-+      set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+      wake_up_process(rfcomm_thread);
-+}
-+
-+extern struct semaphore rfcomm_sem;
-+#define rfcomm_lock() down(&rfcomm_sem);
-+#define rfcomm_unlock()       up(&rfcomm_sem);
-+
-+/* ---- RFCOMM DLCs (channels) ---- */
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
-+void rfcomm_dlc_free(struct rfcomm_dlc *d);
-+int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
-+int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
-+int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
-+int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
-+int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
-+
-+#define rfcomm_dlc_lock(d)    spin_lock(&d->lock)
-+#define rfcomm_dlc_unlock(d)  spin_unlock(&d->lock)
-+
-+static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
-+{
-+      atomic_inc(&d->refcnt);
-+}
-+
-+static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
-+{
-+      if (atomic_dec_and_test(&d->refcnt))
-+              rfcomm_dlc_free(d);
-+}
-+
-+extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
-+extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
-+
-+static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+      if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+              __rfcomm_dlc_throttle(d);
-+}
-+
-+static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+      if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+              __rfcomm_dlc_unthrottle(d);
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
-+void   rfcomm_session_del(struct rfcomm_session *s);
-+void   rfcomm_session_close(struct rfcomm_session *s, int err);
-+void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
-+
-+static inline void rfcomm_session_hold(struct rfcomm_session *s)
-+{
-+      atomic_inc(&s->refcnt);
-+}
-+
-+static inline void rfcomm_session_put(struct rfcomm_session *s)
-+{
-+      if (atomic_dec_and_test(&s->refcnt))
-+              rfcomm_session_del(s);
-+}
-+
-+/* ---- RFCOMM chechsum ---- */
-+extern u8 rfcomm_crc_table[];
-+
-+/* ---- RFCOMM sockets ---- */
-+struct sockaddr_rc {
-+      sa_family_t rc_family;
-+      bdaddr_t    rc_bdaddr;
-+      u8          rc_channel;
-+};
-+
-+#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo)
-+
-+struct rfcomm_pinfo {
-+      struct rfcomm_dlc *dlc;
-+      u8 channel;
-+};
-+
-+int  rfcomm_init_sockets(void);
-+void rfcomm_cleanup_sockets(void);
-+
-+int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
-+
-+/* ---- RFCOMM TTY ---- */
-+#define RFCOMM_MAX_DEV  256
-+
-+#define RFCOMMCREATEDEV               _IOW('R', 200, int)
-+#define RFCOMMRELEASEDEV      _IOW('R', 201, int)
-+#define RFCOMMGETDEVLIST      _IOR('R', 210, int)
-+#define RFCOMMGETDEVINFO      _IOR('R', 211, int)
-+#define RFCOMMSTEALDLC                _IOW('R', 220, int)
-+
-+#define RFCOMM_REUSE_DLC      0
-+#define RFCOMM_RELEASE_ONHUP  1
-+#define RFCOMM_HANGUP_NOW     2
-+#define RFCOMM_TTY_ATTACHED   3
-+
-+struct rfcomm_dev_req {
-+      s16      dev_id;
-+      u32      flags;
-+      bdaddr_t src;
-+      bdaddr_t dst;
-+      u8       channel;
-+};
-+
-+struct rfcomm_dev_info {
-+      s16      id;
-+      u32      flags;
-+      u16      state;
-+      bdaddr_t src;
-+      bdaddr_t dst;
-+      u8       channel;
-+};
-+
-+struct rfcomm_dev_list_req {
-+      u16      dev_num;
-+      struct   rfcomm_dev_info dev_info[0];
-+};
-+
-+int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
-+int  rfcomm_init_ttys(void);
-+void rfcomm_cleanup_ttys(void);
-+
-+#endif /* __RFCOMM_H */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/include/net/bluetooth/sco.h  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,81 @@
-+/* 
-+   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: sco.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $
-+ */
-+
-+#ifndef __SCO_H
-+#define __SCO_H
-+
-+/* SCO defaults */
-+#define SCO_DEFAULT_MTU       500
-+#define SCO_DEFAULT_FLUSH_TO  0xFFFF
-+
-+#define SCO_CONN_TIMEOUT      (HZ * 40)
-+#define SCO_DISCONN_TIMEOUT   (HZ * 2)
-+#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
-+
-+/* SCO socket address */
-+struct sockaddr_sco {
-+      sa_family_t     sco_family;
-+      bdaddr_t        sco_bdaddr;
-+};
-+
-+/* set/get sockopt defines */
-+#define SCO_OPTIONS  0x01
-+struct sco_options {
-+      __u16 mtu;
-+};
-+
-+#define SCO_CONNINFO  0x02
-+struct sco_conninfo {
-+      __u16 hci_handle;
-+};
-+
-+/* ---- SCO connections ---- */
-+struct sco_conn {
-+      struct hci_conn *hcon;
-+
-+      bdaddr_t        *dst;
-+      bdaddr_t        *src;
-+      
-+      spinlock_t      lock;
-+      struct sock     *sk;
-+
-+      unsigned int    mtu;
-+};
-+
-+#define sco_conn_lock(c)      spin_lock(&c->lock);
-+#define sco_conn_unlock(c)    spin_unlock(&c->lock);
-+
-+/* ----- SCO socket info ----- */
-+#define sco_pi(sk)   ((struct sco_pinfo *) &sk->tp_pinfo)
-+
-+struct sco_pinfo {
-+      __u32           flags;
-+      struct sco_conn *conn;
-+};
-+
-+#endif /* __SCO_H */
---- linux/include/pcmcia/ciscode.h~bluetooth-2.4.18-mh11       2001-12-21 18:42:04.000000000 +0100
-+++ linux/include/pcmcia/ciscode.h     2004-01-25 23:37:39.000000000 +0100
-@@ -1,5 +1,5 @@
- /*
-- * ciscode.h 1.48 2001/08/24 12:16:12
-+ * ciscode.h 1.57 2002/11/03 20:38:14
-  *
-  * The contents of this file are subject to the Mozilla Public License
-  * Version 1.1 (the "License"); you may not use this file except in
-@@ -60,6 +60,10 @@
- #define PRODID_INTEL_DUAL_RS232               0x0301
- #define PRODID_INTEL_2PLUS            0x8422
-+#define MANFID_KME                    0x0032
-+#define PRODID_KME_KXLC005_A          0x0704
-+#define PRODID_KME_KXLC005_B          0x2904
-+
- #define MANFID_LINKSYS                        0x0143
- #define PRODID_LINKSYS_PCMLM28                0xc0ab
- #define PRODID_LINKSYS_3400           0x3341
-@@ -94,6 +98,8 @@
- #define PRODID_OSITECH_JACK_336               0x0007
- #define PRODID_OSITECH_SEVEN          0x0008
-+#define MANFID_OXSEMI                 0x0279
-+
- #define MANFID_PIONEER                        0x000b
- #define MANFID_PSION                  0x016c
-@@ -103,6 +109,7 @@
- #define PRODID_QUATECH_SPP100         0x0003
- #define PRODID_QUATECH_DUAL_RS232     0x0012
- #define PRODID_QUATECH_DUAL_RS232_D1  0x0007
-+#define PRODID_QUATECH_DUAL_RS232_D2  0x0052
- #define PRODID_QUATECH_QUAD_RS232     0x001b
- #define PRODID_QUATECH_DUAL_RS422     0x000e
- #define PRODID_QUATECH_QUAD_RS422     0x0045
-@@ -120,9 +127,12 @@
- #define MANFID_TDK                    0x0105
- #define PRODID_TDK_CF010              0x0900
-+#define PRODID_TDK_GN3410             0x4815
- #define MANFID_TOSHIBA                        0x0098
-+#define MANFID_UNGERMANN              0x02c0
-+
- #define MANFID_XIRCOM                 0x0105
- #endif /* _LINUX_CISCODE_H */
---- linux/kernel/ksyms.c~bluetooth-2.4.18-mh11 2004-01-25 23:28:30.000000000 +0100
-+++ linux/kernel/ksyms.c       2004-01-25 23:37:39.000000000 +0100
-@@ -47,6 +47,7 @@
- #include <linux/in6.h>
- #include <linux/completion.h>
- #include <linux/seq_file.h>
-+#include <linux/firmware.h>
- #include <asm/checksum.h>
- #if defined(CONFIG_PROC_FS)
-@@ -543,6 +544,13 @@
- EXPORT_SYMBOL(strspn);
- EXPORT_SYMBOL(strsep);
-+#ifdef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
-+
- /* software interrupts */
- EXPORT_SYMBOL(tasklet_hi_vec);
- EXPORT_SYMBOL(tasklet_vec);
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/lib/Config.in        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,12 @@
-+#
-+# Library configuration
-+#
-+mainmenu_option next_comment
-+comment 'Library routines'
-+
-+if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
-+     "$CONFIG_HOTPLUG" = "y" ]; then
-+   tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
-+fi
-+
-+endmenu
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/lib/firmware_class.c 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,573 @@
-+/*
-+ * firmware_class.c - Multi purpose firmware loading support
-+ *
-+ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
-+ *
-+ * Please see Documentation/firmware_class/ for more information.
-+ *
-+ */
-+/*
-+ * Based on kernel/kmod.c and drivers/usb/usb.c
-+ */
-+/*
-+        kernel/kmod.c
-+        Kirk Petersen
-+
-+        Reorganized not to be a daemon by Adam Richter, with guidance
-+        from Greg Zornetzer.
-+
-+        Modified to avoid chroot and file sharing problems.
-+        Mikael Pettersson
-+
-+        Limit the concurrent number of kmod modprobes to catch loops from
-+        "modprobe needs a service that is in a module".
-+        Keith Owens <kaos@ocs.com.au> December 1999
-+
-+        Unblock all signals when we exec a usermode process.
-+        Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
-+*/
-+/*
-+ * drivers/usb/usb.c
-+ *
-+ * (C) Copyright Linus Torvalds 1999
-+ * (C) Copyright Johannes Erdfelt 1999-2001
-+ * (C) Copyright Andreas Gal 1999
-+ * (C) Copyright Gregory P. Smith 1999
-+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
-+ * (C) Copyright Randy Dunlap 2000
-+ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
-+ * (C) Copyright Yggdrasil Computing, Inc. 2000
-+ *     (usb_device_id matching changes by Adam J. Richter)
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/kmod.h>
-+#include <linux/proc_fs.h>
-+#include <linux/vmalloc.h>
-+#include <asm/hardirq.h>
-+
-+#include "linux/firmware.h"
-+
-+MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-+MODULE_DESCRIPTION("Multi purpose firmware loading support");
-+MODULE_LICENSE("GPL");
-+
-+#define err(format, arg...) \
-+     printk(KERN_ERR  "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define warn(format, arg...) \
-+     printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+#define dbg(format, arg...) \
-+     printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
-+
-+static int loading_timeout = 10;      /* In seconds */
-+static struct proc_dir_entry *proc_dir_timeout;
-+static struct proc_dir_entry *proc_dir;
-+
-+#ifdef CONFIG_HOTPLUG
-+
-+static int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+      char *argv[3], **envp, *buf, *scratch;
-+      int i = 0;
-+
-+      int retval = 0;
-+
-+      if (!hotplug_path[0])
-+              return -ENOENT;
-+      if (in_interrupt()) {
-+              err("in_interrupt");
-+              return -EFAULT;
-+      }
-+      if (!current->fs->root) {
-+              warn("call_policy %s -- no FS yet", verb);
-+              return -EPERM;
-+      }
-+
-+      if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
-+              err("unable to allocate envp");
-+              return -ENOMEM;
-+      }
-+      if (!(buf = kmalloc(256, GFP_KERNEL))) {
-+              kfree(envp);
-+              err("unable to allocate buf");
-+              return -ENOMEM;
-+      }
-+
-+      /* only one standardized param to hotplug command: type */
-+      argv[0] = hotplug_path;
-+      argv[1] = "firmware";
-+      argv[2] = 0;
-+
-+      /* minimal command environment */
-+      envp[i++] = "HOME=/";
-+      envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+
-+#ifdef  DEBUG
-+      /* hint that policy agent should enter no-stdout debug mode */
-+      envp[i++] = "DEBUG=kernel";
-+#endif
-+      scratch = buf;
-+
-+      if (device) {
-+              envp[i++] = scratch;
-+              scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
-+                                  "DEVPATH=/driver/firmware/%s", device) + 1;
-+      }
-+
-+      envp[i++] = scratch;
-+      scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
-+
-+      envp[i++] = scratch;
-+      scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
-+                          "FIRMWARE=%s", name) + 1;
-+
-+      envp[i++] = 0;
-+
-+#ifdef  DEBUG
-+      dbg("firmware: %s %s %s", argv[0], argv[1], verb);
-+#endif
-+
-+      retval = call_usermodehelper(argv[0], argv, envp);
-+      if (retval) {
-+              printk("call_usermodehelper return %d\n", retval);
-+      }
-+
-+      kfree(buf);
-+      kfree(envp);
-+      return retval;
-+}
-+#else
-+
-+static inline int
-+call_helper(char *verb, const char *name, const char *device)
-+{
-+      return -ENOENT;
-+}
-+
-+#endif /* CONFIG_HOTPLUG */
-+
-+struct firmware_priv {
-+      struct completion completion;
-+      struct proc_dir_entry *proc_dir;
-+      struct proc_dir_entry *attr_data;
-+      struct proc_dir_entry *attr_loading;
-+      struct firmware *fw;
-+      int loading;
-+      int abort;
-+      int alloc_size;
-+      struct timer_list timeout;
-+};
-+
-+static int
-+firmware_timeout_show(char *buf, char **start, off_t off,
-+                    int count, int *eof, void *data)
-+{
-+      return sprintf(buf, "%d\n", loading_timeout);
-+}
-+
-+/**
-+ * firmware_timeout_store:
-+ * Description:
-+ *    Sets the number of seconds to wait for the firmware.  Once
-+ *    this expires an error will be return to the driver and no
-+ *    firmware will be provided.
-+ *
-+ *    Note: zero means 'wait for ever'
-+ *  
-+ **/
-+static int
-+firmware_timeout_store(struct file *file, const char *buf,
-+                     unsigned long count, void *data)
-+{
-+      loading_timeout = simple_strtol(buf, NULL, 10);
-+      return count;
-+}
-+
-+static int
-+firmware_loading_show(char *buf, char **start, off_t off,
-+                    int count, int *eof, void *data)
-+{
-+      struct firmware_priv *fw_priv = data;
-+      return sprintf(buf, "%d\n", fw_priv->loading);
-+}
-+
-+/**
-+ * firmware_loading_store: - loading control file
-+ * Description:
-+ *    The relevant values are: 
-+ *
-+ *     1: Start a load, discarding any previous partial load.
-+ *     0: Conclude the load and handle the data to the driver code.
-+ *    -1: Conclude the load with an error and discard any written data.
-+ **/
-+static int
-+firmware_loading_store(struct file *file, const char *buf,
-+                     unsigned long count, void *data)
-+{
-+      struct firmware_priv *fw_priv = data;
-+      int prev_loading = fw_priv->loading;
-+
-+      fw_priv->loading = simple_strtol(buf, NULL, 10);
-+
-+      switch (fw_priv->loading) {
-+      case -1:
-+              fw_priv->abort = 1;
-+              wmb();
-+              complete(&fw_priv->completion);
-+              break;
-+      case 1:
-+              kfree(fw_priv->fw->data);
-+              fw_priv->fw->data = NULL;
-+              fw_priv->fw->size = 0;
-+              fw_priv->alloc_size = 0;
-+              break;
-+      case 0:
-+              if (prev_loading == 1)
-+                      complete(&fw_priv->completion);
-+              break;
-+      }
-+
-+      return count;
-+}
-+
-+static int
-+firmware_data_read(char *buffer, char **start, off_t offset,
-+                 int count, int *eof, void *data)
-+{
-+      struct firmware_priv *fw_priv = data;
-+      struct firmware *fw = fw_priv->fw;
-+
-+      if (offset > fw->size)
-+              return 0;
-+      if (offset + count > fw->size)
-+              count = fw->size - offset;
-+
-+      memcpy(buffer, fw->data + offset, count);
-+      *start = (void *) ((long) count);
-+      return count;
-+}
-+static int
-+fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
-+{
-+      u8 *new_data;
-+      int new_size;
-+
-+      if (min_size <= fw_priv->alloc_size)
-+              return 0;
-+      if((min_size % PAGE_SIZE) == 0)
-+              new_size = min_size;
-+      else
-+              new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
-+      new_data = vmalloc(new_size);
-+      if (!new_data) {
-+              printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
-+              /* Make sure that we don't keep incomplete data */
-+              fw_priv->abort = 1;
-+              return -ENOMEM;
-+      }
-+      fw_priv->alloc_size = new_size;
-+      if (fw_priv->fw->data) {
-+              memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
-+              vfree(fw_priv->fw->data);
-+      }
-+      fw_priv->fw->data = new_data;
-+      BUG_ON(min_size > fw_priv->alloc_size);
-+      return 0;
-+}
-+
-+/**
-+ * firmware_data_write:
-+ *
-+ * Description:
-+ *
-+ *    Data written to the 'data' attribute will be later handled to
-+ *    the driver as a firmware image.
-+ **/
-+static int
-+firmware_data_write(struct file *file, const char *buffer,
-+                  unsigned long count, void *data)
-+{
-+      struct firmware_priv *fw_priv = data;
-+      struct firmware *fw = fw_priv->fw;
-+      int offset = file->f_pos;
-+      int retval;
-+
-+      retval = fw_realloc_buffer(fw_priv, offset + count);
-+      if (retval) {
-+              printk("%s: retval:%d\n", __FUNCTION__, retval);
-+              return retval;
-+      }
-+
-+      memcpy(fw->data + offset, buffer, count);
-+
-+      fw->size = max_t(size_t, offset + count, fw->size);
-+      file->f_pos += count;
-+      return count;
-+}
-+
-+static void
-+firmware_class_timeout(u_long data)
-+{
-+      struct firmware_priv *fw_priv = (struct firmware_priv *) data;
-+      fw_priv->abort = 1;
-+      wmb();
-+      complete(&fw_priv->completion);
-+}
-+static int
-+fw_setup_class_device(struct firmware_priv **fw_priv_p,
-+                    const char *fw_name, const char *device)
-+{
-+      int retval;
-+      struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
-+                                              GFP_KERNEL);
-+      *fw_priv_p = fw_priv;
-+      if (!fw_priv) {
-+              retval = -ENOMEM;
-+              goto out;
-+      }
-+      memset(fw_priv, 0, sizeof (*fw_priv));
-+
-+      init_completion(&fw_priv->completion);
-+
-+      fw_priv->timeout.function = firmware_class_timeout;
-+      fw_priv->timeout.data = (u_long) fw_priv;
-+      init_timer(&fw_priv->timeout);
-+
-+      retval = -EAGAIN;
-+      fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
-+      if (!fw_priv->proc_dir)
-+              goto err_free_fw_priv;
-+
-+      fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
-+                                             fw_priv->proc_dir);
-+      if (!fw_priv->attr_data)
-+              goto err_remove_dir;
-+
-+      fw_priv->attr_data->read_proc = firmware_data_read;
-+      fw_priv->attr_data->write_proc = firmware_data_write;
-+      fw_priv->attr_data->data = fw_priv;
-+
-+      fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
-+                                                fw_priv->proc_dir);
-+      if (!fw_priv->attr_loading)
-+              goto err_remove_data;
-+
-+      fw_priv->attr_loading->read_proc = firmware_loading_show;
-+      fw_priv->attr_loading->write_proc = firmware_loading_store;
-+      fw_priv->attr_loading->data = fw_priv;
-+
-+      retval = 0;
-+      fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
-+      if (!fw_priv->fw) {
-+              printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
-+                     __FUNCTION__);
-+              retval = -ENOMEM;
-+              goto err_remove_loading;
-+      }
-+      memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
-+
-+      goto out;
-+
-+err_remove_loading:
-+      remove_proc_entry("loading", fw_priv->proc_dir);
-+err_remove_data:
-+      remove_proc_entry("data", fw_priv->proc_dir);
-+err_remove_dir:
-+      remove_proc_entry(device, proc_dir);
-+err_free_fw_priv:
-+      kfree(fw_priv);
-+out:
-+      return retval;
-+}
-+static void
-+fw_remove_class_device(struct firmware_priv *fw_priv)
-+{
-+      remove_proc_entry("loading", fw_priv->proc_dir);
-+      remove_proc_entry("data", fw_priv->proc_dir);
-+      remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
-+}
-+
-+/** 
-+ * request_firmware: - request firmware to hotplug and wait for it
-+ * Description:
-+ *    @firmware will be used to return a firmware image by the name
-+ *    of @name for device @device.
-+ *
-+ *    Should be called from user context where sleeping is allowed.
-+ *
-+ *    @name will be use as $FIRMWARE in the hotplug environment and
-+ *    should be distinctive enough not to be confused with any other
-+ *    firmware image for this or any other device.
-+ **/
-+int
-+request_firmware(const struct firmware **firmware, const char *name,
-+               const char *device)
-+{
-+      struct firmware_priv *fw_priv;
-+      int retval;
-+
-+      if (!firmware) {
-+              retval = -EINVAL;
-+              goto out;
-+      }
-+      *firmware = NULL;
-+
-+      retval = fw_setup_class_device(&fw_priv, name, device);
-+      if (retval)
-+              goto out;
-+
-+      retval = call_helper("add", name, device);
-+      if (retval)
-+              goto out;
-+      if (loading_timeout) {
-+              fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
-+              add_timer(&fw_priv->timeout);
-+      }
-+
-+      wait_for_completion(&fw_priv->completion);
-+
-+      del_timer(&fw_priv->timeout);
-+      fw_remove_class_device(fw_priv);
-+
-+      if (fw_priv->fw->size && !fw_priv->abort) {
-+              *firmware = fw_priv->fw;
-+      } else {
-+              retval = -ENOENT;
-+              vfree(fw_priv->fw->data);
-+              kfree(fw_priv->fw);
-+      }
-+out:
-+      kfree(fw_priv);
-+      return retval;
-+}
-+
-+void
-+release_firmware(const struct firmware *fw)
-+{
-+      if (fw) {
-+              vfree(fw->data);
-+              kfree(fw);
-+      }
-+}
-+
-+/**
-+ * register_firmware: - provide a firmware image for later usage
-+ * 
-+ * Description:
-+ *    Make sure that @data will be available by requesting firmware @name.
-+ *
-+ *    Note: This will not be possible until some kind of persistence
-+ *    is available.
-+ **/
-+void
-+register_firmware(const char *name, const u8 *data, size_t size)
-+{
-+      /* This is meaningless without firmware caching, so until we
-+       * decide if firmware caching is reasonable just leave it as a
-+       * noop */
-+}
-+
-+/* Async support */
-+struct firmware_work {
-+      struct tq_struct work;
-+      struct module *module;
-+      const char *name;
-+      const char *device;
-+      void *context;
-+      void (*cont)(const struct firmware *fw, void *context);
-+};
-+
-+static void
-+request_firmware_work_func(void *arg)
-+{
-+      struct firmware_work *fw_work = arg;
-+      const struct firmware *fw;
-+      if (!arg)
-+              return;
-+      request_firmware(&fw, fw_work->name, fw_work->device);
-+      fw_work->cont(fw, fw_work->context);
-+      release_firmware(fw);
-+      __MOD_DEC_USE_COUNT(fw_work->module);
-+      kfree(fw_work);
-+}
-+
-+/**
-+ * request_firmware_nowait:
-+ *
-+ * Description:
-+ *    Asynchronous variant of request_firmware() for contexts where
-+ *    it is not possible to sleep.
-+ *
-+ *    @cont will be called asynchronously when the firmware request is over.
-+ *
-+ *    @context will be passed over to @cont.
-+ *
-+ *    @fw may be %NULL if firmware request fails.
-+ *
-+ **/
-+int
-+request_firmware_nowait(
-+      struct module *module,
-+      const char *name, const char *device, void *context,
-+      void (*cont)(const struct firmware *fw, void *context))
-+{
-+      struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
-+                                              GFP_ATOMIC);
-+      if (!fw_work)
-+              return -ENOMEM;
-+      if (!try_inc_mod_count(module)) {
-+              kfree(fw_work);
-+              return -EFAULT;
-+      }
-+
-+      *fw_work = (struct firmware_work) {
-+              .module = module,
-+              .name = name,
-+              .device = device,
-+              .context = context,
-+              .cont = cont,
-+      };
-+      INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
-+
-+      schedule_task(&fw_work->work);
-+      return 0;
-+}
-+
-+static int __init
-+firmware_class_init(void)
-+{
-+      proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
-+      if (!proc_dir)
-+              return -EAGAIN;
-+      proc_dir_timeout = create_proc_entry("timeout",
-+                                           0644 | S_IFREG, proc_dir);
-+      if (!proc_dir_timeout) {
-+              remove_proc_entry("driver/firmware", NULL);
-+              return -EAGAIN;
-+      }
-+      proc_dir_timeout->read_proc = firmware_timeout_show;
-+      proc_dir_timeout->write_proc = firmware_timeout_store;
-+      return 0;
-+}
-+static void __exit
-+firmware_class_exit(void)
-+{
-+      remove_proc_entry("timeout", proc_dir);
-+      remove_proc_entry("driver/firmware", NULL);
-+}
-+
-+module_init(firmware_class_init);
-+module_exit(firmware_class_exit);
-+
-+#ifndef CONFIG_FW_LOADER
-+EXPORT_SYMBOL(release_firmware);
-+EXPORT_SYMBOL(request_firmware);
-+EXPORT_SYMBOL(request_firmware_nowait);
-+EXPORT_SYMBOL(register_firmware);
-+#endif
---- linux/lib/Makefile~bluetooth-2.4.18-mh11   2001-09-18 00:31:15.000000000 +0200
-+++ linux/lib/Makefile 2004-01-25 23:37:39.000000000 +0100
-@@ -8,13 +8,17 @@
- L_TARGET := lib.a
--export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
-+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
-+             firmware_class.o
- obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
-+obj-$(CONFIG_FW_LOADER) += firmware_class.o
- obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
- obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
-+include $(TOPDIR)/drivers/bluetooth/Makefile.lib
-+
- ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
-   obj-y += dec_and_lock.o
- endif
---- linux/MAINTAINERS~bluetooth-2.4.18-mh11    2004-01-25 23:28:29.000000000 +0100
-+++ linux/MAINTAINERS  2004-01-25 23:37:39.000000000 +0100
-@@ -259,7 +259,84 @@
- L:    linux-kernel@vger.kernel.org
- S:    Maintained
--BLUETOOTH SUBSYSTEM (BlueZ)
-+BLUETOOTH SUBSYSTEM
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+P:    Maxim Krasnyansky
-+M:    maxk@qualcomm.com
-+L:    bluez-devel@lists.sf.net
-+W:    http://bluez.sf.net
-+S:    Maintained
-+
-+BLUETOOTH RFCOMM LAYER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+P:    Maxim Krasnyansky
-+M:    maxk@qualcomm.com
-+W:    http://bluez.sf.net
-+S:    Maintained
-+
-+BLUETOOTH BNEP LAYER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+P:    Maxim Krasnyansky
-+M:    maxk@qualcomm.com
-+W:    http://bluez.sf.net
-+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
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+P:    Maxim Krasnyansky
-+M:    maxk@qualcomm.com
-+W:    http://bluez.sf.net
-+S:    Maintained
-+
-+BLUETOOTH HCI UART DRIVER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+P:    Maxim Krasnyansky
-+M:    maxk@qualcomm.com
-+W:    http://bluez.sf.net
-+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
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+W:    http://www.holtmann.org/linux/bluetooth/
-+S:    Maintained
-+
-+BLUETOOTH HCI BLUECARD DRIVER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+W:    http://www.holtmann.org/linux/bluetooth/
-+S:    Maintained
-+
-+BLUETOOTH HCI BT3C DRIVER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+W:    http://www.holtmann.org/linux/bluetooth/
-+S:    Maintained
-+
-+BLUETOOTH HCI BTUART DRIVER
-+P:    Marcel Holtmann
-+M:    marcel@holtmann.org
-+W:    http://www.holtmann.org/linux/bluetooth/
-+S:    Maintained
-+
-+BLUETOOTH HCI VHCI DRIVER
- P:    Maxim Krasnyansky
- M:    maxk@qualcomm.com
- W:    http://bluez.sf.net
---- linux/net/bluetooth/af_bluetooth.c~bluetooth-2.4.18-mh11   2001-09-07 18:28:38.000000000 +0200
-+++ linux/net/bluetooth/af_bluetooth.c 2004-01-25 23:37:39.000000000 +0100
-@@ -25,14 +25,15 @@
- /*
-  * BlueZ Bluetooth address family and sockets.
-  *
-- * $Id: af_bluetooth.c,v 1.4 2001/07/05 18:42:44 maxk Exp $
-+ * $Id: af_bluetooth.c,v 1.8 2002/07/22 20:32:54 maxk Exp $
-  */
--#define VERSION "1.1"
-+#define VERSION "2.3"
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
-+#include <linux/list.h>
- #include <linux/errno.h>
- #include <linux/kernel.h>
- #include <linux/major.h>
-@@ -40,6 +41,7 @@
- #include <linux/slab.h>
- #include <linux/skbuff.h>
- #include <linux/init.h>
-+#include <linux/poll.h>
- #include <linux/proc_fs.h>
- #include <net/sock.h>
-@@ -48,70 +50,79 @@
- #endif
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
-+
-+#ifndef AF_BLUETOOTH_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
- /* Bluetooth sockets */
--static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
-+#define BLUEZ_MAX_PROTO       6
-+static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
- int bluez_sock_register(int proto, struct net_proto_family *ops)
- {
--      if (proto > BLUEZ_MAX_PROTO)
-+      if (proto >= BLUEZ_MAX_PROTO)
-               return -EINVAL;
--      if (bluez_sock[proto])
-+      if (bluez_proto[proto])
-               return -EEXIST;
--      bluez_sock[proto] = ops;
-+      bluez_proto[proto] = ops;
-       return 0;
- }
- int bluez_sock_unregister(int proto)
- {
--      if (proto > BLUEZ_MAX_PROTO)
-+      if (proto >= BLUEZ_MAX_PROTO)
-               return -EINVAL;
--      if (!bluez_sock[proto])
-+      if (!bluez_proto[proto])
-               return -ENOENT;
--      bluez_sock[proto] = NULL;
-+      bluez_proto[proto] = NULL;
-       return 0;
- }
- static int bluez_sock_create(struct socket *sock, int proto)
- {
--      if (proto > BLUEZ_MAX_PROTO)
-+      if (proto >= BLUEZ_MAX_PROTO)
-               return -EINVAL;
- #if defined(CONFIG_KMOD)
--      if (!bluez_sock[proto]) {
-+      if (!bluez_proto[proto]) {
-               char module_name[30];
-               sprintf(module_name, "bt-proto-%d", proto);
-               request_module(module_name);
-       }
- #endif
--      if (!bluez_sock[proto])
-+      if (!bluez_proto[proto])
-               return -ENOENT;
--      return bluez_sock[proto]->create(sock, proto);
-+      return bluez_proto[proto]->create(sock, proto);
-+}
-+
-+void bluez_sock_init(struct socket *sock, struct sock *sk)
-+{ 
-+      sock_init_data(sock, sk);
-+      INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
- }
- void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
- {
--      write_lock(&l->lock);
--
-+      write_lock_bh(&l->lock);
-       sk->next = l->head;
-       l->head = sk;
-       sock_hold(sk);
--
--      write_unlock(&l->lock);
-+      write_unlock_bh(&l->lock);
- }
- void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
- {
-       struct sock **skp;
--      write_lock(&l->lock);
-+      write_lock_bh(&l->lock);
-       for (skp = &l->head; *skp; skp = &((*skp)->next)) {
-               if (*skp == sk) {
-                       *skp = sk->next;
-@@ -119,7 +130,162 @@
-                       break;
-               }
-       }
--      write_unlock(&l->lock);
-+      write_unlock_bh(&l->lock);
-+}
-+
-+void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
-+{
-+      BT_DBG("parent %p, sk %p", parent, sk);
-+
-+      sock_hold(sk);
-+      list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
-+      bluez_pi(sk)->parent = parent;
-+      parent->ack_backlog++;
-+}
-+
-+static void bluez_accept_unlink(struct sock *sk)
-+{
-+      BT_DBG("sk %p state %d", sk, sk->state);
-+
-+      list_del_init(&bluez_pi(sk)->accept_q);
-+      bluez_pi(sk)->parent->ack_backlog--;
-+      bluez_pi(sk)->parent = NULL;
-+      sock_put(sk);
-+}
-+
-+struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
-+{
-+      struct list_head *p, *n;
-+      struct bluez_pinfo *pi;
-+      struct sock *sk;
-+      
-+      BT_DBG("parent %p", parent);
-+
-+      list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
-+              pi = list_entry(p, struct bluez_pinfo, accept_q);
-+              sk = bluez_sk(pi);
-+              
-+              lock_sock(sk);
-+              if (sk->state == BT_CLOSED) {
-+                      release_sock(sk);
-+                      bluez_accept_unlink(sk);
-+                      continue;
-+              }
-+              
-+              if (sk->state == BT_CONNECTED || !newsock) {
-+                      bluez_accept_unlink(sk);
-+                      if (newsock)
-+                              sock_graft(sk, newsock);
-+                      release_sock(sk);
-+                      return sk;
-+              }
-+              release_sock(sk);
-+      }
-+      return NULL;
-+}
-+
-+int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
-+{
-+      int noblock = flags & MSG_DONTWAIT;
-+      struct sock *sk = sock->sk;
-+      struct sk_buff *skb;
-+      int copied, err;
-+
-+      BT_DBG("sock %p sk %p len %d", sock, sk, len);
-+
-+      if (flags & (MSG_OOB))
-+              return -EOPNOTSUPP;
-+
-+      if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
-+              if (sk->shutdown & RCV_SHUTDOWN)
-+                      return 0;
-+              return err;
-+      }
-+
-+      msg->msg_namelen = 0;
-+
-+      copied = skb->len;
-+      if (len < copied) {
-+              msg->msg_flags |= MSG_TRUNC;
-+              copied = len;
-+      }
-+
-+      skb->h.raw = skb->data;
-+      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-+
-+      skb_free_datagram(sk, skb);
-+
-+      return err ? : copied;
-+}
-+
-+unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
-+{
-+      struct sock *sk = sock->sk;
-+      unsigned int mask;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      poll_wait(file, sk->sleep, wait);
-+      mask = 0;
-+
-+      if (sk->err || !skb_queue_empty(&sk->error_queue))
-+              mask |= POLLERR;
-+
-+      if (sk->shutdown == SHUTDOWN_MASK)
-+              mask |= POLLHUP;
-+
-+      if (!skb_queue_empty(&sk->receive_queue) || 
-+                      !list_empty(&bluez_pi(sk)->accept_q) ||
-+                      (sk->shutdown & RCV_SHUTDOWN))
-+              mask |= POLLIN | POLLRDNORM;
-+
-+      if (sk->state == BT_CLOSED)
-+              mask |= POLLHUP;
-+
-+      if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
-+              return mask;
-+      
-+      if (sock_writeable(sk))
-+              mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-+      else
-+              set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
-+
-+      return mask;
-+}
-+
-+int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      int err = 0;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      add_wait_queue(sk->sleep, &wait);
-+      while (sk->state != state) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (!timeo) {
-+                      err = -EAGAIN;
-+                      break;
-+              }
-+
-+              if (signal_pending(current)) {
-+                      err = sock_intr_errno(timeo);
-+                      break;
-+              }
-+
-+              release_sock(sk);
-+              timeo = schedule_timeout(timeo);
-+              lock_sock(sk);
-+
-+              if (sk->err) {
-+                      err = sock_error(sk);
-+                      break;
-+              }
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+      return err;
- }
- struct net_proto_family bluez_sock_family_ops =
-@@ -129,9 +295,9 @@
- int bluez_init(void)
- {
--      INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-+      BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
-                VERSION);
--      INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+      BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-       proc_mkdir("bluetooth", NULL);
-@@ -164,5 +330,6 @@
- module_exit(bluez_cleanup);
- MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
-+MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
-+MODULE_LICENSE("GPL");
- #endif
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/bnep.h    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,185 @@
-+/*
-+  BNEP protocol definition for Linux Bluetooth stack (BlueZ).
-+  Copyright (C) 2002 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.
-+
-+  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
-+*/
-+
-+/*
-+ * $Id: bnep2.h,v 1.9 2002/07/14 07:09:19 maxk Exp $
-+ */
-+
-+#ifndef _BNEP_H
-+#define _BNEP_H
-+
-+#include <linux/types.h>
-+#include <net/bluetooth/bluetooth.h>
-+
-+#include "crc32.h"
-+
-+// Limits
-+#define BNEP_MAX_PROTO_FILTERS     5
-+#define BNEP_MAX_MULTICAST_FILTERS 20
-+
-+// UUIDs
-+#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
-+#define BNEP_UUID16    0x02
-+#define BNEP_UUID32    0x04
-+#define BNEP_UUID128   0x16
-+
-+#define BNEP_SVC_PANU  0x1115
-+#define BNEP_SVC_NAP   0x1116
-+#define BNEP_SVC_GN    0x1117
-+
-+// Packet types
-+#define BNEP_GENERAL               0x00
-+#define BNEP_CONTROL               0x01
-+#define BNEP_COMPRESSED            0x02
-+#define BNEP_COMPRESSED_SRC_ONLY   0x03
-+#define BNEP_COMPRESSED_DST_ONLY   0x04
-+
-+// Control types
-+#define BNEP_CMD_NOT_UNDERSTOOD    0x00
-+#define BNEP_SETUP_CONN_REQ        0x01
-+#define BNEP_SETUP_CONN_RSP        0x02
-+#define BNEP_FILTER_NET_TYPE_SET   0x03
-+#define BNEP_FILTER_NET_TYPE_RSP   0x04
-+#define BNEP_FILTER_MULTI_ADDR_SET 0x05
-+#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
-+
-+// Extension types
-+#define BNEP_EXT_CONTROL           0x00
-+
-+// Response messages 
-+#define BNEP_SUCCESS               0x00
-+
-+#define BNEP_CONN_INVALID_DST      0x01
-+#define BNEP_CONN_INVALID_SRC      0x02
-+#define BNEP_CONN_INVALID_SVC      0x03
-+#define BNEP_CONN_NOT_ALLOWED      0x04
-+
-+#define BNEP_FILTER_UNSUPPORTED_REQ    0x01
-+#define BNEP_FILTER_INVALID_RANGE      0x02
-+#define BNEP_FILTER_INVALID_MCADDR     0x02
-+#define BNEP_FILTER_LIMIT_REACHED      0x03
-+#define BNEP_FILTER_DENIED_SECURITY    0x04
-+
-+// L2CAP settings
-+#define BNEP_MTU         1691
-+#define BNEP_PSM       0x0f
-+#define BNEP_FLUSH_TO    0xffff
-+#define BNEP_CONNECT_TO  15
-+#define BNEP_FILTER_TO   15
-+
-+// Headers 
-+#define BNEP_TYPE_MASK         0x7f
-+#define BNEP_EXT_HEADER        0x80
-+
-+struct bnep_setup_conn_req {
-+      __u8  type;
-+      __u8  ctrl;
-+      __u8  uuid_size;
-+      __u8  service[0];
-+} __attribute__((packed));
-+
-+struct bnep_set_filter_req {
-+      __u8  type;
-+      __u8  ctrl;
-+      __u16 len;
-+      __u8  list[0];
-+} __attribute__((packed));
-+
-+struct bnep_control_rsp {
-+      __u8  type;
-+      __u8  ctrl;
-+      __u16 resp;
-+} __attribute__((packed));
-+
-+struct bnep_ext_hdr {
-+      __u8  type;
-+      __u8  len;
-+      __u8  data[0];
-+} __attribute__((packed));
-+
-+/* BNEP ioctl defines */
-+#define BNEPCONNADD   _IOW('B', 200, int)
-+#define BNEPCONNDEL   _IOW('B', 201, int)
-+#define BNEPGETCONNLIST       _IOR('B', 210, int)
-+#define BNEPGETCONNINFO       _IOR('B', 211, int)
-+
-+struct bnep_connadd_req {
-+      int   sock;       // Connected socket
-+      __u32 flags;
-+      __u16 role;
-+      char  device[16]; // Name of the Ethernet device
-+};
-+
-+struct bnep_conndel_req {
-+      __u32 flags;
-+      __u8  dst[ETH_ALEN];
-+};
-+
-+struct bnep_conninfo {
-+      __u32 flags;
-+      __u16 role;
-+      __u16 state;    
-+      __u8  dst[ETH_ALEN];
-+      char  device[16];
-+};
-+
-+struct bnep_connlist_req {
-+      __u32  cnum;
-+      struct bnep_conninfo *ci;
-+};
-+
-+struct bnep_proto_filter {
-+      __u16 start;
-+      __u16 end;
-+};
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
-+int bnep_del_connection(struct bnep_conndel_req *req);
-+int bnep_get_connlist(struct bnep_connlist_req *req);
-+int bnep_get_conninfo(struct bnep_conninfo *ci);
-+
-+// BNEP sessions
-+struct bnep_session {
-+      struct list_head list;
-+      
-+      unsigned int  role;
-+        unsigned long state;
-+        unsigned long flags;
-+      atomic_t      killed;
-+
-+      struct ethhdr eh;
-+      struct msghdr msg;
-+
-+      struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
-+      u64    mc_filter;
-+      
-+      struct socket    *sock;
-+      struct net_device dev;
-+      struct net_device_stats stats;
-+};
-+
-+int bnep_net_init(struct net_device *dev);
-+int bnep_sock_init(void);
-+int bnep_sock_cleanup(void);
-+
-+static inline int bnep_mc_hash(__u8 *addr)
-+{
-+        return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
-+}
-+
-+#endif
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/Config.in 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,11 @@
-+#
-+# Bluetooth BNEP layer configuration
-+#
-+
-+dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-+   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
-+   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+fi
-+
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/core.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,708 @@
-+/* 
-+   BNEP implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2001-2002 Inventel Systemes
-+   Written 2001-2002 by
-+      ClĂ©ment Moreau <clement.moreau@inventel.fr>
-+      David Libault  <david.libault@inventel.fr>
-+
-+   Copyright (C) 2002 Maxim Krasnyanskiy <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: core.c,v 1.18 2002/07/14 07:09:19 maxk Exp $
-+ */ 
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/errno.h>
-+#include <linux/smp_lock.h>
-+#include <linux/net.h>
-+#include <net/sock.h>
-+
-+#include <linux/socket.h>
-+#include <linux/file.h>
-+
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.1"
-+
-+static LIST_HEAD(bnep_session_list);
-+static DECLARE_RWSEM(bnep_session_sem);
-+
-+static struct bnep_session *__bnep_get_session(u8 *dst)
-+{
-+      struct bnep_session *s;
-+      struct list_head *p;
-+
-+      BT_DBG("");
-+
-+      list_for_each(p, &bnep_session_list) {
-+              s = list_entry(p, struct bnep_session, list);   
-+              if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
-+                      return s;
-+      }
-+      return NULL;
-+}
-+
-+static void __bnep_link_session(struct bnep_session *s)
-+{
-+      MOD_INC_USE_COUNT;
-+      list_add(&s->list, &bnep_session_list); 
-+}
-+
-+static void __bnep_unlink_session(struct bnep_session *s)
-+{
-+      list_del(&s->list);
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static int bnep_send(struct bnep_session *s, void *data, size_t len)
-+{
-+      struct socket *sock = s->sock;
-+      struct iovec iv = { data, len };
-+      s->msg.msg_iov    = &iv;
-+      s->msg.msg_iovlen = 1;
-+      return sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+}
-+
-+static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
-+{
-+      struct bnep_control_rsp rsp;
-+      rsp.type = BNEP_CONTROL;
-+      rsp.ctrl = ctrl;
-+      rsp.resp = htons(resp);
-+      return bnep_send(s, &rsp, sizeof(rsp));
-+}
-+
-+static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
-+{
-+      int n;
-+
-+      if (len < 2)
-+              return -EILSEQ;
-+      
-+      n = ntohs(get_unaligned(data));
-+      data++; len -= 2;
-+
-+      if (len < n)
-+              return -EILSEQ;
-+
-+      BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+      n /= 4;
-+      if (n <= BNEP_MAX_PROTO_FILTERS) {
-+              struct bnep_proto_filter *f = s->proto_filter;
-+              int i;
-+
-+              for (i = 0; i < n; i++) {
-+                      f[i].start = get_unaligned(data++);
-+                      f[i].end   = get_unaligned(data++);
-+
-+                      BT_DBG("proto filter start %d end %d",
-+                              f[i].start, f[i].end);
-+              }
-+              if (i < BNEP_MAX_PROTO_FILTERS)
-+                      memset(f + i, 0, sizeof(*f));
-+
-+              bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
-+      } else {
-+              bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
-+      }
-+#else
-+      bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+      return 0;
-+}
-+
-+static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
-+{
-+      int n;
-+
-+      if (len < 2)
-+              return -EILSEQ;
-+      
-+      n = ntohs(get_unaligned((u16 *) data)); 
-+      data += 2; len -= 2;
-+
-+      if (len < n)
-+              return -EILSEQ;
-+
-+      BT_DBG("filter len %d", n);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+      n /= (ETH_ALEN * 2);
-+
-+      if (n > 0) {
-+              s->mc_filter = 0;
-+
-+              /* Always send broadcast */
-+              set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
-+
-+              /* Add address ranges to the multicast hash */
-+              for (; n > 0; n--) {
-+                      u8 a1[6], *a2;
-+
-+                      memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
-+                      a2 = data; data += ETH_ALEN;
-+      
-+                      BT_DBG("mc filter %s -> %s",
-+                              batostr((void *) a1), batostr((void *) a2));
-+
-+                      #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
-+
-+                      /* Iterate from a1 to a2 */
-+                      set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+                      while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
-+                              INCA(a1);
-+                              set_bit(bnep_mc_hash(a1), &s->mc_filter);
-+                      }
-+              }
-+      }
-+
-+      BT_DBG("mc filter hash 0x%llx", s->mc_filter);
-+
-+      bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
-+#else
-+      bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
-+#endif
-+      return 0;
-+}
-+
-+static int bnep_rx_control(struct bnep_session *s, void *data, int len)
-+{
-+      u8  cmd = *(u8 *)data;
-+      int err = 0;
-+
-+      data++; len--;
-+      
-+      switch (cmd) {
-+      case BNEP_CMD_NOT_UNDERSTOOD:
-+      case BNEP_SETUP_CONN_REQ:
-+      case BNEP_SETUP_CONN_RSP:
-+      case BNEP_FILTER_NET_TYPE_RSP:
-+      case BNEP_FILTER_MULTI_ADDR_RSP:
-+              /* Ignore these for now */
-+              break;
-+              
-+      case BNEP_FILTER_NET_TYPE_SET:
-+              err = bnep_ctrl_set_netfilter(s, data, len);
-+              break;
-+
-+      case BNEP_FILTER_MULTI_ADDR_SET:
-+              err = bnep_ctrl_set_mcfilter(s, data, len);
-+              break;
-+
-+      default: {
-+                      u8 pkt[3];
-+                      pkt[0] = BNEP_CONTROL;
-+                      pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
-+                      pkt[2] = cmd;
-+                      bnep_send(s, pkt, sizeof(pkt));
-+              }
-+              break;
-+      }
-+
-+      return err;
-+}
-+
-+static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
-+{
-+      struct bnep_ext_hdr *h;
-+      int err = 0;
-+
-+      do {
-+              h = (void *) skb->data;
-+              if (!skb_pull(skb, sizeof(*h))) {
-+                      err = -EILSEQ;
-+                      break;
-+              }
-+
-+              BT_DBG("type 0x%x len %d", h->type, h->len);
-+              
-+              switch (h->type & BNEP_TYPE_MASK) {
-+              case BNEP_EXT_CONTROL:
-+                      bnep_rx_control(s, skb->data, skb->len);
-+                      break;
-+
-+              default:
-+                      /* Unknown extension, skip it. */
-+                      break;
-+              }
-+      
-+              if (!skb_pull(skb, h->len)) {
-+                      err = -EILSEQ;
-+                      break;
-+              }
-+      } while (!err && (h->type & BNEP_EXT_HEADER));
-+      
-+      return err;
-+}
-+
-+static u8 __bnep_rx_hlen[] = {
-+      ETH_HLEN,     /* BNEP_GENERAL */
-+      0,            /* BNEP_CONTROL */
-+      2,            /* BNEP_COMPRESSED */
-+      ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
-+      ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
-+};
-+#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1)
-+
-+static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+      struct net_device *dev = &s->dev;
-+      struct sk_buff *nskb;
-+      u8 type;
-+
-+      dev->last_rx = jiffies;
-+      s->stats.rx_bytes += skb->len;
-+
-+      type = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+      if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
-+              goto badframe;
-+      
-+      if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
-+              bnep_rx_control(s, skb->data, skb->len);
-+              kfree_skb(skb);
-+              return 0;
-+      }
-+
-+      skb->mac.raw = skb->data;
-+
-+      /* Verify and pull out header */
-+      if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
-+              goto badframe;
-+
-+      s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+
-+      if (type & BNEP_EXT_HEADER) {
-+              if (bnep_rx_extension(s, skb) < 0)
-+                      goto badframe;
-+      }
-+
-+      /* Strip 802.1p header */
-+      if (ntohs(s->eh.h_proto) == 0x8100) {
-+              if (!skb_pull(skb, 4))
-+                      goto badframe;
-+              s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
-+      }
-+      
-+      /* We have to alloc new skb and copy data here :(. Because original skb
-+       * may not be modified and because of the alignment requirements. */
-+      nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
-+      if (!nskb) {
-+              s->stats.rx_dropped++;
-+              kfree_skb(skb);
-+              return -ENOMEM;
-+      }
-+      skb_reserve(nskb, 2);
-+
-+      /* Decompress header and construct ether frame */
-+      switch (type & BNEP_TYPE_MASK) {
-+      case BNEP_COMPRESSED:
-+              memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
-+              break;
-+      
-+      case BNEP_COMPRESSED_SRC_ONLY:
-+              memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
-+              memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+              put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+              break;
-+
-+      case BNEP_COMPRESSED_DST_ONLY:
-+              memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
-+              memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
-+              break;
-+
-+      case BNEP_GENERAL:
-+              memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
-+              put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
-+              break;
-+      }
-+
-+      memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
-+      kfree_skb(skb);
-+      
-+      s->stats.rx_packets++;
-+      nskb->dev       = dev;
-+      nskb->ip_summed = CHECKSUM_UNNECESSARY;
-+      nskb->protocol  = eth_type_trans(nskb, dev);
-+      netif_rx_ni(nskb);
-+      return 0;
-+
-+badframe:
-+      s->stats.rx_errors++;
-+      kfree_skb(skb);
-+      return 0;
-+}
-+
-+static u8 __bnep_tx_types[] = {
-+      BNEP_GENERAL,
-+      BNEP_COMPRESSED_SRC_ONLY,
-+      BNEP_COMPRESSED_DST_ONLY,
-+      BNEP_COMPRESSED
-+};
-+
-+static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
-+{
-+      struct ethhdr *eh = (void *) skb->data;
-+      struct socket *sock = s->sock;
-+      struct iovec iv[3];
-+      int len = 0, il = 0;
-+      u8 type = 0;
-+
-+      BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
-+
-+      if (!skb->dev) {
-+              /* Control frame sent by us */
-+              goto send;
-+      }
-+
-+      iv[il++] = (struct iovec) { &type, 1 };
-+      len++;
-+
-+      if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
-+              type |= 0x01;
-+
-+      if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
-+              type |= 0x02;
-+
-+      if (type)
-+              skb_pull(skb, ETH_ALEN * 2);
-+
-+      type = __bnep_tx_types[type];
-+      switch (type) {
-+      case BNEP_COMPRESSED_SRC_ONLY:
-+              iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
-+              len += ETH_ALEN;
-+              break;
-+              
-+      case BNEP_COMPRESSED_DST_ONLY:
-+              iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
-+              len += ETH_ALEN;
-+              break;
-+      }
-+
-+send:
-+      iv[il++] = (struct iovec) { skb->data, skb->len };
-+      len += skb->len;
-+      
-+      /* FIXME: linearize skb */
-+      
-+      s->msg.msg_iov    = iv;
-+      s->msg.msg_iovlen = il;
-+      len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
-+      kfree_skb(skb);
-+
-+      if (len > 0) {
-+              s->stats.tx_bytes += len;
-+              s->stats.tx_packets++;
-+              return 0;
-+      }
-+
-+      return len;
-+}
-+
-+static int bnep_session(void *arg)
-+{
-+      struct bnep_session *s = arg;
-+      struct net_device *dev = &s->dev;
-+      struct sock *sk = s->sock->sk;
-+      struct sk_buff *skb;
-+      wait_queue_t wait;
-+
-+      BT_DBG("");
-+
-+        daemonize(); reparent_to_init();
-+
-+        sprintf(current->comm, "kbnepd %s", dev->name);
-+      
-+        sigfillset(&current->blocked);
-+      flush_signals(current);
-+
-+      current->nice = -15;
-+
-+        set_fs(KERNEL_DS);
-+
-+      init_waitqueue_entry(&wait, current);
-+      add_wait_queue(sk->sleep, &wait);
-+      while (!atomic_read(&s->killed)) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              // RX
-+              while ((skb = skb_dequeue(&sk->receive_queue))) {
-+                      skb_orphan(skb);
-+                      bnep_rx_frame(s, skb);
-+              }
-+
-+              if (sk->state != BT_CONNECTED)
-+                      break;
-+      
-+              // TX
-+              while ((skb = skb_dequeue(&sk->write_queue)))
-+                      if (bnep_tx_frame(s, skb))
-+                              break;
-+              netif_wake_queue(dev);
-+      
-+              schedule();
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+
-+      /* Cleanup session */
-+      down_write(&bnep_session_sem);
-+
-+      /* Delete network device */
-+      unregister_netdev(dev);
-+
-+      /* Release the socket */
-+      fput(s->sock->file);
-+
-+      __bnep_unlink_session(s);
-+
-+      up_write(&bnep_session_sem);
-+      kfree(s);
-+      return 0;
-+}
-+
-+int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
-+{
-+      struct net_device *dev;
-+      struct bnep_session *s, *ss;
-+      u8 dst[ETH_ALEN], src[ETH_ALEN];
-+      int err;
-+
-+      BT_DBG("");
-+
-+      baswap((void *) dst, &bluez_pi(sock->sk)->dst);
-+      baswap((void *) src, &bluez_pi(sock->sk)->src);
-+
-+      s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
-+      if (!s) 
-+              return -ENOMEM;
-+      memset(s, 0, sizeof(struct bnep_session));
-+
-+      down_write(&bnep_session_sem);
-+
-+      ss = __bnep_get_session(dst);
-+      if (ss && ss->state == BT_CONNECTED) {
-+              err = -EEXIST;
-+              goto failed;
-+      }
-+
-+      dev = &s->dev;
-+      
-+      if (*req->device)
-+              strcpy(dev->name, req->device);
-+      else
-+              strcpy(dev->name, "bnep%d");
-+
-+      memset(dev->broadcast, 0xff, ETH_ALEN);
-+
-+      /* This is rx header therefor addresses are swaped.
-+       * ie eh.h_dest is our local address. */
-+      memcpy(s->eh.h_dest,   &src, ETH_ALEN);
-+      memcpy(s->eh.h_source, &dst, ETH_ALEN);
-+
-+      s->sock  = sock;
-+      s->role  = req->role;
-+      s->state = BT_CONNECTED;
-+      
-+      s->msg.msg_flags = MSG_NOSIGNAL;
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+      /* Set default mc filter */
-+      set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
-+#endif
-+      
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+      /* Set default protocol filter */
-+
-+      /* (IPv4, ARP)  */
-+      s->proto_filter[0].start = htons(0x0800);
-+      s->proto_filter[0].end   = htons(0x0806);
-+      /* (RARP, AppleTalk) */
-+      s->proto_filter[1].start = htons(0x8035);
-+      s->proto_filter[1].end   = htons(0x80F3);
-+      /* (IPX, IPv6) */
-+      s->proto_filter[2].start = htons(0x8137);
-+      s->proto_filter[2].end   = htons(0x86DD);
-+#endif
-+      
-+      dev->init = bnep_net_init;
-+      dev->priv = s;
-+      err = register_netdev(dev);
-+      if (err) {
-+              goto failed;
-+      }
-+
-+      __bnep_link_session(s);
-+      
-+      err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+      if (err < 0) {
-+              /* Session thread start failed, gotta cleanup. */
-+              unregister_netdev(dev);
-+              __bnep_unlink_session(s);
-+              goto failed;
-+      }
-+
-+      up_write(&bnep_session_sem);
-+      strcpy(req->device, dev->name);
-+      return 0;
-+
-+failed:
-+      up_write(&bnep_session_sem);
-+      kfree(s);
-+      return err;
-+}
-+
-+int bnep_del_connection(struct bnep_conndel_req *req)
-+{
-+      struct bnep_session *s;
-+      int  err = 0;
-+
-+      BT_DBG("");
-+
-+      down_read(&bnep_session_sem);
-+
-+      s = __bnep_get_session(req->dst);
-+      if (s) {
-+              /* Wakeup user-space which is polling for socket errors.
-+               * This is temporary hack untill we have shutdown in L2CAP */
-+              s->sock->sk->err = EUNATCH;
-+              
-+              /* Kill session thread */
-+              atomic_inc(&s->killed);
-+              wake_up_interruptible(s->sock->sk->sleep);
-+      } else
-+              err = -ENOENT;
-+
-+      up_read(&bnep_session_sem);
-+      return err;
-+}
-+
-+static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
-+{
-+      memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
-+      strcpy(ci->device, s->dev.name);
-+      ci->flags = s->flags;
-+      ci->state = s->state;
-+      ci->role  = s->role;
-+}
-+
-+int bnep_get_connlist(struct bnep_connlist_req *req)
-+{
-+      struct list_head *p;
-+      int err = 0, n = 0;
-+
-+      down_read(&bnep_session_sem);
-+
-+      list_for_each(p, &bnep_session_list) {
-+              struct bnep_session *s;
-+              struct bnep_conninfo ci;
-+
-+              s = list_entry(p, struct bnep_session, list);
-+
-+              __bnep_copy_ci(&ci, s);
-+              
-+              if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-+
-+              if (++n >= req->cnum)
-+                      break;
-+
-+              req->ci++;
-+      }
-+      req->cnum = n;
-+
-+      up_read(&bnep_session_sem);
-+      return err;
-+}
-+
-+int bnep_get_conninfo(struct bnep_conninfo *ci)
-+{
-+      struct bnep_session *s;
-+      int err = 0;
-+
-+      down_read(&bnep_session_sem);
-+
-+      s = __bnep_get_session(ci->dst);
-+      if (s)
-+              __bnep_copy_ci(ci, s);
-+      else
-+              err = -ENOENT;
-+
-+      up_read(&bnep_session_sem);
-+      return err;
-+}
-+
-+static int __init bnep_init_module(void)
-+{
-+      l2cap_load();
-+
-+      bnep_crc32_init();
-+      bnep_sock_init();
-+
-+      BT_INFO("BlueZ BNEP ver %s", VERSION);
-+      BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
-+      BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
-+      BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
-+      BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+
-+      return 0;
-+}
-+
-+static void __exit bnep_cleanup_module(void)
-+{
-+      bnep_sock_cleanup();
-+      bnep_crc32_cleanup();
-+}
-+
-+module_init(bnep_init_module);
-+module_exit(bnep_cleanup_module);
-+
-+MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
-+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/crc32.c   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,59 @@
-+/* 
-+ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
-+ *
-+ * FIXME: Remove in 2.5  
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <asm/atomic.h>
-+
-+#include "crc32.h"
-+
-+#define CRCPOLY_BE 0x04c11db7
-+#define CRC_BE_BITS 8
-+
-+static u32 *bnep_crc32_table;
-+
-+/*
-+ * This code is in the public domain; copyright abandoned.
-+ * Liability for non-performance of this code is limited to the amount
-+ * you paid for it.  Since it is distributed for free, your refund will
-+ * be very very small.  If it breaks, you get to keep both pieces.
-+ */
-+u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
-+{
-+      while (len--)
-+              crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
-+      
-+      return crc;
-+}
-+
-+int __init bnep_crc32_init(void)
-+{
-+      unsigned i, j;
-+      u32 crc = 0x80000000;
-+
-+      bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
-+      if (!bnep_crc32_table)
-+              return -ENOMEM;
-+
-+      bnep_crc32_table[0] = 0;
-+
-+      for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
-+              crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-+              for (j = 0; j < i; j++)
-+                      bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
-+      }
-+      return 0;
-+}
-+
-+void __exit bnep_crc32_cleanup(void)
-+{
-+      if (bnep_crc32_table)
-+              kfree(bnep_crc32_table);
-+      bnep_crc32_table = NULL;
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/crc32.h   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,10 @@
-+/*
-+ * crc32.h
-+ * See crc32.c for license and changes
-+ *
-+ * FIXME: Remove in 2.5
-+ */
-+
-+int  bnep_crc32_init(void);
-+void bnep_crc32_cleanup(void);
-+u32  bnep_crc32(u32 crc, unsigned char const *p, size_t len);
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/Makefile  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth BNEP layer
-+#
-+
-+O_TARGET := bnep.o
-+
-+obj-y  := core.o sock.o netdev.o crc32.o
-+obj-m    += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/netdev.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,254 @@
-+/* 
-+   BNEP implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2001-2002 Inventel Systemes
-+   Written 2001-2002 by
-+      ClĂ©ment Moreau <clement.moreau@inventel.fr>
-+      David Libault  <david.libault@inventel.fr>
-+
-+   Copyright (C) 2002 Maxim Krasnyanskiy <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: netdev.c,v 1.7 2002/07/14 05:39:26 maxk Exp $
-+ */ 
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/socket.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/wait.h>
-+
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+#define BNEP_TX_QUEUE_LEN 20
-+
-+static int bnep_net_open(struct net_device *dev)
-+{
-+      netif_start_queue(dev);
-+      return 0;
-+}
-+
-+static int bnep_net_close(struct net_device *dev)
-+{
-+      netif_stop_queue(dev);
-+      return 0;
-+}
-+
-+static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
-+{
-+      struct bnep_session *s = dev->priv;
-+      return &s->stats;
-+}
-+
-+static void bnep_net_set_mc_list(struct net_device *dev)
-+{
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+      struct bnep_session *s = dev->priv;
-+      struct sock *sk = s->sock->sk;
-+      struct bnep_set_filter_req *r;
-+      struct sk_buff *skb;
-+      int size;
-+
-+      BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
-+
-+      size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
-+      skb  = alloc_skb(size, GFP_ATOMIC);
-+      if (!skb) {
-+              BT_ERR("%s Multicast list allocation failed", dev->name);
-+              return;
-+      }
-+
-+      r = (void *) skb->data;
-+      __skb_put(skb, sizeof(*r));
-+
-+      r->type = BNEP_CONTROL;
-+      r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
-+
-+        if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
-+              u8 start[ETH_ALEN] = { 0x01 };
-+
-+              /* Request all addresses */
-+              memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
-+              memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+              r->len = htons(ETH_ALEN * 2);
-+      } else {
-+                struct dev_mc_list *dmi = dev->mc_list;
-+              int i, len = skb->len;
-+
-+              if (dev->flags & IFF_BROADCAST) {
-+                      memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+                      memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
-+              }       
-+              
-+              /* FIXME: We should group addresses here. */
-+
-+              for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
-+                      memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+                      memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-+                      dmi = dmi->next;
-+              }
-+              r->len = htons(skb->len - len);
-+      }
-+
-+      skb_queue_tail(&sk->write_queue, skb);
-+      wake_up_interruptible(sk->sleep);
-+#endif
-+}
-+
-+static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
-+{
-+      BT_DBG("%s", dev->name);
-+      return 0;
-+}
-+
-+static void bnep_net_timeout(struct net_device *dev)
-+{
-+      BT_DBG("net_timeout");
-+      netif_wake_queue(dev);
-+}
-+
-+static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-+{
-+      return -EINVAL;
-+}
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+      struct ethhdr *eh = (void *) skb->data;
-+
-+      if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
-+              BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, 
-+                              eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
-+                              eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
-+              return 1;
-+      }
-+      return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+/* Determine ether protocol. Based on eth_type_trans. */
-+static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
-+{
-+      struct ethhdr *eh = (void *) skb->data;
-+      
-+      if (ntohs(eh->h_proto) >= 1536)
-+              return eh->h_proto;
-+              
-+      if (get_unaligned((u16 *) skb->data) == 0xFFFF)
-+              return htons(ETH_P_802_3);
-+              
-+      return htons(ETH_P_802_2);
-+}
-+
-+static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
-+{
-+      u16 proto = bnep_net_eth_proto(skb);
-+      struct bnep_proto_filter *f = s->proto_filter;
-+      int i;
-+      
-+      for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
-+              if (proto >= f[i].start && proto <= f[i].end)
-+                      return 0;
-+      }
-+
-+      BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
-+      return 1;
-+}
-+#endif
-+
-+static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      struct bnep_session *s = dev->priv;
-+      struct sock *sk = s->sock->sk;
-+
-+      BT_DBG("skb %p, dev %p", skb, dev);
-+
-+#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
-+      if (bnep_net_mc_filter(skb, s)) {
-+              kfree_skb(skb);
-+              return 0;
-+      }
-+#endif
-+      
-+#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
-+      if (bnep_net_proto_filter(skb, s)) {
-+              kfree_skb(skb);
-+              return 0;
-+      }
-+#endif
-+      
-+      /*
-+       * We cannot send L2CAP packets from here as we are potentially in a bh.
-+       * So we have to queue them and wake up session thread which is sleeping
-+       * on the sk->sleep.
-+       */
-+      dev->trans_start = jiffies;
-+      skb_queue_tail(&sk->write_queue, skb);
-+      wake_up_interruptible(sk->sleep);
-+
-+      if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
-+              BT_DBG("tx queue is full");
-+
-+              /* Stop queuing.
-+               * Session thread will do netif_wake_queue() */
-+              netif_stop_queue(dev);
-+      }
-+
-+      return 0;
-+}
-+
-+int bnep_net_init(struct net_device *dev)
-+{
-+      struct bnep_session *s = dev->priv;
-+
-+      memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
-+      dev->addr_len = ETH_ALEN;
-+
-+      ether_setup(dev);
-+
-+      dev->open            = bnep_net_open;
-+      dev->stop            = bnep_net_close;
-+      dev->hard_start_xmit = bnep_net_xmit;
-+      dev->get_stats       = bnep_net_get_stats;
-+      dev->do_ioctl        = bnep_net_ioctl;
-+      dev->set_mac_address = bnep_net_set_mac_addr;
-+      dev->set_multicast_list = bnep_net_set_mc_list;
-+
-+      dev->watchdog_timeo  = HZ * 2;
-+      dev->tx_timeout      = bnep_net_timeout;
-+
-+      return 0;
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/bnep/sock.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,238 @@
-+/* 
-+   BNEP implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2001-2002 Inventel Systemes
-+   Written 2001-2002 by
-+      David Libault  <david.libault@inventel.fr>
-+
-+   Copyright (C) 2002 Maxim Krasnyanskiy <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: sock.c,v 1.3 2002/07/10 22:59:52 maxk Exp $
-+ */ 
-+
-+#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 <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "bnep.h"
-+
-+#ifndef CONFIG_BLUEZ_BNEP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static inline struct socket *socki_lookup(struct inode *inode)
-+{
-+      return &inode->u.socket_i;
-+}
-+
-+static struct socket *sockfd_lookup(int fd, int *err)
-+{
-+      struct file *file;
-+      struct inode *inode;
-+      struct socket *sock;
-+
-+      if (!(file = fget(fd))) {
-+              *err = -EBADF;
-+              return NULL;
-+      }
-+
-+      inode = file->f_dentry->d_inode;
-+      if (!inode->i_sock || !(sock = socki_lookup(inode))) {
-+              *err = -ENOTSOCK;
-+              fput(file);
-+              return NULL;
-+      }
-+
-+      if (sock->file != file) {
-+              printk(KERN_ERR "socki_lookup: socket file changed!\n");
-+              sock->file = file;
-+      }
-+      return sock;
-+}
-+ 
-+static int bnep_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);
-+
-+      MOD_DEC_USE_COUNT;
-+      return 0;
-+}
-+
-+static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+      struct bnep_connlist_req cl;
-+      struct bnep_connadd_req  ca;
-+      struct bnep_conndel_req  cd;
-+      struct bnep_conninfo ci;
-+      struct socket *nsock;
-+      int err;
-+
-+      BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+      switch (cmd) {
-+      case BNEPCONNADD:
-+              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->state != BT_CONNECTED)
-+                      return -EBADFD;
-+
-+              err = bnep_add_connection(&ca, nsock);
-+              if (!err) {
-+                      if (copy_to_user((void *) arg, &ca, sizeof(ca)))
-+                              err = -EFAULT;
-+              } else
-+                      fput(nsock->file);
-+
-+              return err;
-+      
-+      case BNEPCONNDEL:
-+              if (!capable(CAP_NET_ADMIN))
-+                      return -EACCES;
-+
-+              if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
-+                      return -EFAULT;
-+      
-+              return bnep_del_connection(&cd);
-+
-+      case BNEPGETCONNLIST:
-+              if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
-+                      return -EFAULT;
-+
-+              if (cl.cnum <= 0)
-+                      return -EINVAL;
-+      
-+              err = bnep_get_connlist(&cl);
-+              if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
-+                      return -EFAULT;
-+
-+              return err;
-+
-+      case BNEPGETCONNINFO:
-+              if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
-+                      return -EFAULT;
-+
-+              err = bnep_get_conninfo(&ci);
-+              if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
-+                      return -EFAULT;
-+
-+              return err;
-+
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+static struct proto_ops bnep_sock_ops = {
-+      family:     PF_BLUETOOTH,
-+      release:    bnep_sock_release,
-+      ioctl:      bnep_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 bnep_sock_create(struct socket *sock, int protocol)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("sock %p", sock);
-+
-+      if (sock->type != SOCK_RAW)
-+              return -ESOCKTNOSUPPORT;
-+
-+      sock->ops = &bnep_sock_ops;
-+
-+      if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+              return -ENOMEM;
-+
-+      MOD_INC_USE_COUNT;
-+
-+      sock->state = SS_UNCONNECTED;
-+      sock_init_data(sock, sk);
-+
-+      sk->destruct = NULL;
-+      sk->protocol = protocol;
-+
-+      return 0;
-+}
-+
-+static struct net_proto_family bnep_sock_family_ops = {
-+      family: PF_BLUETOOTH,
-+      create: bnep_sock_create
-+};
-+
-+int bnep_sock_init(void)
-+{
-+      bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
-+      return 0;
-+}
-+
-+int bnep_sock_cleanup(void)
-+{
-+      if (bluez_sock_unregister(BTPROTO_BNEP))
-+              BT_ERR("Can't unregister BNEP socket");
-+      return 0;
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/capi.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,707 @@
-+/* 
-+   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/capi.h>
-+
-+#include "../drivers/isdn/avmb1/capilli.h"
-+#include "../drivers/isdn/avmb1/capicmd.h"
-+#include "../drivers/isdn/avmb1/capiutil.h"
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define REVISION "1.0"
-+
-+#define CAPI_INTEROPERABILITY         0x20
-+
-+#define CAPI_INTEROPERABILITY_REQ     CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
-+#define CAPI_INTEROPERABILITY_CONF    CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
-+#define CAPI_INTEROPERABILITY_IND     CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
-+#define CAPI_INTEROPERABILITY_RESP    CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
-+
-+#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_CONF_LEN        (CAPI_MSG_BASELEN + 4)
-+#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2)
-+#define CAPI_INTEROPERABILITY_RESP_LEN        (CAPI_MSG_BASELEN + 2)
-+
-+#define CAPI_FUNCTION_REGISTER                0
-+#define CAPI_FUNCTION_RELEASE         1
-+#define CAPI_FUNCTION_GET_PROFILE     2
-+#define CAPI_FUNCTION_GET_MANUFACTURER        3
-+#define CAPI_FUNCTION_GET_VERSION     4
-+#define CAPI_FUNCTION_GET_SERIAL_NUMBER       5
-+#define CAPI_FUNCTION_MANUFACTURER    6
-+#define CAPI_FUNCTION_LOOPBACK                7
-+
-+static struct capi_driver_interface *di;
-+
-+
-+#define CMTP_MSGNUM   1
-+#define CMTP_APPLID   2
-+#define CMTP_MAPPING  3
-+
-+static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
-+{
-+      struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
-+
-+      BT_DBG("session %p application %p appl %d", session, app, appl);
-+
-+      if (!app)
-+              return NULL;
-+
-+      memset(app, 0, sizeof(*app));
-+
-+      app->state = BT_OPEN;
-+      app->appl = appl;
-+
-+      list_add_tail(&app->list, &session->applications);
-+
-+      return app;
-+}
-+
-+static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
-+{
-+      BT_DBG("session %p application %p", session, app);
-+
-+      if (app) {
-+              list_del(&app->list);
-+              kfree(app);
-+      }
-+}
-+
-+static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
-+{
-+      struct cmtp_application *app;
-+      struct list_head *p, *n;
-+
-+      list_for_each_safe(p, n, &session->applications) {
-+              app = list_entry(p, struct cmtp_application, list);
-+              switch (pattern) {
-+              case CMTP_MSGNUM:
-+                      if (app->msgnum == value)
-+                              return app;
-+                      break;
-+              case CMTP_APPLID:
-+                      if (app->appl == value)
-+                              return app;
-+                      break;
-+              case CMTP_MAPPING:
-+                      if (app->mapping == value)
-+                              return app;
-+                      break;
-+              }
-+      }
-+
-+      return NULL;
-+}
-+
-+static int cmtp_msgnum_get(struct cmtp_session *session)
-+{
-+      session->msgnum++;
-+
-+      if ((session->msgnum & 0xff) > 200)
-+              session->msgnum = CMTP_INITIAL_MSGNUM + 1;
-+
-+      return session->msgnum;
-+}
-+
-+
-+static void cmtp_send_interopmsg(struct cmtp_session *session,
-+                                      __u8 subcmd, __u16 appl, __u16 msgnum,
-+                                      __u16 function, unsigned char *buf, int len)
-+{
-+      struct sk_buff *skb;
-+      unsigned char *s;
-+
-+      BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
-+
-+      if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
-+              BT_ERR("Can't allocate memory for interoperability packet");
-+              return;
-+      }
-+
-+      s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
-+
-+      capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
-+      capimsg_setu16(s, 2, appl);
-+      capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
-+      capimsg_setu8 (s, 5, subcmd);
-+      capimsg_setu16(s, 6, msgnum);
-+
-+      /* Interoperability selector (Bluetooth Device Management) */
-+      capimsg_setu16(s, 8, 0x0001);
-+
-+      capimsg_setu8 (s, 10, 3 + len);
-+      capimsg_setu16(s, 11, function);
-+      capimsg_setu8 (s, 13, len);
-+
-+      if (len > 0)
-+              memcpy(s + 14, buf, len);
-+
-+      cmtp_send_capimsg(session, skb);
-+}
-+
-+static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+      struct capi_ctr *ctrl = session->ctrl;
-+      struct cmtp_application *application;
-+      __u16 appl, msgnum, func, info;
-+      __u32 controller;
-+
-+      BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+      switch (CAPIMSG_SUBCOMMAND(skb->data)) {
-+      case CAPI_CONF:
-+              func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
-+              info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
-+
-+              switch (func) {
-+              case CAPI_FUNCTION_REGISTER:
-+                      msgnum = CAPIMSG_MSGID(skb->data);
-+
-+                      application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
-+                      if (application) {
-+                              application->state = BT_CONNECTED;
-+                              application->msgnum = 0;
-+                              application->mapping = CAPIMSG_APPID(skb->data);
-+                              wake_up_interruptible(&session->wait);
-+                      }
-+
-+                      break;
-+
-+              case CAPI_FUNCTION_RELEASE:
-+                      appl = CAPIMSG_APPID(skb->data);
-+
-+                      application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+                      if (application) {
-+                              application->state = BT_CLOSED;
-+                              application->msgnum = 0;
-+                              wake_up_interruptible(&session->wait);
-+                      }
-+
-+                      break;
-+
-+              case CAPI_FUNCTION_GET_PROFILE:
-+                      controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
-+                      msgnum = CAPIMSG_MSGID(skb->data);
-+
-+                      if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
-+                              session->ncontroller = controller;
-+                              wake_up_interruptible(&session->wait);
-+                              break;
-+                      }
-+
-+                      if (!info && ctrl) {
-+                              memcpy(&ctrl->profile,
-+                                      skb->data + CAPI_MSG_BASELEN + 11,
-+                                      sizeof(capi_profile));
-+                              session->state = BT_CONNECTED;
-+                              ctrl->ready(ctrl);
-+                      }
-+
-+                      break;
-+
-+              case CAPI_FUNCTION_GET_MANUFACTURER:
-+                      controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
-+
-+                      if (!info && ctrl) {
-+                              strncpy(ctrl->manu,
-+                                      skb->data + CAPI_MSG_BASELEN + 15,
-+                                      skb->data[CAPI_MSG_BASELEN + 14]);
-+                      }
-+
-+                      break;
-+
-+              case CAPI_FUNCTION_GET_VERSION:
-+                      controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+                      if (!info && ctrl) {
-+                              ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
-+                              ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
-+                              ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
-+                              ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
-+                      }
-+
-+                      break;
-+
-+              case CAPI_FUNCTION_GET_SERIAL_NUMBER:
-+                      controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
-+
-+                      if (!info && ctrl) {
-+                              memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
-+                              strncpy(ctrl->serial,
-+                                      skb->data + CAPI_MSG_BASELEN + 17,
-+                                      skb->data[CAPI_MSG_BASELEN + 16]);
-+                      }
-+
-+                      break;
-+              }
-+
-+              break;
-+
-+      case CAPI_IND:
-+              func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
-+
-+              if (func == CAPI_FUNCTION_LOOPBACK) {
-+                      appl = CAPIMSG_APPID(skb->data);
-+                      msgnum = CAPIMSG_MSGID(skb->data);
-+                      cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
-+                                              skb->data + CAPI_MSG_BASELEN + 6,
-+                                              skb->data[CAPI_MSG_BASELEN + 5]);
-+              }
-+
-+              break;
-+      }
-+
-+      kfree_skb(skb);
-+}
-+
-+void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+      struct capi_ctr *ctrl = session->ctrl;
-+      struct cmtp_application *application;
-+      __u16 cmd, appl, info;
-+      __u32 ncci, contr;
-+
-+      BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+      if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
-+              cmtp_recv_interopmsg(session, skb);
-+              return;
-+      }
-+
-+      if (session->flags & (1 << CMTP_LOOPBACK)) {
-+              kfree_skb(skb);
-+              return;
-+      }
-+
-+      cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
-+      appl = CAPIMSG_APPID(skb->data);
-+      contr = CAPIMSG_CONTROL(skb->data);
-+
-+      application = cmtp_application_get(session, CMTP_MAPPING, appl);
-+      if (application) {
-+              appl = application->appl;
-+              CAPIMSG_SETAPPID(skb->data, appl);
-+      } else {
-+              BT_ERR("Can't find application with id %d", appl);
-+              kfree_skb(skb);
-+              return;
-+      }
-+
-+      if ((contr & 0x7f) == 0x01) {
-+              contr = (contr & 0xffffff80) | session->num;
-+              CAPIMSG_SETCONTROL(skb->data, contr);
-+      }
-+
-+      if (!ctrl) {
-+              BT_ERR("Can't find controller %d for message", session->num);
-+              kfree_skb(skb);
-+              return;
-+      }
-+
-+      switch (cmd) {
-+      case CAPI_CONNECT_B3_CONF:
-+              ncci = CAPIMSG_NCCI(skb->data);
-+              info = CAPIMSG_U16(skb->data, 12);
-+
-+              BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
-+
-+              if (info == 0)
-+                      ctrl->new_ncci(ctrl, appl, ncci, 8);
-+
-+              ctrl->handle_capimsg(ctrl, appl, skb);
-+              break;
-+
-+      case CAPI_CONNECT_B3_IND:
-+              ncci = CAPIMSG_NCCI(skb->data);
-+
-+              BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+              ctrl->new_ncci(ctrl, appl, ncci, 8);
-+              ctrl->handle_capimsg(ctrl, appl, skb);
-+              break;
-+
-+      case CAPI_DISCONNECT_B3_IND:
-+              ncci = CAPIMSG_NCCI(skb->data);
-+
-+              BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
-+
-+              if (ncci == 0xffffffff)
-+                      BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
-+
-+              ctrl->handle_capimsg(ctrl, appl, skb);
-+              ctrl->free_ncci(ctrl, appl, ncci);
-+              break;
-+
-+      default:
-+              ctrl->handle_capimsg(ctrl, appl, skb);
-+              break;
-+      }
-+}
-+
-+void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+      struct cmtp_scb *scb = (void *) skb->cb;
-+
-+      BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+      scb->id = -1;
-+      scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
-+
-+      skb_queue_tail(&session->transmit, skb);
-+
-+      cmtp_schedule(session);
-+}
-+
-+
-+static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
-+{
-+      BT_DBG("ctrl %p data %p", ctrl, data);
-+
-+      return -EIO;
-+}
-+
-+static void cmtp_reset_ctr(struct capi_ctr *ctrl)
-+{
-+      BT_DBG("ctrl %p", ctrl);
-+
-+      ctrl->reseted(ctrl);
-+}
-+
-+static void cmtp_remove_ctr(struct capi_ctr *ctrl)
-+{
-+      struct cmtp_session *session = ctrl->driverdata;
-+
-+      BT_DBG("ctrl %p", ctrl);
-+
-+      ctrl->suspend_output(ctrl);
-+
-+      atomic_inc(&session->terminate);
-+      cmtp_schedule(session);
-+}
-+
-+static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct cmtp_session *session = ctrl->driverdata;
-+      struct cmtp_application *application;
-+      unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+      unsigned char buf[8];
-+      int err = 0, nconn, want = rp->level3cnt;
-+
-+      BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
-+              ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
-+
-+      application = cmtp_application_add(session, appl);
-+      if (!application) {
-+              BT_ERR("Can't allocate memory for new application");
-+              ctrl->appl_released(ctrl, appl);
-+              return;
-+      }
-+
-+      if (want < 0)
-+              nconn = ctrl->profile.nbchannel * -want;
-+      else
-+              nconn = want;
-+
-+      if (nconn == 0)
-+              nconn = ctrl->profile.nbchannel;
-+
-+      capimsg_setu16(buf, 0, nconn);
-+      capimsg_setu16(buf, 2, rp->datablkcnt);
-+      capimsg_setu16(buf, 4, rp->datablklen);
-+
-+      application->state = BT_CONFIG;
-+      application->msgnum = cmtp_msgnum_get(session);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
-+                              CAPI_FUNCTION_REGISTER, buf, 6);
-+
-+      add_wait_queue(&session->wait, &wait);
-+      while (1) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (!timeo) {
-+                      err = -EAGAIN;
-+                      break;
-+              }
-+
-+              if (application->state == BT_CLOSED) {
-+                      err = -application->err;
-+                      break;
-+              }
-+
-+              if (application->state == BT_CONNECTED)
-+                      break;
-+
-+              if (signal_pending(current)) {
-+                      err = -EINTR;
-+                      break;
-+              }
-+
-+              timeo = schedule_timeout(timeo);
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(&session->wait, &wait);
-+
-+      if (err) {
-+              ctrl->appl_released(ctrl, appl);
-+              cmtp_application_del(session, application);
-+              return;
-+      }
-+
-+      ctrl->appl_registered(ctrl, appl);
-+}
-+
-+static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct cmtp_session *session = ctrl->driverdata;
-+      struct cmtp_application *application;
-+      unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+
-+      BT_DBG("ctrl %p appl %d", ctrl, appl);
-+
-+      application = cmtp_application_get(session, CMTP_APPLID, appl);
-+      if (!application) {
-+              BT_ERR("Can't find application");
-+              return;
-+      }
-+
-+      application->msgnum = cmtp_msgnum_get(session);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
-+                              CAPI_FUNCTION_RELEASE, NULL, 0);
-+
-+      add_wait_queue(&session->wait, &wait);
-+      while (timeo) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (application->state == BT_CLOSED)
-+                      break;
-+
-+              if (signal_pending(current))
-+                      break;
-+
-+              timeo = schedule_timeout(timeo);
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(&session->wait, &wait);
-+
-+      cmtp_application_del(session, application);
-+      ctrl->appl_released(ctrl, appl);
-+}
-+
-+static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
-+{
-+      struct cmtp_session *session = ctrl->driverdata;
-+      struct cmtp_application *application;
-+      __u16 appl;
-+      __u32 contr;
-+
-+      BT_DBG("ctrl %p skb %p", ctrl, skb);
-+
-+      appl = CAPIMSG_APPID(skb->data);
-+      contr = CAPIMSG_CONTROL(skb->data);
-+
-+      application = cmtp_application_get(session, CMTP_APPLID, appl);
-+      if ((!application) || (application->state != BT_CONNECTED)) {
-+              BT_ERR("Can't find application with id %d", appl);
-+              kfree_skb(skb);
-+              return;
-+      }
-+
-+      CAPIMSG_SETAPPID(skb->data, application->mapping);
-+
-+      if ((contr & 0x7f) == session->num) {
-+              contr = (contr & 0xffffff80) | 0x01;
-+              CAPIMSG_SETCONTROL(skb->data, contr);
-+      }
-+
-+      cmtp_send_capimsg(session, skb);
-+}
-+
-+static char *cmtp_procinfo(struct capi_ctr *ctrl)
-+{
-+      return "CAPI Message Transport Protocol";
-+}
-+
-+static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
-+{
-+      struct cmtp_session *session = ctrl->driverdata;
-+      struct cmtp_application *app;
-+      struct list_head *p, *n;
-+      int len = 0;
-+
-+      len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
-+      len += sprintf(page + len, "addr %s\n", session->name);
-+      len += sprintf(page + len, "ctrl %d\n", session->num);
-+
-+      list_for_each_safe(p, n, &session->applications) {
-+              app = list_entry(p, struct cmtp_application, list);
-+              len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
-+      }
-+
-+      if (off + count >= len)
-+              *eof = 1;
-+
-+      if (len < off)
-+              return 0;
-+
-+      *start = page + off;
-+
-+      return ((count < len - off) ? count : len - off);
-+}
-+
-+static struct capi_driver cmtp_driver = {
-+      name:           "cmtp",
-+      revision:       REVISION,
-+      load_firmware:  cmtp_load_firmware,
-+      reset_ctr:      cmtp_reset_ctr,
-+      remove_ctr:     cmtp_remove_ctr,
-+      register_appl:  cmtp_register_appl,
-+      release_appl:   cmtp_release_appl,
-+      send_message:   cmtp_send_message,
-+      procinfo:       cmtp_procinfo,
-+      ctr_read_proc:  cmtp_ctr_read_proc,
-+
-+      driver_read_proc:       0,
-+      add_card:               0,
-+};
-+
-+
-+int cmtp_attach_device(struct cmtp_session *session)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      unsigned long timeo = CMTP_INTEROP_TIMEOUT;
-+      unsigned char buf[4];
-+
-+      BT_DBG("session %p", session);
-+
-+      capimsg_setu32(buf, 0, 0);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
-+                              CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+      add_wait_queue(&session->wait, &wait);
-+      while (timeo) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (session->ncontroller)
-+                      break;
-+
-+              if (signal_pending(current))
-+                      break;
-+
-+              timeo = schedule_timeout(timeo);
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(&session->wait, &wait);
-+
-+      BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
-+
-+      if (!timeo)
-+              return -ETIMEDOUT;
-+
-+      if (!session->ncontroller)
-+              return -ENODEV;
-+
-+
-+      if (session->ncontroller > 1)
-+              BT_INFO("Setting up only CAPI controller 1");
-+
-+      if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
-+              BT_ERR("Can't attach new controller");
-+              return -EBUSY;
-+      }
-+
-+      session->num = session->ctrl->cnr;
-+
-+      BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
-+
-+      capimsg_setu32(buf, 0, 1);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+                              CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+                              CAPI_FUNCTION_GET_VERSION, buf, 4);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+                              CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
-+
-+      cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
-+                              CAPI_FUNCTION_GET_PROFILE, buf, 4);
-+
-+      return 0;
-+}
-+
-+void cmtp_detach_device(struct cmtp_session *session)
-+{
-+      struct capi_ctr *ctrl = session->ctrl;
-+
-+      BT_DBG("session %p ctrl %p", session, ctrl);
-+
-+      if (!ctrl)
-+              return;
-+
-+      ctrl->reseted(ctrl);
-+
-+      di->detach_ctr(ctrl);
-+}
-+
-+int cmtp_init_capi(void)
-+{
-+      if (!(di = attach_capi_driver(&cmtp_driver))) {
-+              BT_ERR("Can't attach CAPI driver");
-+              return -EIO;
-+      }
-+
-+      return 0;
-+}
-+
-+void cmtp_cleanup_capi(void)
-+{
-+      detach_capi_driver(&cmtp_driver);
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/cmtp.h    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,138 @@
-+/* 
-+   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->sleep);
-+}
-+
-+/* CMTP init defines */
-+int cmtp_init_capi(void);
-+int cmtp_init_sockets(void);
-+void cmtp_cleanup_capi(void);
-+void cmtp_cleanup_sockets(void);
-+
-+#endif /* __CMTP_H */
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/Config.in 2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,7 @@
-+#
-+# Bluetooth CMTP layer configuration
-+#
-+
-+if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then 
-+   dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
-+fi
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/core.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,515 @@
-+/* 
-+   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 <linux/init.h>
-+#include <net/sock.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define VERSION "1.0"
-+
-+static DECLARE_RWSEM(cmtp_session_sem);
-+static LIST_HEAD(cmtp_session_list);
-+
-+static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
-+{
-+      struct cmtp_session *session;
-+      struct list_head *p;
-+
-+      BT_DBG("");
-+
-+      list_for_each(p, &cmtp_session_list) {
-+              session = list_entry(p, struct cmtp_session, list);
-+              if (!bacmp(bdaddr, &session->bdaddr))
-+                      return session;
-+      }
-+      return NULL;
-+}
-+
-+static void __cmtp_link_session(struct cmtp_session *session)
-+{
-+      MOD_INC_USE_COUNT;
-+      list_add(&session->list, &cmtp_session_list);
-+}
-+
-+static void __cmtp_unlink_session(struct cmtp_session *session)
-+{
-+      list_del(&session->list);
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
-+{
-+      bacpy(&ci->bdaddr, &session->bdaddr);
-+
-+      ci->flags = session->flags;
-+      ci->state = session->state;
-+
-+      ci->num = session->num;
-+}
-+
-+
-+static inline int cmtp_alloc_block_id(struct cmtp_session *session)
-+{
-+      int i, id = -1;
-+
-+      for (i = 0; i < 16; i++)
-+              if (!test_and_set_bit(i, &session->blockids)) {
-+                      id = i;
-+                      break;
-+              }
-+
-+      return id;
-+}
-+
-+static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
-+{
-+      clear_bit(id, &session->blockids);
-+}
-+
-+static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
-+{
-+      struct sk_buff *skb = session->reassembly[id], *nskb;
-+      int size;
-+
-+      BT_DBG("session %p buf %p count %d", session, buf, count);
-+
-+      size = (skb) ? skb->len + count : count;
-+
-+      if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
-+              BT_ERR("Can't allocate memory for CAPI message");
-+              return;
-+      }
-+
-+      if (skb && (skb->len > 0))
-+              memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
-+
-+      memcpy(skb_put(nskb, count), buf, count);
-+
-+      session->reassembly[id] = nskb;
-+
-+      if (skb)
-+              kfree_skb(skb);
-+}
-+
-+static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
-+{
-+      __u8 hdr, hdrlen, id;
-+      __u16 len;
-+
-+      BT_DBG("session %p skb %p len %d", session, skb, skb->len);
-+
-+      while (skb->len > 0) {
-+              hdr = skb->data[0];
-+
-+              switch (hdr & 0xc0) {
-+              case 0x40:
-+                      hdrlen = 2;
-+                      len = skb->data[1];
-+                      break;
-+              case 0x80:
-+                      hdrlen = 3;
-+                      len = skb->data[1] | (skb->data[2] << 8);
-+                      break;
-+              default:
-+                      hdrlen = 1;
-+                      len = 0;
-+                      break;
-+              }
-+
-+              id = (hdr & 0x3c) >> 2;
-+
-+              BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
-+
-+              if (hdrlen + len > skb->len) {
-+                      BT_ERR("Wrong size or header information in CMTP frame");
-+                      break;
-+              }
-+
-+              if (len == 0) {
-+                      skb_pull(skb, hdrlen);
-+                      continue;
-+              }
-+
-+              switch (hdr & 0x03) {
-+              case 0x00:
-+                      cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+                      cmtp_recv_capimsg(session, session->reassembly[id]);
-+                      session->reassembly[id] = NULL;
-+                      break;
-+              case 0x01:
-+                      cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
-+                      break;
-+              default:
-+                      if (session->reassembly[id] != NULL)
-+                              kfree_skb(session->reassembly[id]);
-+                      session->reassembly[id] = NULL;
-+                      break;
-+              }
-+
-+              skb_pull(skb, hdrlen + len);
-+      }
-+
-+      kfree_skb(skb);
-+      return 0;
-+}
-+
-+static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
-+{
-+      struct socket *sock = session->sock;
-+      struct iovec iv = { data, len };
-+      struct msghdr msg;
-+      int err;
-+
-+      BT_DBG("session %p data %p len %d", session, data, len);
-+
-+      if (!len)
-+              return 0;
-+
-+      memset(&msg, 0, sizeof(msg));
-+      msg.msg_iovlen = 1;
-+      msg.msg_iov = &iv;
-+
-+      err = sock->ops->sendmsg(sock, &msg, len, 0);
-+      return err;
-+}
-+
-+static int cmtp_process_transmit(struct cmtp_session *session)
-+{
-+      struct sk_buff *skb, *nskb;
-+      unsigned char *hdr;
-+      unsigned int size, tail;
-+
-+      BT_DBG("session %p", session);
-+
-+      if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
-+              BT_ERR("Can't allocate memory for new frame");
-+              return -ENOMEM;
-+      }
-+
-+      while ((skb = skb_dequeue(&session->transmit))) {
-+              struct cmtp_scb *scb = (void *) skb->cb;
-+
-+              if ((tail = (session->mtu - nskb->len)) < 5) {
-+                      cmtp_send_frame(session, nskb->data, nskb->len);
-+                      skb_trim(nskb, 0);
-+                      tail = session->mtu;
-+              }
-+
-+              size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
-+
-+              if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
-+                      skb_queue_head(&session->transmit, skb);
-+                      break;
-+              }
-+
-+              if (size < 256) {
-+                      hdr = skb_put(nskb, 2);
-+                      hdr[0] = 0x40
-+                              | ((scb->id << 2) & 0x3c)
-+                              | ((skb->len == size) ? 0x00 : 0x01);
-+                      hdr[1] = size;
-+              } else {
-+                      hdr = skb_put(nskb, 3);
-+                      hdr[0] = 0x80
-+                              | ((scb->id << 2) & 0x3c)
-+                              | ((skb->len == size) ? 0x00 : 0x01);
-+                      hdr[1] = size & 0xff;
-+                      hdr[2] = size >> 8;
-+              }
-+
-+              memcpy(skb_put(nskb, size), skb->data, size);
-+              skb_pull(skb, size);
-+
-+              if (skb->len > 0) {
-+                      skb_queue_head(&session->transmit, skb);
-+              } else {
-+                      cmtp_free_block_id(session, scb->id);
-+                      if (scb->data) {
-+                              cmtp_send_frame(session, nskb->data, nskb->len);
-+                              skb_trim(nskb, 0);
-+                      }
-+                      kfree_skb(skb);
-+              }
-+      }
-+
-+      cmtp_send_frame(session, nskb->data, nskb->len);
-+
-+      kfree_skb(nskb);
-+
-+      return skb_queue_len(&session->transmit);
-+}
-+
-+static int cmtp_session(void *arg)
-+{
-+      struct cmtp_session *session = arg;
-+      struct sock *sk = session->sock->sk;
-+      struct sk_buff *skb;
-+      wait_queue_t wait;
-+
-+      BT_DBG("session %p", session);
-+
-+      daemonize(); reparent_to_init();
-+
-+      sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
-+
-+      sigfillset(&current->blocked);
-+      flush_signals(current);
-+
-+      current->nice = -15;
-+
-+      set_fs(KERNEL_DS);
-+
-+      init_waitqueue_entry(&wait, current);
-+      add_wait_queue(sk->sleep, &wait);
-+      while (!atomic_read(&session->terminate)) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (sk->state != BT_CONNECTED)
-+                      break;
-+
-+              while ((skb = skb_dequeue(&sk->receive_queue))) {
-+                      skb_orphan(skb);
-+                      cmtp_recv_frame(session, skb);
-+              }
-+
-+              cmtp_process_transmit(session);
-+
-+              schedule();
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+
-+      down_write(&cmtp_session_sem);
-+
-+      if (!(session->flags & (1 << CMTP_LOOPBACK)))
-+              cmtp_detach_device(session);
-+
-+      fput(session->sock->file);
-+
-+      __cmtp_unlink_session(session);
-+
-+      up_write(&cmtp_session_sem);
-+
-+      kfree(session);
-+      return 0;
-+}
-+
-+int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
-+{
-+      struct cmtp_session *session, *s;
-+      bdaddr_t src, dst;
-+      int i, err;
-+
-+      BT_DBG("");
-+
-+      baswap(&src, &bluez_pi(sock->sk)->src);
-+      baswap(&dst, &bluez_pi(sock->sk)->dst);
-+
-+      session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
-+      if (!session) 
-+              return -ENOMEM;
-+      memset(session, 0, sizeof(struct cmtp_session));
-+
-+      down_write(&cmtp_session_sem);
-+
-+      s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
-+      if (s && s->state == BT_CONNECTED) {
-+              err = -EEXIST;
-+              goto failed;
-+      }
-+
-+      bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
-+
-+      session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
-+
-+      BT_DBG("mtu %d", session->mtu);
-+
-+      sprintf(session->name, "%s", batostr(&dst));
-+
-+      session->sock  = sock;
-+      session->state = BT_CONFIG;
-+
-+      init_waitqueue_head(&session->wait);
-+
-+      session->ctrl   = NULL;
-+      session->msgnum = CMTP_INITIAL_MSGNUM;
-+
-+      INIT_LIST_HEAD(&session->applications);
-+
-+      skb_queue_head_init(&session->transmit);
-+
-+      for (i = 0; i < 16; i++)
-+              session->reassembly[i] = NULL;
-+
-+      session->flags = req->flags;
-+
-+      __cmtp_link_session(session);
-+
-+      err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+      if (err < 0)
-+              goto unlink;
-+
-+      if (!(session->flags & (1 << CMTP_LOOPBACK))) {
-+              err = cmtp_attach_device(session);
-+              if (err < 0)
-+                      goto detach;
-+      }
-+
-+      up_write(&cmtp_session_sem);
-+      return 0;
-+
-+detach:
-+      cmtp_detach_device(session);
-+
-+unlink:
-+      __cmtp_unlink_session(session);
-+
-+failed:
-+      up_write(&cmtp_session_sem);
-+      kfree(session);
-+      return err;
-+}
-+
-+int cmtp_del_connection(struct cmtp_conndel_req *req)
-+{
-+      struct cmtp_session *session;
-+      int err = 0;
-+
-+      BT_DBG("");
-+
-+      down_read(&cmtp_session_sem);
-+
-+      session = __cmtp_get_session(&req->bdaddr);
-+      if (session) {
-+              /* Flush the transmit queue */
-+              skb_queue_purge(&session->transmit);
-+
-+              /* Kill session thread */
-+              atomic_inc(&session->terminate);
-+              cmtp_schedule(session);
-+      } else
-+              err = -ENOENT;
-+
-+      up_read(&cmtp_session_sem);
-+      return err;
-+}
-+
-+int cmtp_get_connlist(struct cmtp_connlist_req *req)
-+{
-+      struct list_head *p;
-+      int err = 0, n = 0;
-+
-+      BT_DBG("");
-+
-+      down_read(&cmtp_session_sem);
-+
-+      list_for_each(p, &cmtp_session_list) {
-+              struct cmtp_session *session;
-+              struct cmtp_conninfo ci;
-+
-+              session = list_entry(p, struct cmtp_session, list);
-+
-+              __cmtp_copy_session(session, &ci);
-+
-+              if (copy_to_user(req->ci, &ci, sizeof(ci))) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-+
-+              if (++n >= req->cnum)
-+                      break;
-+
-+              req->ci++;
-+      }
-+      req->cnum = n;
-+
-+      up_read(&cmtp_session_sem);
-+      return err;
-+}
-+
-+int cmtp_get_conninfo(struct cmtp_conninfo *ci)
-+{
-+      struct cmtp_session *session;
-+      int err = 0;
-+
-+      down_read(&cmtp_session_sem);
-+
-+      session = __cmtp_get_session(&ci->bdaddr);
-+      if (session)
-+              __cmtp_copy_session(session, ci);
-+      else
-+              err = -ENOENT;
-+
-+      up_read(&cmtp_session_sem);
-+      return err;
-+}
-+
-+
-+int __init init_cmtp(void)
-+{
-+      l2cap_load();
-+
-+      cmtp_init_capi();
-+      cmtp_init_sockets();
-+
-+      BT_INFO("BlueZ CMTP ver %s", VERSION);
-+      BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
-+
-+      return 0;
-+}
-+
-+void __exit exit_cmtp(void)
-+{
-+      cmtp_cleanup_sockets();
-+      cmtp_cleanup_capi();
-+}
-+
-+module_init(init_cmtp);
-+module_exit(exit_cmtp);
-+
-+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/Makefile  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the Linux Bluetooth CMTP layer
-+#
-+
-+O_TARGET := cmtp.o
-+
-+obj-y := core.o sock.o capi.o
-+obj-m += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/cmtp/sock.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,236 @@
-+/* 
-+   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 <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include "cmtp.h"
-+
-+#ifndef CONFIG_BLUEZ_CMTP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static inline struct socket *socki_lookup(struct inode *inode)
-+{
-+      return &inode->u.socket_i;
-+}
-+
-+static struct socket *sockfd_lookup(int fd, int *err)
-+{
-+      struct file *file;
-+      struct inode *inode;
-+      struct socket *sock;
-+
-+      if (!(file = fget(fd))) {
-+              *err = -EBADF;
-+              return NULL;
-+      }
-+
-+      inode = file->f_dentry->d_inode;
-+      if (!inode->i_sock || !(sock = socki_lookup(inode))) {
-+              *err = -ENOTSOCK;
-+              fput(file);
-+              return NULL;
-+      }
-+
-+      if (sock->file != file) {
-+              printk(KERN_ERR "socki_lookup: socket file changed!\n");
-+              sock->file = file;
-+      }
-+      return sock;
-+}
-+
-+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);
-+
-+      MOD_DEC_USE_COUNT;
-+      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->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,
-+      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;
-+
-+      sock->ops = &cmtp_sock_ops;
-+
-+      if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
-+              return -ENOMEM;
-+
-+      MOD_INC_USE_COUNT;
-+
-+      sock->state = SS_UNCONNECTED;
-+      sock_init_data(sock, sk);
-+
-+      sk->destruct = NULL;
-+      sk->protocol = protocol;
-+
-+      return 0;
-+}
-+
-+static struct net_proto_family cmtp_sock_family_ops = {
-+      family:         PF_BLUETOOTH,
-+      create:         cmtp_sock_create
-+};
-+
-+int cmtp_init_sockets(void)
-+{
-+      int err;
-+
-+      if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
-+              BT_ERR("Can't register CMTP socket layer (%d)", err);
-+              return err;
-+      }
-+
-+      return 0;
-+}
-+
-+void cmtp_cleanup_sockets(void)
-+{
-+      int err;
-+
-+      if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
-+              BT_ERR("Can't unregister CMTP socket layer (%d)", err);
-+
-+      return;
-+}
---- linux/net/bluetooth/Config.in~bluetooth-2.4.18-mh11        2001-06-12 04:15:27.000000000 +0200
-+++ linux/net/bluetooth/Config.in      2004-01-25 23:37:39.000000000 +0100
-@@ -1,16 +1,22 @@
- #
--# Bluetooth configuration
-+# Bluetooth subsystem configuration
- #
- if [ "$CONFIG_NET" != "n" ]; then
-+
-    mainmenu_option next_comment
-    comment 'Bluetooth support'
-    dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
-    if [ "$CONFIG_BLUEZ" != "n" ]; then
-       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
-+      dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
-+      source net/bluetooth/rfcomm/Config.in
-+      source net/bluetooth/bnep/Config.in
-+      source net/bluetooth/cmtp/Config.in
-       source drivers/bluetooth/Config.in
-    fi
-+
-    endmenu
- fi
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/hci_conn.c     2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,435 @@
-+/* 
-+   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.
-+*/
-+
-+/*
-+ * HCI Connection handling.
-+ *
-+ * $Id: hci_conn.c,v 1.5 2002/07/17 18:46:25 maxk Exp $
-+ */
-+
-+#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/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+void hci_acl_connect(struct hci_conn *conn)
-+{
-+      struct hci_dev *hdev = conn->hdev;
-+      struct inquiry_entry *ie;
-+      create_conn_cp cp;
-+
-+      BT_DBG("%p", conn);
-+
-+      conn->state = BT_CONNECT;
-+      conn->out   = 1;
-+      conn->link_mode = HCI_LM_MASTER;
-+
-+      memset(&cp, 0, sizeof(cp));
-+      bacpy(&cp.bdaddr, &conn->dst);
-+      cp.pscan_rep_mode = 0x02;
-+
-+      if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
-+                      inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
-+              cp.pscan_rep_mode = ie->info.pscan_rep_mode;
-+              cp.pscan_mode     = ie->info.pscan_mode;
-+              cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
-+      }
-+
-+      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;
-+      else
-+              cp.role_switch  = 0x00;
-+              
-+      hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
-+                              CREATE_CONN_CP_SIZE, &cp);
-+}
-+
-+void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
-+{
-+      disconnect_cp cp;
-+
-+      BT_DBG("%p", conn);
-+
-+      conn->state = BT_DISCONN;
-+
-+      cp.handle = __cpu_to_le16(conn->handle);
-+      cp.reason = reason;
-+      hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
-+                              DISCONNECT_CP_SIZE, &cp);
-+}
-+
-+void hci_add_sco(struct hci_conn *conn, __u16 handle)
-+{
-+      struct hci_dev *hdev = conn->hdev;
-+      add_sco_cp cp;
-+
-+      BT_DBG("%p", conn);
-+
-+      conn->state = BT_CONNECT;
-+      conn->out = 1;
-+
-+      cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
-+      cp.handle   = __cpu_to_le16(handle);
-+
-+      hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
-+}
-+
-+static void hci_conn_timeout(unsigned long arg)
-+{
-+      struct hci_conn *conn = (void *)arg;
-+      struct hci_dev  *hdev = conn->hdev;
-+
-+      BT_DBG("conn %p state %d", conn, conn->state);
-+
-+      if (atomic_read(&conn->refcnt))
-+              return;
-+
-+      hci_dev_lock(hdev);
-+      if (conn->state == BT_CONNECTED)
-+              hci_acl_disconn(conn, 0x13);
-+      else
-+              conn->state = BT_CLOSED;
-+      hci_dev_unlock(hdev);
-+      return;
-+}
-+
-+static void hci_conn_init_timer(struct hci_conn *conn)
-+{
-+      init_timer(&conn->timer);
-+      conn->timer.function = hci_conn_timeout;
-+      conn->timer.data = (unsigned long)conn;
-+}
-+
-+struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+      struct hci_conn *conn;
-+
-+      BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+      if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
-+              return NULL;
-+      memset(conn, 0, sizeof(struct hci_conn));
-+
-+      bacpy(&conn->dst, dst);
-+      conn->type   = type;
-+      conn->hdev   = hdev;
-+      conn->state  = BT_OPEN;
-+
-+      skb_queue_head_init(&conn->data_q);
-+      hci_conn_init_timer(conn);
-+
-+      atomic_set(&conn->refcnt, 0);
-+
-+      hci_dev_hold(hdev);
-+
-+      tasklet_disable(&hdev->tx_task);
-+      conn_hash_add(hdev, conn);
-+      tasklet_enable(&hdev->tx_task);
-+
-+      return conn;
-+}
-+
-+int hci_conn_del(struct hci_conn *conn)
-+{
-+      struct hci_dev  *hdev = conn->hdev;
-+
-+      BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
-+      
-+      hci_conn_del_timer(conn);
-+
-+      if (conn->type == SCO_LINK) {
-+              struct hci_conn *acl = conn->link;
-+              if (acl) {
-+                      acl->link = NULL;
-+                      hci_conn_put(acl);
-+              }
-+      } else {
-+              struct hci_conn *sco = conn->link;
-+              if (sco)
-+                      sco->link = NULL;
-+
-+              /* Unacked frames */
-+              hdev->acl_cnt += conn->sent;
-+      }
-+
-+      tasklet_disable(&hdev->tx_task);
-+      conn_hash_del(hdev, conn);
-+      tasklet_enable(&hdev->tx_task);
-+
-+      skb_queue_purge(&conn->data_q);
-+
-+      hci_dev_put(hdev);
-+
-+      kfree(conn);
-+      return 0;
-+}
-+
-+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
-+{
-+      int use_src = bacmp(src, BDADDR_ANY);
-+      struct hci_dev *hdev = NULL;
-+      struct list_head *p;
-+
-+      BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+      read_lock_bh(&hdev_list_lock);
-+
-+      list_for_each(p, &hdev_list) {
-+              struct hci_dev *d;
-+              d = list_entry(p, struct hci_dev, list);
-+              
-+              if (!test_bit(HCI_UP, &d->flags))
-+                      continue;
-+
-+              /* Simple routing: 
-+               *      No source address - find interface with bdaddr != dst 
-+               *      Source address    - find interface with bdaddr == src 
-+               */
-+
-+              if (use_src) {
-+                      if (!bacmp(&d->bdaddr, src)) {
-+                              hdev = d; break;
-+                      }
-+              } else {
-+                      if (bacmp(&d->bdaddr, dst)) {
-+                              hdev = d; break;
-+                      }
-+              }
-+      }
-+
-+      if (hdev)
-+              hci_dev_hold(hdev);
-+
-+      read_unlock_bh(&hdev_list_lock);
-+      return hdev;
-+}
-+
-+/* Create SCO or ACL connection.
-+ * Device _must_ be locked */
-+struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
-+{
-+      struct hci_conn *acl;
-+
-+      BT_DBG("%s dst %s", hdev->name, batostr(dst));
-+
-+      if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
-+              if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
-+                      return NULL;
-+      }
-+
-+      hci_conn_hold(acl);
-+
-+      if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
-+              hci_acl_connect(acl);
-+
-+      if (type == SCO_LINK) {
-+              struct hci_conn *sco;
-+
-+              if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
-+                      if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
-+                              hci_conn_put(acl);
-+                              return NULL;
-+                      }
-+              }
-+              acl->link = sco;
-+              sco->link = acl;
-+
-+              hci_conn_hold(sco);
-+
-+              if (acl->state == BT_CONNECTED && 
-+                              (sco->state == BT_OPEN || sco->state == BT_CLOSED))
-+                      hci_add_sco(sco, acl->handle);
-+
-+              return sco;
-+      } else {
-+              return acl;
-+      }
-+}
-+
-+/* Authenticate remote device */
-+int hci_conn_auth(struct hci_conn *conn)
-+{
-+      BT_DBG("conn %p", conn);
-+      
-+      if (conn->link_mode & HCI_LM_AUTH)
-+              return 1;
-+      
-+      if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
-+              auth_requested_cp ar;
-+              ar.handle = __cpu_to_le16(conn->handle);
-+              hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-+                              AUTH_REQUESTED_CP_SIZE, &ar);
-+      }
-+      return 0;
-+}
-+
-+/* Enable encryption */
-+int hci_conn_encrypt(struct hci_conn *conn)
-+{
-+      BT_DBG("conn %p", conn);
-+      
-+      if (conn->link_mode & HCI_LM_ENCRYPT)
-+              return 1;
-+      
-+      if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
-+              return 0;
-+
-+      if (hci_conn_auth(conn)) {
-+              set_conn_encrypt_cp ce;
-+              ce.handle  = __cpu_to_le16(conn->handle);
-+              ce.encrypt = 1; 
-+              hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
-+                              SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+      }
-+      return 0;
-+}
-+
-+/* Drop all connection on the device */
-+void hci_conn_hash_flush(struct hci_dev *hdev)
-+{
-+      struct conn_hash *h = &hdev->conn_hash;
-+        struct list_head *p;
-+
-+      BT_DBG("hdev %s", hdev->name);
-+
-+      p = h->list.next;
-+      while (p != &h->list) {
-+              struct hci_conn *c;
-+
-+              c = list_entry(p, struct hci_conn, list);
-+              p = p->next;
-+
-+              c->state = BT_CLOSED;
-+
-+              hci_proto_disconn_ind(c, 0x16);
-+              hci_conn_del(c);
-+      }
-+}
-+
-+int hci_get_conn_list(unsigned long arg)
-+{
-+      struct hci_conn_list_req req, *cl;
-+      struct hci_conn_info *ci;
-+      struct hci_dev *hdev;
-+      struct list_head *p;
-+      int n = 0, size;
-+
-+      if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+              return -EFAULT;
-+
-+      if (!(hdev = hci_dev_get(req.dev_id)))
-+              return -ENODEV;
-+
-+      size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
-+
-+      if (verify_area(VERIFY_WRITE, (void *)arg, size))
-+              return -EFAULT;
-+
-+      if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
-+              return -ENOMEM;
-+      ci = cl->conn_info;
-+
-+      hci_dev_lock_bh(hdev);
-+      list_for_each(p, &hdev->conn_hash.list) {
-+              register struct hci_conn *c;
-+              c = list_entry(p, struct hci_conn, list);
-+
-+              bacpy(&(ci + n)->bdaddr, &c->dst);
-+              (ci + n)->handle = c->handle;
-+              (ci + n)->type  = c->type;
-+              (ci + n)->out   = c->out;
-+              (ci + n)->state = c->state;
-+              (ci + n)->link_mode = c->link_mode;
-+              n++;
-+      }
-+      hci_dev_unlock_bh(hdev);
-+
-+      cl->dev_id = hdev->id;
-+      cl->conn_num = n;
-+      size = n * sizeof(struct hci_conn_info) + sizeof(req);
-+
-+      hci_dev_put(hdev);
-+
-+      copy_to_user((void *) arg, cl, size);
-+      kfree(cl);
-+
-+      return 0;
-+}
-+
-+int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
-+{
-+      struct hci_conn_info_req req;
-+      struct hci_conn_info ci;
-+      struct hci_conn *conn;
-+      char *ptr = (void *) arg + sizeof(req);
-+
-+      if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+              return -EFAULT;
-+
-+      if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
-+              return -EFAULT;
-+
-+      hci_dev_lock_bh(hdev);
-+      conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
-+      if (conn) {
-+              bacpy(&ci.bdaddr, &conn->dst);
-+              ci.handle = conn->handle;
-+              ci.type  = conn->type;
-+              ci.out   = conn->out;
-+              ci.state = conn->state;
-+              ci.link_mode = conn->link_mode;
-+      }
-+      hci_dev_unlock_bh(hdev);
-+
-+      if (!conn)
-+              return -ENOENT;
-+
-+      copy_to_user(ptr, &ci, sizeof(ci));
-+      return 0;
-+}
---- linux/net/bluetooth/hci_core.c~bluetooth-2.4.18-mh11       2001-11-09 23:21:21.000000000 +0100
-+++ linux/net/bluetooth/hci_core.c     2004-01-25 23:37:39.000000000 +0100
-@@ -25,11 +25,12 @@
- /*
-  * BlueZ HCI Core.
-  *
-- * $Id: hci_core.c,v 1.22 2001/08/03 04:19:50 maxk Exp $
-+ * $Id: hci_core.c,v 1.14 2002/08/26 16:57:57 maxk Exp $
-  */
- #include <linux/config.h>
- #include <linux/module.h>
-+#include <linux/kmod.h>
- #include <linux/types.h>
- #include <linux/errno.h>
-@@ -50,12 +51,11 @@
- #include <asm/unaligned.h>
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
- #ifndef HCI_CORE_DEBUG
--#undef  DBG
--#define DBG( A... )
-+#undef  BT_DBG
-+#define BT_DBG( A... )
- #endif
- static void hci_cmd_task(unsigned long arg);
-@@ -63,279 +63,69 @@
- static void hci_tx_task(unsigned long arg);
- static void hci_notify(struct hci_dev *hdev, int event);
--static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
-+rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
- /* HCI device list */
--struct hci_dev *hdev_list[HCI_MAX_DEV];
--spinlock_t hdev_list_lock;
--#define GET_HDEV(a) (hdev_list[a])
-+LIST_HEAD(hdev_list);
-+rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
--/* HCI protocol list */
--struct hci_proto *hproto_list[HCI_MAX_PROTO];
--#define GET_HPROTO(a) (hproto_list[a])
-+/* HCI protocols */
-+#define HCI_MAX_PROTO 2
-+struct hci_proto *hci_proto[HCI_MAX_PROTO];
- /* HCI notifiers list */
--struct notifier_block *hci_dev_notifier;
--
--/* HCI device notifications */
--int hci_register_notifier(struct notifier_block *nb)
--{
--      int err, i;
--      struct hci_dev *hdev;
--
--      if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
--              return err;
--
--      /* Notify about already registered devices */
--      spin_lock(&hdev_list_lock);
--      for (i = 0; i < HCI_MAX_DEV; i++) {
--              if (!(hdev = GET_HDEV(i)))
--                      continue;
--              if (hdev->flags & HCI_UP)
--                      (*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
--      }
--      spin_unlock(&hdev_list_lock);
--
--      return 0;
--}
--
--int hci_unregister_notifier(struct notifier_block *nb)
--{
--      return notifier_chain_unregister(&hci_dev_notifier, nb);
--}
--
--static inline void hci_notify(struct hci_dev *hdev, int event)
--{
--      notifier_call_chain(&hci_dev_notifier, event, hdev);
--}
--
--/* Get HCI device by index (device is locked on return)*/
--struct hci_dev *hci_dev_get(int index)
--{
--      struct hci_dev *hdev;
--      DBG("%d", index);
--
--      if (index < 0 || index >= HCI_MAX_DEV)
--              return NULL;
--
--      spin_lock(&hdev_list_lock);
--      if ((hdev = GET_HDEV(index)))
--              hci_dev_hold(hdev);
--      spin_unlock(&hdev_list_lock);
--
--      return hdev;
--}
--
--/* Flush inquiry cache */
--void inquiry_cache_flush(struct inquiry_cache *cache)
--{
--      struct inquiry_entry *next = cache->list, *e;
--
--      DBG("cache %p", cache);
--
--      cache->list = NULL;
--      while ((e = next)) {
--              next = e->next;
--              kfree(e);
--      }
--}
--
--/* Lookup by bdaddr.
-- * Cache must be locked. */
--static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
--{
--      struct inquiry_entry *e;
--
--      DBG("cache %p, %s", cache, batostr(bdaddr));
--
--      for (e = cache->list; e; e = e->next)
--              if (!bacmp(&e->info.bdaddr, bdaddr))
--                      break;
--
--      return e;
--}
--
--static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
--{
--      struct inquiry_entry *e;
--
--      DBG("cache %p, %s", cache, batostr(&info->bdaddr));
--
--      inquiry_cache_lock(cache);
--
--      if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
--              /* Entry not in the cache. Add new one. */
--              if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
--                      goto unlock;
--              memset(e, 0, sizeof(struct inquiry_entry));
--              e->next     = cache->list;
--              cache->list = e;
--      }
--
--      memcpy(&e->info, info, sizeof(inquiry_info));
--      e->timestamp = jiffies;
--      cache->timestamp = jiffies;
--unlock:
--      inquiry_cache_unlock(cache);
--}
--
--static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
--{
--      inquiry_info *info = (inquiry_info *) buf;
--      struct inquiry_entry *e;
--      int copied = 0;
--
--      inquiry_cache_lock(cache);
--
--      for (e = cache->list; e && copied < num; e = e->next, copied++)
--              memcpy(info++, &e->info, sizeof(inquiry_info));
-+static struct notifier_block *hci_notifier;
--      inquiry_cache_unlock(cache);
--      DBG("cache %p, copied %d", cache, copied);
--      return copied;
--}
-+/* ---- HCI notifications ---- */
--/* --------- BaseBand connections --------- */
--static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
-+int hci_register_notifier(struct notifier_block *nb)
- {
--      struct hci_conn *conn;
--
--      DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
--
--      if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
--              ERR("%s handle 0x%x already exists", hdev->name, handle);
--              return NULL;
--      }
--
--      if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
--              return NULL;
--      memset(conn, 0, sizeof(struct hci_conn));
--
--      bacpy(&conn->dst, dst);
--      conn->handle = handle;
--      conn->type   = type;
--      conn->hdev   = hdev;
--
--      skb_queue_head_init(&conn->data_q);
--
--      hci_dev_hold(hdev);
--      conn_hash_add(&hdev->conn_hash, handle, conn);
--
--      return conn;
-+      return notifier_chain_register(&hci_notifier, nb);
- }
--static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
-+int hci_unregister_notifier(struct notifier_block *nb)
- {
--      DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
--
--      conn_hash_del(&hdev->conn_hash, conn);
--      hci_dev_put(hdev);
--
--      /* Unacked frames */
--      hdev->acl_cnt += conn->sent;
--
--      skb_queue_purge(&conn->data_q);
--
--      kfree(conn);
--      return 0;
-+      return notifier_chain_unregister(&hci_notifier, nb);
- }
--/* Drop all connection on the device */
--static void hci_conn_hash_flush(struct hci_dev *hdev)
-+void hci_notify(struct hci_dev *hdev, int event)
- {
--      struct conn_hash *h = &hdev->conn_hash;
--      struct hci_proto *hp;
--        struct list_head *p;
--
--      DBG("hdev %s", hdev->name);
--
--      p = h->list.next;
--      while (p != &h->list) {
--              struct hci_conn *c;
--
--              c = list_entry(p, struct hci_conn, list);
--              p = p->next;
--
--              if (c->type == ACL_LINK) {
--                      /* ACL link notify L2CAP layer */
--                      if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
--                              hp->disconn_ind(c, 0x16);
--              } else {
--                      /* SCO link (no notification) */
--              }
--
--              hci_conn_del(hdev, c);
--      }
-+      notifier_call_chain(&hci_notifier, event, hdev);
- }
--int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
--      struct inquiry_cache *cache = &hdev->inq_cache;
--      struct inquiry_entry *e;
--      create_conn_cp cc;
--      __u16 clock_offset;
--
--      DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
--
--      if (!(hdev->flags & HCI_UP))
--              return -ENODEV;
--
--      inquiry_cache_lock_bh(cache);
--
--      if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
--              cc.pscan_rep_mode = 0;
--              cc.pscan_mode     = 0;
--              clock_offset      = 0;
--      } else {
--              cc.pscan_rep_mode = e->info.pscan_rep_mode;
--              cc.pscan_mode     = e->info.pscan_mode;
--              clock_offset      = __le16_to_cpu(e->info.clock_offset) & 0x8000;
--      }
--
--      inquiry_cache_unlock_bh(cache);
--
--      bacpy(&cc.bdaddr, bdaddr);
--      cc.pkt_type     = __cpu_to_le16(hdev->pkt_type);
--      cc.clock_offset = __cpu_to_le16(clock_offset);
--
--      if (lmp_rswitch_capable(hdev))
--              cc.role_switch  = 0x01;
--      else
--              cc.role_switch  = 0x00;
--              
--      hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
-+/* ---- HCI hotplug support ---- */
--      return 0;
--}
-+#ifdef CONFIG_HOTPLUG
--int hci_disconnect(struct hci_conn *conn, __u8 reason)
-+static int hci_run_hotplug(char *dev, char *action)
- {
--      disconnect_cp dc;
--
--      DBG("conn %p handle %d", conn, conn->handle);
-+      char *argv[3], *envp[5], dstr[20], astr[32];
--      dc.handle = __cpu_to_le16(conn->handle);
--      dc.reason = reason;
--      hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
-+      sprintf(dstr, "DEVICE=%s", dev);
-+      sprintf(astr, "ACTION=%s", action);
--      return 0;
--}
-+        argv[0] = hotplug_path;
-+        argv[1] = "bluetooth";
-+        argv[2] = NULL;
--/* --------- HCI request handling ------------ */
--static inline void hci_req_lock(struct hci_dev *hdev)
--{
--      down(&hdev->req_lock);
-+      envp[0] = "HOME=/";
-+      envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-+      envp[2] = dstr;
-+      envp[3] = astr;
-+      envp[4] = NULL;
-+      
-+      return call_usermodehelper(argv[0], argv, envp);
- }
-+#else
-+#define hci_run_hotplug(A...)
-+#endif
--static inline void hci_req_unlock(struct hci_dev *hdev)
--{
--      up(&hdev->req_lock);
--}
-+/* ---- HCI requests ---- */
--static inline void hci_req_complete(struct hci_dev *hdev, int result)
-+void hci_req_complete(struct hci_dev *hdev, int result)
- {
--      DBG("%s result 0x%2.2x", hdev->name, result);
-+      BT_DBG("%s result 0x%2.2x", hdev->name, result);
-       if (hdev->req_status == HCI_REQ_PEND) {
-               hdev->req_result = result;
-@@ -344,9 +134,9 @@
-       }
- }
--static inline void hci_req_cancel(struct hci_dev *hdev, int err)
-+void hci_req_cancel(struct hci_dev *hdev, int err)
- {
--      DBG("%s err 0x%2.2x", hdev->name, err);
-+      BT_DBG("%s err 0x%2.2x", hdev->name, err);
-       if (hdev->req_status == HCI_REQ_PEND) {
-               hdev->req_result = err;
-@@ -356,23 +146,22 @@
- }
- /* Execute request and wait for completion. */
--static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
--                         unsigned long opt, __u32 timeout)
-+static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
- {
-       DECLARE_WAITQUEUE(wait, current);
-       int err = 0;
--      DBG("%s start", hdev->name);
-+      BT_DBG("%s start", hdev->name);
-       hdev->req_status = HCI_REQ_PEND;
-       add_wait_queue(&hdev->req_wait_q, &wait);
--      current->state = TASK_INTERRUPTIBLE;
-+      set_current_state(TASK_INTERRUPTIBLE);
-       req(hdev, opt);
-       schedule_timeout(timeout);
--      current->state = TASK_RUNNING;
-+      set_current_state(TASK_RUNNING);
-       remove_wait_queue(&hdev->req_wait_q, &wait);
-       if (signal_pending(current))
-@@ -394,7 +183,7 @@
-       hdev->req_status = hdev->req_result = 0;
--      DBG("%s end: err %d", hdev->name, err);
-+      BT_DBG("%s end: err %d", hdev->name, err);
-       return err;
- }
-@@ -412,10 +201,9 @@
-       return ret;
- }
--/* --------- HCI requests ---------- */
- static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
- {
--      DBG("%s %ld", hdev->name, opt);
-+      BT_DBG("%s %ld", hdev->name, opt);
-       /* Reset device */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
-@@ -423,10 +211,10 @@
- static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
- {
--      set_event_flt_cp ec;
-+      set_event_flt_cp ef;
-       __u16 param;
--      DBG("%s %ld", hdev->name, opt);
-+      BT_DBG("%s %ld", hdev->name, opt);
-       /* Mandatory initialization */
-@@ -436,14 +224,27 @@
-       /* Read Buffer Size (ACL mtu, max pkt, etc.) */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
-+#if 0
-+      /* Host buffer size */
-+      {
-+              host_buffer_size_cp bs;
-+              bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
-+              bs.sco_mtu = HCI_MAX_SCO_SIZE;
-+              bs.acl_max_pkt = __cpu_to_le16(0xffff);
-+              bs.sco_max_pkt = __cpu_to_le16(0xffff);
-+              hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
-+                              HOST_BUFFER_SIZE_CP_SIZE, &bs);
-+      }
-+#endif
-+
-       /* Read BD Address */
-       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
-       /* Optional initialization */
-       /* Clear Event Filters */
--      ec.flt_type  = FLT_CLEAR_ALL;
--      hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
-+      ef.flt_type  = FLT_CLEAR_ALL;
-+      hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
-       /* Page timeout ~20 secs */
-       param = __cpu_to_le16(0x8000);
-@@ -458,7 +259,7 @@
- {
-       __u8 scan = opt;
--      DBG("%s %x", hdev->name, scan);
-+      BT_DBG("%s %x", hdev->name, scan);
-       /* Inquiry and Page scans */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
-@@ -468,27 +269,190 @@
- {
-       __u8 auth = opt;
--      DBG("%s %x", hdev->name, auth);
-+      BT_DBG("%s %x", hdev->name, auth);
-       /* Authentication */
-       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
- }
-+static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
-+{
-+      __u8 encrypt = opt;
-+
-+      BT_DBG("%s %x", hdev->name, encrypt);
-+
-+      /* Authentication */
-+      hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
-+}
-+
-+/* Get HCI device by index. 
-+ * Device is locked on return. */
-+struct hci_dev *hci_dev_get(int index)
-+{
-+      struct hci_dev *hdev;
-+      struct list_head *p;
-+
-+      BT_DBG("%d", index);
-+
-+      if (index < 0)
-+              return NULL;
-+
-+      read_lock(&hdev_list_lock);
-+      list_for_each(p, &hdev_list) {
-+              hdev = list_entry(p, struct hci_dev, list);
-+              if (hdev->id == index) {
-+                      hci_dev_hold(hdev);
-+                      goto done;
-+              }
-+      }
-+      hdev = NULL;
-+done:
-+      read_unlock(&hdev_list_lock);
-+      return hdev;
-+}
-+
-+/* ---- Inquiry support ---- */
-+void inquiry_cache_flush(struct hci_dev *hdev)
-+{
-+      struct inquiry_cache *cache = &hdev->inq_cache;
-+      struct inquiry_entry *next  = cache->list, *e;
-+
-+      BT_DBG("cache %p", cache);
-+
-+      cache->list = NULL;
-+      while ((e = next)) {
-+              next = e->next;
-+              kfree(e);
-+      }
-+}
-+
-+struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
-+{
-+      struct inquiry_cache *cache = &hdev->inq_cache;
-+      struct inquiry_entry *e;
-+
-+      BT_DBG("cache %p, %s", cache, batostr(bdaddr));
-+
-+      for (e = cache->list; e; e = e->next)
-+              if (!bacmp(&e->info.bdaddr, bdaddr))
-+                      break;
-+      return e;
-+}
-+
-+void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
-+{
-+      struct inquiry_cache *cache = &hdev->inq_cache;
-+      struct inquiry_entry *e;
-+
-+      BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
-+
-+      if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
-+              /* Entry not in the cache. Add new one. */
-+              if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
-+                      return;
-+              memset(e, 0, sizeof(struct inquiry_entry));
-+              e->next     = cache->list;
-+              cache->list = e;
-+      }
-+
-+      memcpy(&e->info, info, sizeof(inquiry_info));
-+      e->timestamp = jiffies;
-+      cache->timestamp = jiffies;
-+}
-+
-+int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
-+{
-+      struct inquiry_cache *cache = &hdev->inq_cache;
-+      inquiry_info *info = (inquiry_info *) buf;
-+      struct inquiry_entry *e;
-+      int copied = 0;
-+
-+      for (e = cache->list; e && copied < num; e = e->next, copied++)
-+              memcpy(info++, &e->info, sizeof(inquiry_info));
-+
-+      BT_DBG("cache %p, copied %d", cache, copied);
-+      return copied;
-+}
-+
- static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
- {
-       struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
-       inquiry_cp ic;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", hdev->name);
-+
-+      if (test_bit(HCI_INQUIRY, &hdev->flags))
-+              return;
-       /* Start Inquiry */
-       memcpy(&ic.lap, &ir->lap, 3);
--      ic.lenght  = ir->length;
-+      ic.length  = ir->length;
-       ic.num_rsp = ir->num_rsp;
-       hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
- }
--/* HCI ioctl helpers */
-+int hci_inquiry(unsigned long arg)
-+{
-+      struct hci_inquiry_req ir;
-+      struct hci_dev *hdev;
-+      int err = 0, do_inquiry = 0, max_rsp;
-+      long timeo;
-+      __u8 *buf, *ptr;
-+
-+      ptr = (void *) arg;
-+      if (copy_from_user(&ir, ptr, sizeof(ir)))
-+              return -EFAULT;
-+
-+      if (!(hdev = hci_dev_get(ir.dev_id)))
-+              return -ENODEV;
-+
-+      hci_dev_lock_bh(hdev);
-+      if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || 
-+                                      inquiry_cache_empty(hdev) ||
-+                                      ir.flags & IREQ_CACHE_FLUSH) {
-+              inquiry_cache_flush(hdev);
-+              do_inquiry = 1;
-+      }
-+      hci_dev_unlock_bh(hdev);
-+
-+      timeo = ir.length * 2 * HZ;
-+      if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-+              goto done;
-+
-+      /* for unlimited number of responses we will use buffer with 255 entries */
-+      max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
-+
-+      /* cache_dump can't sleep. Therefore we allocate temp buffer and then
-+       * copy it to the user space.
-+       */
-+      if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
-+              err = -ENOMEM;
-+              goto done;
-+      }
-+
-+      hci_dev_lock_bh(hdev);
-+      ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
-+      hci_dev_unlock_bh(hdev);
-+
-+      BT_DBG("num_rsp %d", ir.num_rsp);
-+
-+      if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + 
-+                              (sizeof(inquiry_info) * ir.num_rsp))) {
-+              copy_to_user(ptr, &ir, sizeof(ir));
-+              ptr += sizeof(ir);
-+              copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
-+      } else 
-+              err = -EFAULT;
-+
-+      kfree(buf);
-+
-+done:
-+      hci_dev_put(hdev);
-+      return err;
-+}
-+
-+/* ---- HCI ioctl helpers ---- */
-+
- int hci_dev_open(__u16 dev)
- {
-       struct hci_dev *hdev;
-@@ -497,11 +461,11 @@
-       if (!(hdev = hci_dev_get(dev)))
-               return -ENODEV;
--      DBG("%s %p", hdev->name, hdev);
-+      BT_DBG("%s %p", hdev->name, hdev);
-       hci_req_lock(hdev);
--      if (hdev->flags & HCI_UP) {
-+      if (test_bit(HCI_UP, &hdev->flags)) {
-               ret = -EALREADY;
-               goto done;
-       }
-@@ -511,18 +475,18 @@
-               goto done;
-       }
--      if (hdev->flags & HCI_NORMAL) {
-+      if (!test_bit(HCI_RAW, &hdev->flags)) {
-               atomic_set(&hdev->cmd_cnt, 1);
--              hdev->flags |= HCI_INIT;
-+              set_bit(HCI_INIT, &hdev->flags);
-               //__hci_request(hdev, hci_reset_req, 0, HZ);
-               ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
-        
--              hdev->flags &= ~HCI_INIT;
-+              clear_bit(HCI_INIT, &hdev->flags);
-       }
-       if (!ret) {
--              hdev->flags |= HCI_UP;
-+              set_bit(HCI_UP, &hdev->flags);
-               hci_notify(hdev, HCI_DEV_UP);
-       } else {        
-               /* Init failed, cleanup */
-@@ -542,42 +506,36 @@
-               }
-               hdev->close(hdev);
-+              hdev->flags = 0;
-       }
- done:
-       hci_req_unlock(hdev);
-       hci_dev_put(hdev);
--
-       return ret;
- }
--int hci_dev_close(__u16 dev)
-+static int hci_dev_do_close(struct hci_dev *hdev)
- {
--      struct hci_dev *hdev;
--
--      if (!(hdev = hci_dev_get(dev)))
--              return -ENODEV;
--
--      DBG("%s %p", hdev->name, hdev);
-+      BT_DBG("%s %p", hdev->name, hdev);
-       hci_req_cancel(hdev, ENODEV);
-       hci_req_lock(hdev);
--      if (!(hdev->flags & HCI_UP))
--              goto done;
-+      if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
-+              hci_req_unlock(hdev);
-+              return 0;
-+      }
-       /* Kill RX and TX tasks */
-       tasklet_kill(&hdev->rx_task);
-       tasklet_kill(&hdev->tx_task);
--      inquiry_cache_flush(&hdev->inq_cache);
--
-+      hci_dev_lock_bh(hdev);
-+      inquiry_cache_flush(hdev);
-       hci_conn_hash_flush(hdev);
--
--      /* Clear flags */
--      hdev->flags &= HCI_SOCK;
--      hdev->flags |= HCI_NORMAL;
--
-+      hci_dev_unlock_bh(hdev);
-+      
-       hci_notify(hdev, HCI_DEV_DOWN);
-       if (hdev->flush)
-@@ -586,9 +544,9 @@
-       /* Reset device */
-       skb_queue_purge(&hdev->cmd_q);
-       atomic_set(&hdev->cmd_cnt, 1);
--      hdev->flags |= HCI_INIT;
--      __hci_request(hdev, hci_reset_req, 0, HZ);
--      hdev->flags &= ~HCI_INIT;
-+      set_bit(HCI_INIT, &hdev->flags);
-+      __hci_request(hdev, hci_reset_req, 0, HZ/4);
-+      clear_bit(HCI_INIT, &hdev->flags);
-       /* Kill cmd task */
-       tasklet_kill(&hdev->cmd_task);
-@@ -605,17 +563,28 @@
-       }
-       /* After this point our queues are empty
--       * and no tasks are scheduled.
--       */
-+       * and no tasks are scheduled. */
-       hdev->close(hdev);
--done:
--      hci_req_unlock(hdev);
--      hci_dev_put(hdev);
-+      /* Clear flags */
-+      hdev->flags = 0;
-+      hci_req_unlock(hdev);
-       return 0;
- }
-+int hci_dev_close(__u16 dev)
-+{
-+      struct hci_dev *hdev;
-+      int err;
-+      
-+      if (!(hdev = hci_dev_get(dev)))
-+              return -ENODEV;
-+      err = hci_dev_do_close(hdev);
-+      hci_dev_put(hdev);
-+      return err;
-+}
-+
- int hci_dev_reset(__u16 dev)
- {
-       struct hci_dev *hdev;
-@@ -627,16 +596,17 @@
-       hci_req_lock(hdev);
-       tasklet_disable(&hdev->tx_task);
--      if (!(hdev->flags & HCI_UP))
-+      if (!test_bit(HCI_UP, &hdev->flags))
-               goto done;
-       /* Drop queues */
-       skb_queue_purge(&hdev->rx_q);
-       skb_queue_purge(&hdev->cmd_q);
--      inquiry_cache_flush(&hdev->inq_cache);
--
-+      hci_dev_lock_bh(hdev);
-+      inquiry_cache_flush(hdev);
-       hci_conn_hash_flush(hdev);
-+      hci_dev_unlock_bh(hdev);
-       if (hdev->flush)
-               hdev->flush(hdev);
-@@ -650,7 +620,6 @@
-       tasklet_enable(&hdev->tx_task);
-       hci_req_unlock(hdev);
-       hci_dev_put(hdev);
--
-       return ret;
- }
-@@ -669,30 +638,11 @@
-       return ret;
- }
--int hci_dev_setauth(unsigned long arg)
--{
--      struct hci_dev *hdev;
--      struct hci_dev_req dr;
--      int ret = 0;
--
--      if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
--              return -EFAULT;
--
--      if (!(hdev = hci_dev_get(dr.dev_id)))
--              return -ENODEV;
--
--      ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
--      hci_dev_put(hdev);
--
--      return ret;
--}
--
--int hci_dev_setscan(unsigned long arg)
-+int hci_dev_cmd(unsigned int cmd, unsigned long arg)
- {
-       struct hci_dev *hdev;
-       struct hci_dev_req dr;
--      int ret = 0;
-+      int err = 0;
-       if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
-               return -EFAULT;
-@@ -700,48 +650,78 @@
-       if (!(hdev = hci_dev_get(dr.dev_id)))
-               return -ENODEV;
--      ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
--
--      hci_dev_put(hdev);
-+      switch (cmd) {
-+      case HCISETAUTH:
-+              err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+              break;
--      return ret;
--}
-+      case HCISETENCRYPT:
-+              if (!lmp_encrypt_capable(hdev)) {
-+                      err = -EOPNOTSUPP;
-+                      break;
-+              }
--int hci_dev_setptype(unsigned long arg)
--{
--      struct hci_dev *hdev;
--      struct hci_dev_req dr;
--      int ret = 0;
-+              if (!test_bit(HCI_AUTH, &hdev->flags)) {
-+                      /* Auth must be enabled first */
-+                      err = hci_request(hdev, hci_auth_req,
-+                                      dr.dev_opt, HCI_INIT_TIMEOUT);
-+                      if (err)
-+                              break;
-+              }
-+                      
-+              err = hci_request(hdev, hci_encrypt_req,
-+                                      dr.dev_opt, HCI_INIT_TIMEOUT);
-+              break;
-+      
-+      case HCISETSCAN:
-+              err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
-+              break;
-+      
-+      case HCISETPTYPE:
-+              hdev->pkt_type = (__u16) dr.dev_opt;
-+              break;
-+              
-+      case HCISETLINKPOL:
-+              hdev->link_policy = (__u16) dr.dev_opt;
-+              break;
--      if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
--              return -EFAULT;
-+      case HCISETLINKMODE:
-+              hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
-+              break;
--      if (!(hdev = hci_dev_get(dr.dev_id)))
--              return -ENODEV;
-+      case HCISETACLMTU:
-+              hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);
-+              hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
-+              break;
--      hdev->pkt_type = (__u16) dr.dev_opt;
-+      case HCISETSCOMTU:
-+              hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);
-+              hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
-+              break;
-+      default:
-+              err = -EINVAL;
-+              break;
-+      }       
-       hci_dev_put(hdev);
--
--      return ret;
-+      return err;
- }
--int hci_dev_list(unsigned long arg)
-+int hci_get_dev_list(unsigned long arg)
- {
-       struct hci_dev_list_req *dl;
-       struct hci_dev_req *dr;
--      struct hci_dev *hdev;
--      int i, n, size;
-+      struct list_head *p;
-+      int n = 0, size;
-       __u16 dev_num;
-       if (get_user(dev_num, (__u16 *) arg))
-               return -EFAULT;
--      /* Avoid long loop, overflow */
--      if (dev_num > 2048)
-+      if (!dev_num)
-               return -EINVAL;
-       
--      size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
-+      size = dev_num * sizeof(*dr) + sizeof(*dl);
-       if (verify_area(VERIFY_WRITE, (void *) arg, size))
-               return -EFAULT;
-@@ -750,25 +730,27 @@
-               return -ENOMEM;
-       dr = dl->dev_req;
--      spin_lock_bh(&hdev_list_lock);
--      for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
--              if ((hdev = hdev_list[i])) {
--                      (dr + n)->dev_id  = hdev->id;
--                      (dr + n)->dev_opt = hdev->flags;
--                      n++;
--              }
-+      read_lock_bh(&hdev_list_lock);
-+      list_for_each(p, &hdev_list) {
-+              struct hci_dev *hdev;
-+              hdev = list_entry(p, struct hci_dev, list);
-+              (dr + n)->dev_id  = hdev->id;
-+              (dr + n)->dev_opt = hdev->flags;
-+              if (++n >= dev_num)
-+                      break;
-       }
--      spin_unlock_bh(&hdev_list_lock);
-+      read_unlock_bh(&hdev_list_lock);
-       dl->dev_num = n;
--      size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
-+      size = n * sizeof(*dr) + sizeof(*dl);
-       copy_to_user((void *) arg, dl, size);
-+      kfree(dl);
-       return 0;
- }
--int hci_dev_info(unsigned long arg)
-+int hci_get_dev_info(unsigned long arg)
- {
-       struct hci_dev *hdev;
-       struct hci_dev_info di;
-@@ -786,9 +768,11 @@
-       di.flags    = hdev->flags;
-       di.pkt_type = hdev->pkt_type;
-       di.acl_mtu  = hdev->acl_mtu;
--      di.acl_max  = hdev->acl_max;
-+      di.acl_pkts = hdev->acl_pkts;
-       di.sco_mtu  = hdev->sco_mtu;
--      di.sco_max  = hdev->sco_max;
-+      di.sco_pkts = hdev->sco_pkts;
-+      di.link_policy = hdev->link_policy;
-+      di.link_mode   = hdev->link_mode;
-       memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
-       memcpy(&di.features, &hdev->features, sizeof(di.features));
-@@ -801,258 +785,168 @@
-       return err;
- }
--__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
--{
--      __u32 omode = hdev->flags & HCI_MODE_MASK;
--
--      hdev->flags &= ~HCI_MODE_MASK;
--      hdev->flags |= (mode & HCI_MODE_MASK);
--      return omode;
--}
--
--__u32 hci_dev_getmode(struct hci_dev *hdev)
--{
--      return hdev->flags & HCI_MODE_MASK;
--}
-+/* ---- Interface to HCI drivers ---- */
--int hci_conn_list(unsigned long arg)
-+/* Register HCI device */
-+int hci_register_dev(struct hci_dev *hdev)
- {
--      struct hci_conn_list_req req, *cl;
--      struct hci_conn_info *ci;
--      struct hci_dev *hdev;
--      struct list_head *p;
--      int n = 0, size;
--
--      if (copy_from_user(&req, (void *) arg, sizeof(req)))
--              return -EFAULT;
-+      struct list_head *head = &hdev_list, *p;
-+      int id = 0;
--      if (!(hdev = hci_dev_get(req.dev_id)))
--              return -ENODEV;
-+      BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--      /* Set a limit to avoid overlong loops, and also numeric overflow - AC */
--      if(req.conn_num < 2048)
-+      if (!hdev->open || !hdev->close || !hdev->destruct)
-               return -EINVAL;
--      
--      size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
--      if (!(cl = kmalloc(size, GFP_KERNEL)))
--              return -ENOMEM;
--      ci = cl->conn_info;
--
--      local_bh_disable();
--      conn_hash_lock(&hdev->conn_hash);
--      list_for_each(p, &hdev->conn_hash.list) {
--              register struct hci_conn *c;
--              c = list_entry(p, struct hci_conn, list);
-+      write_lock_bh(&hdev_list_lock);
--              (ci + n)->handle = c->handle;
--              bacpy(&(ci + n)->bdaddr, &c->dst);
--              n++;
-+      /* Find first available device id */
-+      list_for_each(p, &hdev_list) {
-+              if (list_entry(p, struct hci_dev, list)->id != id)
-+                      break;
-+              head = p; id++;
-       }
--      conn_hash_unlock(&hdev->conn_hash);
--      local_bh_enable();
--
--      cl->dev_id = hdev->id;
--      cl->conn_num = n;
--      size = n * sizeof(struct hci_conn_info) + sizeof(req);
--
--      hci_dev_put(hdev);
--
--      if(copy_to_user((void *) arg, cl, size))
--              return -EFAULT;
--      return 0;
--}
--
--int hci_inquiry(unsigned long arg)
--{
--      struct inquiry_cache *cache;
--      struct hci_inquiry_req ir;
--      struct hci_dev *hdev;
--      int err = 0, do_inquiry = 0;
--      long timeo;
--      __u8 *buf, *ptr;
--
--      ptr = (void *) arg;
--      if (copy_from_user(&ir, ptr, sizeof(ir)))
--              return -EFAULT;
-+      
-+      sprintf(hdev->name, "hci%d", id);
-+      hdev->id = id;
-+      list_add(&hdev->list, head);
--      if (!(hdev = hci_dev_get(ir.dev_id)))
--              return -ENODEV;
-+      atomic_set(&hdev->refcnt, 1);
-+      spin_lock_init(&hdev->lock);
-+                      
-+      hdev->flags = 0;
-+      hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
-+      hdev->link_mode = (HCI_LM_ACCEPT);
--      cache = &hdev->inq_cache;
-+      tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
-+      tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
-+      tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
--      inquiry_cache_lock(cache);
--      if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
--              inquiry_cache_flush(cache);
--              do_inquiry = 1;
--      }
--      inquiry_cache_unlock(cache);
-+      skb_queue_head_init(&hdev->rx_q);
-+      skb_queue_head_init(&hdev->cmd_q);
-+      skb_queue_head_init(&hdev->raw_q);
--      /* Limit inquiry time, also avoid overflows */
-+      init_waitqueue_head(&hdev->req_wait_q);
-+      init_MUTEX(&hdev->req_lock);
--      if(ir.length > 2048 || ir.num_rsp > 2048)
--      {
--              err = -EINVAL;
--              goto done;
--      }
-+      inquiry_cache_init(hdev);
--      timeo = ir.length * 2 * HZ;
--      if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
--              goto done;
-+      conn_hash_init(hdev);
--      /* cache_dump can't sleep. Therefore we allocate temp buffer and then
--       * copy it to the user space.
--       */
--      if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
--              err = -ENOMEM;
--              goto done;
--      }
--      ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
-+      memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
--      DBG("num_rsp %d", ir.num_rsp);
-+      atomic_set(&hdev->promisc, 0);
--      if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
--              copy_to_user(ptr, &ir, sizeof(ir));
--              ptr += sizeof(ir);
--              copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
--      } else 
--              err = -EFAULT;
-+      MOD_INC_USE_COUNT;
--      kfree(buf);
-+      write_unlock_bh(&hdev_list_lock);
--done:
--      hci_dev_put(hdev);
-+      hci_notify(hdev, HCI_DEV_REG);
-+      hci_run_hotplug(hdev->name, "register");
--      return err;
-+      return id;
- }
--/* Interface to HCI drivers */
--
--/* Register HCI device */
--int hci_register_dev(struct hci_dev *hdev)
-+/* Unregister HCI device */
-+int hci_unregister_dev(struct hci_dev *hdev)
- {
--      int i;
--
--      DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--
--      /* Find free slot */
--      spin_lock_bh(&hdev_list_lock);
--      for (i = 0; i < HCI_MAX_DEV; i++) {
--              if (!hdev_list[i]) {
--                      hdev_list[i] = hdev;
--
--                      sprintf(hdev->name, "hci%d", i);
--                      atomic_set(&hdev->refcnt, 0);
--                      hdev->id    = i;
--                      hdev->flags = HCI_NORMAL;
--
--                      hdev->pkt_type = (HCI_DM1 | HCI_DH1);
--
--                      tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
--                      tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
--                      tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
--
--                      skb_queue_head_init(&hdev->rx_q);
--                      skb_queue_head_init(&hdev->cmd_q);
--                      skb_queue_head_init(&hdev->raw_q);
--
--                      init_waitqueue_head(&hdev->req_wait_q);
--                      init_MUTEX(&hdev->req_lock);
--
--                      inquiry_cache_init(&hdev->inq_cache);
-+      BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
--                      conn_hash_init(&hdev->conn_hash);
-+      write_lock_bh(&hdev_list_lock);
-+      list_del(&hdev->list);
-+      write_unlock_bh(&hdev_list_lock);
--                      memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
-+      hci_dev_do_close(hdev);
--                      hci_notify(hdev, HCI_DEV_REG);
-+      hci_notify(hdev, HCI_DEV_UNREG);
-+      hci_run_hotplug(hdev->name, "unregister");
--                      MOD_INC_USE_COUNT;
--                      break;
--              }
--      }
--      spin_unlock_bh(&hdev_list_lock);
-+      hci_dev_put(hdev);
--      return (i == HCI_MAX_DEV) ? -1 : i;
-+      MOD_DEC_USE_COUNT;
-+      return 0;
- }
--/* Unregister HCI device */
--int hci_unregister_dev(struct hci_dev *hdev)
-+/* Suspend HCI device */
-+int hci_suspend_dev(struct hci_dev *hdev)
- {
--      int i;
-+      hci_notify(hdev, HCI_DEV_SUSPEND);
-+      hci_run_hotplug(hdev->name, "suspend");
-+      return 0;
-+}
--      DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
-+/* Resume HCI device */
-+int hci_resume_dev(struct hci_dev *hdev)
-+{
-+      hci_notify(hdev, HCI_DEV_RESUME);
-+      hci_run_hotplug(hdev->name, "resume");
-+      return 0;
-+}       
--      if (hdev->flags & HCI_UP)
--              hci_dev_close(hdev->id);
-+/* Receive frame from HCI drivers */
-+int hci_recv_frame(struct sk_buff *skb)
-+{
-+      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--      /* Find device slot */
--      spin_lock(&hdev_list_lock);
--      for (i = 0; i < HCI_MAX_DEV; i++) {
--              if (hdev_list[i] == hdev) {
--                      hdev_list[i] = NULL;
--                      MOD_DEC_USE_COUNT;
--                      break;
--              }
-+      if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && 
-+                              !test_bit(HCI_INIT, &hdev->flags)) ) {
-+              kfree_skb(skb);
-+              return -1;
-       }
--      spin_unlock(&hdev_list_lock);
--      hci_notify(hdev, HCI_DEV_UNREG);
--
--      /* Sleep while device is in use */
--      while (atomic_read(&hdev->refcnt)) {
--              int sleep_cnt = 100;
-+      BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--              DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
-+      /* Incomming skb */
-+      bluez_cb(skb)->incomming = 1;
--              sleep_on_timeout(&hdev->req_wait_q, HZ*10);
--              if (!(--sleep_cnt))
--                      break;
--      }
-+      /* Time stamp */
-+      do_gettimeofday(&skb->stamp);
-+      /* Queue frame for rx task */
-+      skb_queue_tail(&hdev->rx_q, skb);
-+      hci_sched_rx(hdev);
-       return 0;
- }
--/* Interface to upper protocols */
-+/* ---- Interface to upper protocols ---- */
- /* Register/Unregister protocols.
-- * hci_task_lock is used to ensure that no tasks are running.
-- */
--int hci_register_proto(struct hci_proto *hproto)
-+ * hci_task_lock is used to ensure that no tasks are running. */
-+int hci_register_proto(struct hci_proto *hp)
- {
-       int err = 0;
--      DBG("%p name %s", hproto, hproto->name);
-+      BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
--      if (hproto->id >= HCI_MAX_PROTO)
-+      if (hp->id >= HCI_MAX_PROTO)
-               return -EINVAL;
-       write_lock_bh(&hci_task_lock);
--      if (!hproto_list[hproto->id])
--              hproto_list[hproto->id] = hproto;
-+      if (!hci_proto[hp->id])
-+              hci_proto[hp->id] = hp;
-       else
--              err = -1;
-+              err = -EEXIST;
-       write_unlock_bh(&hci_task_lock);
-       return err;
- }
--int hci_unregister_proto(struct hci_proto *hproto)
-+int hci_unregister_proto(struct hci_proto *hp)
- {
-       int err = 0;
--      DBG("%p name %s", hproto, hproto->name);
-+      BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
--      if (hproto->id > HCI_MAX_PROTO)
-+      if (hp->id >= HCI_MAX_PROTO)
-               return -EINVAL;
-       write_lock_bh(&hci_task_lock);
--      if (hproto_list[hproto->id])
--              hproto_list[hproto->id] = NULL;
-+      if (hci_proto[hp->id])
-+              hci_proto[hp->id] = NULL;
-       else
-               err = -ENOENT;
-@@ -1070,10 +964,14 @@
-               return -ENODEV;
-       }
--      DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+      BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
-+
-+      if (atomic_read(&hdev->promisc)) {
-+              /* Time stamp */
-+              do_gettimeofday(&skb->stamp);
--      if (hdev->flags & HCI_SOCK)
-               hci_send_to_sock(hdev, skb);
-+      }
-       /* Get rid of skb owner, prior to sending to the driver. */
-       skb_orphan(skb);
-@@ -1081,128 +979,6 @@
-       return hdev->send(skb);
- }
--/* Connection scheduler */
--static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
--{
--      struct conn_hash *h = &hdev->conn_hash;
--      struct hci_conn *conn = NULL;
--      int num = 0, min = 0xffff;
--        struct list_head *p;
--
--      conn_hash_lock(h);
--      list_for_each(p, &h->list) {
--              register struct hci_conn *c;
--
--              c = list_entry(p, struct hci_conn, list);
--
--              if (c->type != type || skb_queue_empty(&c->data_q))
--                      continue;
--              num++;
--
--              if (c->sent < min) {
--                      min  = c->sent;
--                      conn = c;
--              }
--      }
--      conn_hash_unlock(h);
--
--      if (conn) {
--              int q = hdev->acl_cnt / num;
--              *quote = q ? q : 1;
--      } else
--              *quote = 0;
--
--      DBG("conn %p quote %d", conn, *quote);
--
--      return conn;
--}
--
--static inline void hci_sched_acl(struct hci_dev *hdev)
--{
--      struct hci_conn *conn;
--      struct sk_buff *skb;
--      int quote;
--
--      DBG("%s", hdev->name);
--
--      while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
--              while (quote && (skb = skb_dequeue(&conn->data_q))) {
--                      DBG("skb %p len %d", skb, skb->len);
--
--                      hci_send_frame(skb);
--
--                      conn->sent++;
--                      hdev->acl_cnt--;
--                      quote--;
--              }
--      }
--}
--
--/* Schedule SCO */
--static inline void hci_sched_sco(struct hci_dev *hdev)
--{
--      /* FIXME: For now we queue SCO packets to the raw queue 
--
--              while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
--                      hci_send_frame(skb);
--                      conn->sco_sent++;
--                      hdev->sco_cnt--;
--              }
--      */
--}
--
--/* Get data from the previously sent command */
--static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
--{
--      hci_command_hdr *hc;
--
--      if (!hdev->sent_cmd)
--              return NULL;
--
--      hc = (void *) hdev->sent_cmd->data;
--
--      if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
--              return NULL;
--
--      DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
--
--      return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
--}
--
--/* Send raw HCI frame */
--int hci_send_raw(struct sk_buff *skb)
--{
--      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
--      if (!hdev) {
--              kfree_skb(skb);
--              return -ENODEV;
--      }
--
--      DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
--      if (hdev->flags & HCI_NORMAL) {
--              /* Queue frame according it's type */
--              switch (skb->pkt_type) {
--              case HCI_COMMAND_PKT:
--                      skb_queue_tail(&hdev->cmd_q, skb);
--                      hci_sched_cmd(hdev);
--                      return 0;
--
--              case HCI_ACLDATA_PKT:
--              case HCI_SCODATA_PKT:
--                      /* FIXME:
--                       * Check header here and queue to apropriate connection.
--                       */
--                      break;
--              }
--      }
--
--      skb_queue_tail(&hdev->raw_q, skb);
--      hci_sched_tx(hdev);
--      return 0;
--}
--
- /* Send HCI command */
- int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
- {
-@@ -1210,10 +986,10 @@
-       hci_command_hdr *hc;
-       struct sk_buff *skb;
--      DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-+      BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
-       if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
--              ERR("%s Can't allocate memory for HCI command", hdev->name);
-+              BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
-               return -ENOMEM;
-       }
-       
-@@ -1224,7 +1000,7 @@
-       if (plen)
-               memcpy(skb_put(skb, plen), param, plen);
--      DBG("skb len %d", skb->len);
-+      BT_DBG("skb len %d", skb->len);
-       skb->pkt_type = HCI_COMMAND_PKT;
-       skb->dev = (void *) hdev;
-@@ -1234,10 +1010,28 @@
-       return 0;
- }
-+/* Get data from the previously sent command */
-+void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
-+{
-+      hci_command_hdr *hc;
-+
-+      if (!hdev->sent_cmd)
-+              return NULL;
-+
-+      hc = (void *) hdev->sent_cmd->data;
-+
-+      if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
-+              return NULL;
-+
-+      BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
-+
-+      return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
-+}
-+
- /* Send ACL data */
- static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
- {
--      int len = skb->len;     
-+      int len = skb->len;
-       hci_acl_hdr *ah;
-       ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
-@@ -1252,7 +1046,7 @@
-       struct hci_dev *hdev = conn->hdev;
-       struct sk_buff *list;
--      DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-+      BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-       skb->dev = (void *) hdev;
-       skb->pkt_type = HCI_ACLDATA_PKT;
-@@ -1260,12 +1054,12 @@
-       if (!(list = skb_shinfo(skb)->frag_list)) {
-               /* Non fragmented */
--              DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-+              BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
-               
-               skb_queue_tail(&conn->data_q, skb);
-       } else {
-               /* Fragmented */
--              DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+              BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-               skb_shinfo(skb)->frag_list = NULL;
-@@ -1280,7 +1074,7 @@
-                       skb->pkt_type = HCI_ACLDATA_PKT;
-                       hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
-               
--                      DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-+                      BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
-                       __skb_queue_tail(&conn->data_q, skb);
-               } while (list);
-@@ -1298,7 +1092,7 @@
-       struct hci_dev *hdev = conn->hdev;
-       hci_sco_hdr hs;
--      DBG("%s len %d", hdev->name, skb->len);
-+      BT_DBG("%s len %d", hdev->name, skb->len);
-       if (skb->len > hdev->sco_mtu) {
-               kfree_skb(skb);
-@@ -1315,544 +1109,136 @@
-       skb->pkt_type = HCI_SCODATA_PKT;
-       skb_queue_tail(&conn->data_q, skb);
-       hci_sched_tx(hdev);
--
-       return 0;
- }
--/* 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)
--{
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      default:
--              DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
--              break;
--      };
--}
--
--/* Command Complete OGF LINK_POLICY  */
--static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      default:
--              DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
--              break;
--      };
--}
--
--/* Command Complete OGF HOST_CTL  */
--static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
--{
--      __u8 status, param;
--      void *sent;
--
--
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      case OCF_RESET:
--              status = *((__u8 *) skb->data);
--
--              hci_req_complete(hdev, status);
--              break;
--
--      case OCF_SET_EVENT_FLT:
--              status = *((__u8 *) skb->data);
--
--              if (status) {
--                      DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
--              } else {
--                      DBG("%s SET_EVENT_FLT succeseful", hdev->name);
--              }
--              break;
--
--      case OCF_WRITE_AUTH_ENABLE:
--              if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
--                      break;
--
--              status = *((__u8 *) skb->data);
--              param  = *((__u8 *) sent);
--
--              if (!status) {
--                      if (param == AUTH_ENABLED)
--                              hdev->flags |= HCI_AUTH;
--                      else
--                              hdev->flags &= ~HCI_AUTH;
--              }
--              hci_req_complete(hdev, status);
--              break;
--
--      case OCF_WRITE_CA_TIMEOUT:
--              status = *((__u8 *) skb->data);
--
--              if (status) {
--                      DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
--              } else {
--                      DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
--              }
--              break;
--
--      case OCF_WRITE_PG_TIMEOUT:
--              status = *((__u8 *) skb->data);
--
--              if (status) {
--                      DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
--              } else {
--                      DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
--              }
--              break;
--
--      case OCF_WRITE_SCAN_ENABLE:
--              if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
--                      break;
--              status = *((__u8 *) skb->data);
--              param  = *((__u8 *) sent);
--
--              DBG("param 0x%x", param);
--
--              if (!status) {
--                      switch (param) {
--                      case IS_ENA_PS_ENA:
--                              hdev->flags |=  HCI_PSCAN | HCI_ISCAN;
--                              break;
--
--                      case IS_ENA_PS_DIS:
--                              hdev->flags &= ~HCI_PSCAN;
--                              hdev->flags |=  HCI_ISCAN;
--                              break;
--
--                      case IS_DIS_PS_ENA:
--                              hdev->flags &= ~HCI_ISCAN;
--                              hdev->flags |=  HCI_PSCAN;
--                              break;
--
--                      default:
--                              hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
--                              break;
--                      };
--              }
--              hci_req_complete(hdev, status);
--              break;
--
--      default:
--              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)
--{
--      read_local_features_rp *lf;
--      read_buffer_size_rp *bs;
--      read_bd_addr_rp *ba;
--
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      case OCF_READ_LOCAL_FEATURES:
--              lf = (read_local_features_rp *) skb->data;
--
--              if (lf->status) {
--                      DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
--                      break;
--              }
--
--              memcpy(hdev->features, lf->features, sizeof(hdev->features));
--
--              /* Adjust default settings according to features 
--               * supported by device. */
--              if (hdev->features[0] & LMP_3SLOT)
--                      hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
--
--              if (hdev->features[0] & LMP_5SLOT)
--                      hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
--
--              DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
--
--              break;
--
--      case OCF_READ_BUFFER_SIZE:
--              bs = (read_buffer_size_rp *) skb->data;
--
--              if (bs->status) {
--                      DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
--                      break;
--              }
--
--              hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
--              hdev->sco_mtu = bs->sco_mtu;
--              hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
--              hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
--
--              DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
--                  hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
--
--              break;
--
--      case OCF_READ_BD_ADDR:
--              ba = (read_bd_addr_rp *) skb->data;
--
--              if (!ba->status) {
--                      bacpy(&hdev->bdaddr, &ba->bdaddr);
--              } else {
--                      DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
--              }
--
--              hci_req_complete(hdev, ba->status);
--              break;
--
--      default:
--              DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
--              break;
--      };
--}
-+/* ---- HCI TX task (outgoing data) ---- */
--/* Command Status OGF LINK_CTL  */
--static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+/* HCI Connection scheduler */
-+static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
- {
--      struct hci_proto * hp;
--
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      case OCF_CREATE_CONN:
--              if (status) {
--                      create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
--
--                      if (!cc)
--                              break;
-+      struct conn_hash *h = &hdev->conn_hash;
-+      struct hci_conn  *conn = NULL;
-+      int num = 0, min = ~0;
-+        struct list_head *p;
--                      DBG("%s Create connection error: status 0x%x %s", hdev->name,
--                          status, batostr(&cc->bdaddr));
-+      /* We don't have to lock device here. Connections are always 
-+       * added and removed with TX task disabled. */
-+      list_for_each(p, &h->list) {
-+              struct hci_conn *c;
-+              c = list_entry(p, struct hci_conn, list);
--                      /* Notify upper protocols */
--                      if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
--                              tasklet_disable(&hdev->tx_task);
--                              hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
--                              tasklet_enable(&hdev->tx_task);
--                      }
--              }
--              break;
-+              if (c->type != type || c->state != BT_CONNECTED
-+                              || skb_queue_empty(&c->data_q))
-+                      continue;
-+              num++;
--      case OCF_INQUIRY:
--              if (status) {
--                      DBG("%s Inquiry error: status 0x%x", hdev->name, status);
--                      hci_req_complete(hdev, status);
-+              if (c->sent < min) {
-+                      min  = c->sent;
-+                      conn = c;
-               }
--              break;
--
--      default:
--              DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
--              break;
--      };
--}
--
--/* Command Status OGF LINK_POLICY */
--static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      default:
--              DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
--              break;
--      };
--}
--
--/* Command Status OGF HOST_CTL */
--static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
--{
--      DBG("%s ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      default:
--              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)
--{
--      DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
--
--      switch (ocf) {
--      default:
--              DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
--              break;
--      };
--}
--
--/* Inquiry Complete */
--static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
--      __u8 status = *((__u8 *) skb->data);
--
--      DBG("%s status %d", hdev->name, status);
--
--      hci_req_complete(hdev, status);
--}
--
--/* Inquiry Result */
--static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
--{
--      inquiry_info *info = (inquiry_info *) (skb->data + 1);
--      int num_rsp = *((__u8 *) skb->data);
-+      }
--      DBG("%s num_rsp %d", hdev->name, num_rsp);
-+      if (conn) {
-+              int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
-+              int q = cnt / num;
-+              *quote = q ? q : 1;
-+      } else
-+              *quote = 0;
--      for (; num_rsp; num_rsp--)
--              inquiry_cache_update(&hdev->inq_cache, info++);
-+      BT_DBG("conn %p quote %d", conn, *quote);
-+      return conn;
- }
--/* Connect Request */
--static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static inline void hci_acl_tx_to(struct hci_dev *hdev)
- {
--      evt_conn_request *cr = (evt_conn_request *) skb->data;
--      struct hci_proto *hp;
--      accept_conn_req_cp ac;
--      int accept = 0;
-+      struct conn_hash *h = &hdev->conn_hash;
-+      struct list_head *p;
-+      struct hci_conn  *c;
--      DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
-+      BT_ERR("%s ACL tx timeout", hdev->name);
--      /* Notify upper protocols */
--      if (cr->link_type == ACL_LINK) {
--              /* ACL link notify L2CAP */
--              if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
--                      tasklet_disable(&hdev->tx_task);
--                      accept = hp->connect_ind(hdev, &cr->bdaddr);
--                      tasklet_enable(&hdev->tx_task);
-+      /* Kill stalled connections */
-+      list_for_each(p, &h->list) {
-+              c = list_entry(p, struct hci_conn, list);
-+              if (c->type == ACL_LINK && c->sent) {
-+                      BT_ERR("%s killing stalled ACL connection %s",
-+                              hdev->name, batostr(&c->dst));
-+                      hci_acl_disconn(c, 0x13);
-               }
--      } else {
--              /* SCO link (no notification) */
--              /* FIXME: Should be accept it here or let the requester (app) accept it ? */
--              accept = 1;
--      }
--
--      if (accept) {
--              /* Connection accepted by upper layer */
--              bacpy(&ac.bdaddr, &cr->bdaddr);
--              ac.role = 0x01; /* Remain slave */
--              hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
--      } else {
--              /* Connection rejected by upper layer */
--              /* FIXME: 
--               * Should we use HCI reject here ?
--               */
--              return;
-       }
- }
--/* Connect Complete */
--static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static inline void hci_sched_acl(struct hci_dev *hdev)
- {
--      evt_conn_complete *cc = (evt_conn_complete *) skb->data;
--      struct hci_conn *conn = NULL;
--      struct hci_proto *hp;
-+      struct hci_conn *conn;
-+      struct sk_buff *skb;
-+      int quote;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", hdev->name);
--      tasklet_disable(&hdev->tx_task);
-+      /* ACL tx timeout must be longer than maximum
-+       * link supervision timeout (40.9 seconds) */
-+      if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
-+              hci_acl_tx_to(hdev);
--      if (!cc->status)
--              conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
-+      while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-+              while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+                      BT_DBG("skb %p len %d", skb, skb->len);
-+                      hci_send_frame(skb);
-+                      hdev->acl_last_tx = jiffies;
--      /* Notify upper protocols */
--      if (cc->link_type == ACL_LINK) {
--              /* ACL link notify L2CAP layer */
--              if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
--                      hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
--      } else {
--              /* SCO link (no notification) */
-+                      hdev->acl_cnt--;
-+                      conn->sent++;
-+              }
-       }
--
--      tasklet_enable(&hdev->tx_task);
- }
--/* Disconnect Complete */
--static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+/* Schedule SCO */
-+static inline void hci_sched_sco(struct hci_dev *hdev)
- {
--      evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
--      struct hci_conn *conn = NULL;
--      struct hci_proto *hp;
--      __u16 handle = __le16_to_cpu(dc->handle);
-+      struct hci_conn *conn;
-+      struct sk_buff *skb;
-+      int quote;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", hdev->name);
--      if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
--              tasklet_disable(&hdev->tx_task);
-+      while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
-+              while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-+                      BT_DBG("skb %p len %d", skb, skb->len);
-+                      hci_send_frame(skb);
--              /* Notify upper protocols */
--              if (conn->type == ACL_LINK) {
--                      /* ACL link notify L2CAP layer */
--                      if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
--                              hp->disconn_ind(conn, dc->reason);
--              } else {
--                      /* SCO link (no notification) */
-+                      conn->sent++;
-+                      if (conn->sent == ~0)
-+                              conn->sent = 0;
-               }
--
--              hci_conn_del(hdev, conn);
--
--              tasklet_enable(&hdev->tx_task);
-       }
- }
--/* Number of completed packets */
--static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+static void hci_tx_task(unsigned long arg)
- {
--      evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
--      __u16 *ptr;
--      int i;
--
--      skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
--
--      DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+      struct hci_dev *hdev = (struct hci_dev *) arg;
-+      struct sk_buff *skb;
--      if (skb->len < nc->num_hndl * 4) {
--              DBG("%s bad parameters", hdev->name);
--              return;
--      }
-+      read_lock(&hci_task_lock);
--      tasklet_disable(&hdev->tx_task);
-+      BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
--      for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
--              struct hci_conn *conn;
--              __u16 handle, count;
-+      /* Schedule queues and send stuff to HCI driver */
--              handle = __le16_to_cpu(get_unaligned(ptr++));
--              count  = __le16_to_cpu(get_unaligned(ptr++));
-+      hci_sched_acl(hdev);
--              hdev->acl_cnt += count;
-+      hci_sched_sco(hdev);
--              if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
--                      conn->sent -= count;
--      }
-+      /* Send next queued raw (unknown type) packet */
-+      while ((skb = skb_dequeue(&hdev->raw_q)))
-+              hci_send_frame(skb);
--      tasklet_enable(&hdev->tx_task);
--      
--      hci_sched_tx(hdev);
-+      read_unlock(&hci_task_lock);
- }
--static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
--{
--      hci_event_hdr *he = (hci_event_hdr *) skb->data;
--      evt_cmd_status *cs;
--      evt_cmd_complete *ec;
--      __u16 opcode, ocf, ogf;
--
--      skb_pull(skb, HCI_EVENT_HDR_SIZE);
--
--      DBG("%s evt 0x%x", hdev->name, he->evt);
--
--      switch (he->evt) {
--      case EVT_NUM_COMP_PKTS:
--              hci_num_comp_pkts_evt(hdev, skb);
--              break;
--
--      case EVT_INQUIRY_COMPLETE:
--              hci_inquiry_complete_evt(hdev, skb);
--              break;
--
--      case EVT_INQUIRY_RESULT:
--              hci_inquiry_result_evt(hdev, skb);
--              break;
--
--      case EVT_CONN_REQUEST:
--              hci_conn_request_evt(hdev, skb);
--              break;
--
--      case EVT_CONN_COMPLETE:
--              hci_conn_complete_evt(hdev, skb);
--              break;
--
--      case EVT_DISCONN_COMPLETE:
--              hci_disconn_complete_evt(hdev, skb);
--              break;
--
--      case EVT_CMD_STATUS:
--              cs = (evt_cmd_status *) skb->data;
--              skb_pull(skb, EVT_CMD_STATUS_SIZE);
--                              
--              opcode = __le16_to_cpu(cs->opcode);
--              ogf = cmd_opcode_ogf(opcode);
--              ocf = cmd_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:
--                      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);
--              }
--              break;
--
--      case EVT_CMD_COMPLETE:
--              ec = (evt_cmd_complete *) skb->data;
--              skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
--
--              opcode = __le16_to_cpu(ec->opcode);
--              ogf = cmd_opcode_ogf(opcode);
--              ocf = cmd_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 OGF_LINK_CTL:
--                      hci_cc_link_ctl(hdev, ocf, skb);
--                      break;
--
--              case OGF_LINK_POLICY:
--                      hci_cc_link_policy(hdev, ocf, skb);
--                      break;
--
--              default:
--                      DBG("%s Command Completed OGF %x", hdev->name, ogf);
--                      break;
--              };
--
--              if (ec->ncmd) {
--                      atomic_set(&hdev->cmd_cnt, 1);
--                      if (!skb_queue_empty(&hdev->cmd_q))
--                              hci_sched_cmd(hdev);
--              }
--              break;
--      };
--
--      kfree_skb(skb);
--      hdev->stat.evt_rx++;
--}
-+/* ----- HCI RX task (incomming data proccessing) ----- */
- /* ACL data packet */
- static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
-@@ -1867,51 +1253,86 @@
-       flags  = acl_flags(handle);
-       handle = acl_handle(handle);
--      DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
-+      BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
--      if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
-+      hdev->stat.acl_rx++;
-+
-+      hci_dev_lock(hdev);
-+      conn = conn_hash_lookup_handle(hdev, handle);
-+      hci_dev_unlock(hdev);
-+      
-+      if (conn) {
-               register struct hci_proto *hp;
-               /* Send to upper protocol */
--              if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
-+              if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
-                       hp->recv_acldata(conn, skb, flags);
--                      goto sent;
-+                      return;
-               }
-       } else {
--              ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
-+              BT_ERR("%s ACL packet for unknown connection handle %d", 
-+                      hdev->name, handle);
-       }
-       kfree_skb(skb);
--sent:
--      hdev->stat.acl_rx++;
- }
- /* SCO data packet */
- static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
- {
--      DBG("%s len %d", hdev->name, skb->len);
-+      hci_sco_hdr *sh = (void *) skb->data;
-+      struct hci_conn *conn;
-+      __u16 handle;
-+
-+      skb_pull(skb, HCI_SCO_HDR_SIZE);
-+
-+      handle = __le16_to_cpu(sh->handle);
-+
-+      BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
--      kfree_skb(skb);
-       hdev->stat.sco_rx++;
-+
-+      hci_dev_lock(hdev);
-+      conn = conn_hash_lookup_handle(hdev, handle);
-+      hci_dev_unlock(hdev);
-+      
-+      if (conn) {
-+              register struct hci_proto *hp;
-+
-+              /* Send to upper protocol */
-+              if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
-+                      hp->recv_scodata(conn, skb);
-+                      return;
-+              }
-+      } else {
-+              BT_ERR("%s SCO packet for unknown connection handle %d", 
-+                      hdev->name, handle);
-+      }
-+
-+      kfree_skb(skb);
- }
--/* ----- HCI tasks ----- */
- void hci_rx_task(unsigned long arg)
- {
-       struct hci_dev *hdev = (struct hci_dev *) arg;
-       struct sk_buff *skb;
--      DBG("%s", hdev->name);
-+      BT_DBG("%s", hdev->name);
-       read_lock(&hci_task_lock);
-       while ((skb = skb_dequeue(&hdev->rx_q))) {
--              if (hdev->flags & HCI_SOCK) {
-+              if (atomic_read(&hdev->promisc)) {
-                       /* Send copy to the sockets */
-                       hci_send_to_sock(hdev, skb);
-               }
--              if (hdev->flags & HCI_INIT) {
-+              if (test_bit(HCI_RAW, &hdev->flags)) {
-+                      kfree_skb(skb);
-+                      continue;
-+              }
-+
-+              if (test_bit(HCI_INIT, &hdev->flags)) {
-                       /* Don't process data packets in this states. */
-                       switch (skb->pkt_type) {
-                       case HCI_ACLDATA_PKT:
-@@ -1921,64 +1342,43 @@
-                       };
-               }
--              if (hdev->flags & HCI_NORMAL) {
--                      /* Process frame */
--                      switch (skb->pkt_type) {
--                      case HCI_EVENT_PKT:
--                              hci_event_packet(hdev, skb);
--                              break;
-+              /* Process frame */
-+              switch (skb->pkt_type) {
-+              case HCI_EVENT_PKT:
-+                      hci_event_packet(hdev, skb);
-+                      break;
--                      case HCI_ACLDATA_PKT:
--                              DBG("%s ACL data packet", hdev->name);
--                              hci_acldata_packet(hdev, skb);
--                              break;
-+              case HCI_ACLDATA_PKT:
-+                      BT_DBG("%s ACL data packet", hdev->name);
-+                      hci_acldata_packet(hdev, skb);
-+                      break;
--                      case HCI_SCODATA_PKT:
--                              DBG("%s SCO data packet", hdev->name);
--                              hci_scodata_packet(hdev, skb);
--                              break;
-+              case HCI_SCODATA_PKT:
-+                      BT_DBG("%s SCO data packet", hdev->name);
-+                      hci_scodata_packet(hdev, skb);
-+                      break;
--                      default:
--                              kfree_skb(skb);
--                              break;
--                      };
--              } else {
-+              default:
-                       kfree_skb(skb);
-+                      break;
-               }
-       }
-       read_unlock(&hci_task_lock);
- }
--static void hci_tx_task(unsigned long arg)
--{
--      struct hci_dev *hdev = (struct hci_dev *) arg;
--      struct sk_buff *skb;
--
--      read_lock(&hci_task_lock);
--
--      DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
--
--      /* Schedule queues and send stuff to HCI driver */
--
--      hci_sched_acl(hdev);
--
--      hci_sched_sco(hdev);
--
--      /* Send next queued raw (unknown type) packet */
--      while ((skb = skb_dequeue(&hdev->raw_q)))
--              hci_send_frame(skb);
--
--      read_unlock(&hci_task_lock);
--}
--
- static void hci_cmd_task(unsigned long arg)
- {
-       struct hci_dev *hdev = (struct hci_dev *) arg;
-       struct sk_buff *skb;
--      DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-+      BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
-+      if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
-+              BT_ERR("%s command tx timeout", hdev->name);
-+              atomic_set(&hdev->cmd_cnt, 1);
-+      }
-+      
-       /* Send queued commands */
-       if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
-               if (hdev->sent_cmd)
-@@ -1987,6 +1387,7 @@
-               if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
-                       atomic_dec(&hdev->cmd_cnt);
-                       hci_send_frame(skb);
-+                      hdev->cmd_last_tx = jiffies;
-               } else {
-                       skb_queue_head(&hdev->cmd_q, skb);
-                       hci_sched_cmd(hdev);
-@@ -1994,33 +1395,10 @@
-       }
- }
--/* Receive frame from HCI drivers */
--int hci_recv_frame(struct sk_buff *skb)
--{
--      struct hci_dev *hdev = (struct hci_dev *) skb->dev;
--
--      if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
--              kfree_skb(skb);
--              return -1;
--      }
--
--      DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
--
--      /* Incomming skb */
--      bluez_cb(skb)->incomming = 1;
--
--      /* Queue frame for rx task */
--      skb_queue_tail(&hdev->rx_q, skb);
--      hci_sched_rx(hdev);
--
--      return 0;
--}
-+/* ---- Initialization ---- */
- int hci_core_init(void)
- {
--      /* Init locks */
--      spin_lock_init(&hdev_list_lock);
--
-       return 0;
- }
-@@ -2028,5 +1406,3 @@
- {
-       return 0;
- }
--
--MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/hci_event.c    2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,910 @@
-+/* 
-+   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.
-+*/
-+
-+/*
-+ * HCI Events.
-+ *
-+ * $Id: hci_event.c,v 1.4 2002/07/27 18:14:38 maxk Exp $
-+ */
-+
-+#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/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/notifier.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+
-+#ifndef HCI_CORE_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+/* 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)
-+{
-+      __u8 status;
-+
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      switch (ocf) {
-+      case OCF_INQUIRY_CANCEL:
-+              status = *((__u8 *) skb->data);
-+
-+              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);
-+              }
-+              break;
-+
-+      default:
-+              BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
-+              break;
-+      };
-+}
-+
-+/* Command Complete OGF LINK_POLICY  */
-+static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+      struct hci_conn *conn;
-+      role_discovery_rp *rd;
-+
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      switch (ocf) {
-+      case OCF_ROLE_DISCOVERY: 
-+              rd = (void *) skb->data;
-+
-+              if (rd->status)
-+                      break;
-+              
-+              hci_dev_lock(hdev);
-+      
-+              conn = 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;
-+              }
-+                      
-+              hci_dev_unlock(hdev);
-+              break;
-+
-+      default:
-+              BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
-+                              hdev->name, ocf);
-+              break;
-+      };
-+}
-+
-+/* Command Complete OGF HOST_CTL  */
-+static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
-+{
-+      __u8 status, param;
-+      void *sent;
-+
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      switch (ocf) {
-+      case OCF_RESET:
-+              status = *((__u8 *) skb->data);
-+              hci_req_complete(hdev, status);
-+              break;
-+
-+      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;
-+
-+      case OCF_WRITE_AUTH_ENABLE:
-+              sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
-+              if (!sent)
-+                      break;
-+
-+              status = *((__u8 *) skb->data);
-+              param  = *((__u8 *) 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;
-+
-+      case OCF_WRITE_ENCRYPT_MODE:
-+              sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
-+              if (!sent)
-+                      break;
-+
-+              status = *((__u8 *) skb->data);
-+              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;
-+
-+      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;
-+
-+      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;
-+
-+      case OCF_WRITE_SCAN_ENABLE:
-+              sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
-+              if (!sent)
-+                      break;
-+              status = *((__u8 *) skb->data);
-+              param  = *((__u8 *) sent);
-+
-+              BT_DBG("param 0x%x", param);
-+
-+              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 (param & SCAN_PAGE) 
-+                              set_bit(HCI_PSCAN, &hdev->flags);
-+              }
-+              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)
-+{
-+      read_local_features_rp *lf;
-+      read_buffer_size_rp *bs;
-+      read_bd_addr_rp *ba;
-+
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      switch (ocf) {
-+      case OCF_READ_LOCAL_FEATURES:
-+              lf = (read_local_features_rp *) skb->data;
-+
-+              if (lf->status) {
-+                      BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
-+                      break;
-+              }
-+
-+              memcpy(hdev->features, lf->features, sizeof(hdev->features));
-+
-+              /* Adjust default settings according to features 
-+               * supported by device. */
-+              if (hdev->features[0] & LMP_3SLOT)
-+                      hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
-+
-+              if (hdev->features[0] & LMP_5SLOT)
-+                      hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
-+
-+              if (hdev->features[1] & LMP_HV2)
-+                      hdev->pkt_type |= (HCI_HV2);
-+
-+              if (hdev->features[1] & LMP_HV3)
-+                      hdev->pkt_type |= (HCI_HV3);
-+
-+              BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
-+
-+              break;
-+
-+      case OCF_READ_BUFFER_SIZE:
-+              bs = (read_buffer_size_rp *) skb->data;
-+
-+              if (bs->status) {
-+                      BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
-+                      hci_req_complete(hdev, bs->status);
-+                      break;
-+              }
-+
-+              hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
-+              hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
-+              hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
-+              hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
-+
-+              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;
-+
-+      case OCF_READ_BD_ADDR:
-+              ba = (read_bd_addr_rp *) skb->data;
-+
-+              if (!ba->status) {
-+                      bacpy(&hdev->bdaddr, &ba->bdaddr);
-+              } else {
-+                      BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
-+              }
-+
-+              hci_req_complete(hdev, ba->status);
-+              break;
-+
-+      default:
-+              BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
-+              break;
-+      };
-+}
-+
-+/* Command Status OGF LINK_CTL  */
-+static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
-+{
-+      struct hci_conn *conn;
-+      create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
-+
-+      if (!cc)
-+              return;
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
-+
-+      BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, 
-+                      status, batostr(&cc->bdaddr), conn);
-+
-+      if (status) {
-+              if (conn) {
-+                      conn->state = BT_CLOSED;
-+                      hci_proto_connect_cfm(conn, status);
-+                      hci_conn_del(conn);
-+              }
-+      } else {
-+              if (!conn) {
-+                      conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
-+                      if (conn) {
-+                              conn->out = 1;
-+                              conn->link_mode |= HCI_LM_MASTER;
-+                      } else
-+                              BT_ERR("No memmory for new connection");
-+              }
-+      }
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __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;
-+                      add_sco_cp *cp = hci_sent_cmd_data(hdev, 
-+                                              OGF_LINK_CTL, OCF_ADD_SCO);
-+                      __u16 handle;
-+
-+                      if (!cp)
-+                              break;
-+
-+                      handle = __le16_to_cpu(cp->handle);
-+
-+                      BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
-+
-+                      hci_dev_lock(hdev);
-+      
-+                      acl = conn_hash_lookup_handle(hdev, handle);
-+                      if (acl && (sco = acl->link)) {
-+                              sco->state = BT_CLOSED;
-+                              hci_proto_connect_cfm(sco, status);
-+                              hci_conn_del(sco);
-+                      }
-+
-+                      hci_dev_unlock(hdev);
-+              }
-+              break;
-+
-+      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;
-+
-+      default:
-+              BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
-+                      hdev->name, ocf, status);
-+              break;
-+      };
-+}
-+
-+/* Command Status OGF LINK_POLICY */
-+static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      switch (ocf) {
-+      default:
-+              BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
-+              break;
-+      };
-+}
-+
-+/* Command Status OGF HOST_CTL */
-+static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
-+{
-+      BT_DBG("%s ocf 0x%x", hdev->name, ocf);
-+
-+      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);
-+
-+      BT_DBG("%s status %d", hdev->name, status);
-+
-+      clear_bit(HCI_INQUIRY, &hdev->flags);
-+      hci_req_complete(hdev, status);
-+}
-+
-+/* Inquiry Result */
-+static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      inquiry_info *info = (inquiry_info *) (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--)
-+              inquiry_cache_update(hdev, info++);
-+      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)
-+{
-+      inquiry_info_with_rssi *info = (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--) {
-+              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 */
-+static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_conn_request *cr = (evt_conn_request *) skb->data;
-+      int mask = hdev->link_mode;
-+
-+      BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
-+                      batostr(&cr->bdaddr), cr->link_type);
-+
-+      mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
-+
-+      if (mask & HCI_LM_ACCEPT) {
-+              /* Connection accepted */
-+              struct hci_conn *conn;
-+              accept_conn_req_cp ac;
-+
-+              hci_dev_lock(hdev);
-+              conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
-+              if (!conn) {
-+                      if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
-+                              BT_ERR("No memmory for new connection");
-+                              hci_dev_unlock(hdev);
-+                              return;
-+                      }
-+              }
-+              conn->state = BT_CONNECT;
-+              hci_dev_unlock(hdev);
-+
-+              bacpy(&ac.bdaddr, &cr->bdaddr);
-+      
-+              if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
-+                      ac.role = 0x00; /* Become master */
-+              else
-+                      ac.role = 0x01; /* Remain slave */
-+
-+              hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, 
-+                              ACCEPT_CONN_REQ_CP_SIZE, &ac);
-+      } else {
-+              /* Connection rejected */
-+              reject_conn_req_cp rc;
-+
-+              bacpy(&rc.bdaddr, &cr->bdaddr);
-+              rc.reason = 0x0f;
-+              hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
-+                              REJECT_CONN_REQ_CP_SIZE, &rc);
-+      }
-+}
-+
-+/* Connect Complete */
-+static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_conn_complete *cc = (evt_conn_complete *) skb->data;
-+      struct hci_conn *conn = NULL;
-+
-+      BT_DBG("%s", hdev->name);
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
-+      if (!conn) {
-+              hci_dev_unlock(hdev);
-+              return;
-+      }
-+
-+      if (!cc->status) {
-+              conn->handle = __le16_to_cpu(cc->handle);
-+              conn->state  = BT_CONNECTED;
-+
-+              if (test_bit(HCI_AUTH, &hdev->flags))
-+                      conn->link_mode |= HCI_LM_AUTH;
-+              
-+              if (test_bit(HCI_ENCRYPT, &hdev->flags))
-+                      conn->link_mode |= HCI_LM_ENCRYPT;
-+
-+
-+              /* Set link policy */
-+              if (conn->type == ACL_LINK && hdev->link_policy) {
-+                      write_link_policy_cp lp;
-+                      lp.handle = cc->handle;
-+                      lp.policy = __cpu_to_le16(hdev->link_policy);
-+                      hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
-+                              WRITE_LINK_POLICY_CP_SIZE, &lp);
-+              }
-+
-+              /* Set packet type for incomming connection */
-+              if (!conn->out) {
-+                      change_conn_ptype_cp cp;
-+                      cp.handle = cc->handle;
-+                      cp.pkt_type = (conn->type == ACL_LINK) ? 
-+                              __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,
-+                              CHANGE_CONN_PTYPE_CP_SIZE, &cp);
-+              }
-+      } else
-+              conn->state = BT_CLOSED;
-+
-+      if (conn->type == ACL_LINK) {
-+              struct hci_conn *sco = conn->link;
-+              if (sco) {
-+                      if (!cc->status)
-+                              hci_add_sco(sco, conn->handle);
-+                      else {
-+                              hci_proto_connect_cfm(sco, cc->status);
-+                              hci_conn_del(sco);
-+                      }
-+              }
-+      }
-+
-+      hci_proto_connect_cfm(conn, cc->status);
-+      if (cc->status)
-+              hci_conn_del(conn);
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+/* Disconnect Complete */
-+static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
-+      struct hci_conn *conn = NULL;
-+      __u16 handle = __le16_to_cpu(dc->handle);
-+
-+      BT_DBG("%s status %d", hdev->name, dc->status);
-+
-+      if (dc->status)
-+              return;
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_handle(hdev, handle);
-+      if (conn) {
-+              conn->state = BT_CLOSED;
-+              hci_proto_disconn_ind(conn, dc->reason);
-+              hci_conn_del(conn);
-+      }
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+/* Number of completed packets */
-+static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
-+      __u16 *ptr;
-+      int i;
-+
-+      skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
-+
-+      BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
-+
-+      if (skb->len < nc->num_hndl * 4) {
-+              BT_DBG("%s bad parameters", hdev->name);
-+              return;
-+      }
-+
-+      tasklet_disable(&hdev->tx_task);
-+
-+      for (i = 0, ptr = (__u16 *) skb->data; i < nc->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 = conn_hash_lookup_handle(hdev, handle);
-+              if (conn) {
-+                      conn->sent -= count;
-+
-+                      if (conn->type == SCO_LINK) {
-+                              if ((hdev->sco_cnt += count) > hdev->sco_pkts)
-+                                      hdev->sco_cnt = hdev->sco_pkts;
-+                      } else {
-+                              if ((hdev->acl_cnt += count) > hdev->acl_pkts)
-+                                      hdev->acl_cnt = hdev->acl_pkts;
-+                      }
-+              }
-+      }
-+      hci_sched_tx(hdev);
-+
-+      tasklet_enable(&hdev->tx_task);
-+}
-+
-+/* Role Change */
-+static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_role_change *rc = (evt_role_change *) skb->data;
-+      struct hci_conn *conn = NULL;
-+
-+      BT_DBG("%s status %d", hdev->name, rc->status);
-+
-+      if (rc->status)
-+              return;
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
-+      if (conn) {
-+              if (rc->role)
-+                      conn->link_mode &= ~HCI_LM_MASTER;
-+              else 
-+                      conn->link_mode |= HCI_LM_MASTER;
-+      }
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+/* Authentication Complete */
-+static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_auth_complete *ac = (evt_auth_complete *) skb->data;
-+      struct hci_conn *conn = NULL;
-+      __u16 handle = __le16_to_cpu(ac->handle);
-+
-+      BT_DBG("%s status %d", hdev->name, ac->status);
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_handle(hdev, handle);
-+      if (conn) {
-+              if (!ac->status)
-+                      conn->link_mode |= HCI_LM_AUTH;
-+              clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
-+
-+              hci_proto_auth_cfm(conn, ac->status);
-+              
-+              if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
-+                      if (!ac->status) {
-+                              set_conn_encrypt_cp ce;
-+                              ce.handle  = __cpu_to_le16(conn->handle);
-+                              ce.encrypt = 1;
-+                              hci_send_cmd(conn->hdev, OGF_LINK_CTL,
-+                                              OCF_SET_CONN_ENCRYPT,
-+                                              SET_CONN_ENCRYPT_CP_SIZE, &ce);
-+                      } else {
-+                              clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+                              hci_proto_encrypt_cfm(conn, ac->status);
-+                      }
-+              }
-+      }
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+/* Encryption Change */
-+static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
-+      struct hci_conn *conn = NULL;
-+      __u16 handle = __le16_to_cpu(ec->handle);
-+
-+      BT_DBG("%s status %d", hdev->name, ec->status);
-+
-+      hci_dev_lock(hdev);
-+      
-+      conn = conn_hash_lookup_handle(hdev, handle);
-+      if (conn) {
-+              if (!ec->status) {
-+                      if (ec->encrypt)
-+                              conn->link_mode |= HCI_LM_ENCRYPT;
-+                      else
-+                              conn->link_mode &= ~HCI_LM_ENCRYPT;
-+              }
-+              clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
-+              
-+              hci_proto_encrypt_cfm(conn, ec->status);
-+      }
-+
-+      hci_dev_unlock(hdev);
-+}
-+
-+void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
-+{
-+      hci_event_hdr *he = (hci_event_hdr *) skb->data;
-+      evt_cmd_status *cs;
-+      evt_cmd_complete *ec;
-+      __u16 opcode, ocf, ogf;
-+
-+      skb_pull(skb, HCI_EVENT_HDR_SIZE);
-+
-+      BT_DBG("%s evt 0x%x", hdev->name, he->evt);
-+
-+      switch (he->evt) {
-+      case EVT_NUM_COMP_PKTS:
-+              hci_num_comp_pkts_evt(hdev, skb);
-+              break;
-+
-+      case EVT_INQUIRY_COMPLETE:
-+              hci_inquiry_complete_evt(hdev, skb);
-+              break;
-+
-+      case EVT_INQUIRY_RESULT:
-+              hci_inquiry_result_evt(hdev, skb);
-+              break;
-+
-+      case EVT_INQUIRY_RESULT_WITH_RSSI:
-+              hci_inquiry_result_with_rssi_evt(hdev, skb);
-+              break;
-+
-+      case EVT_CONN_REQUEST:
-+              hci_conn_request_evt(hdev, skb);
-+              break;
-+
-+      case EVT_CONN_COMPLETE:
-+              hci_conn_complete_evt(hdev, skb);
-+              break;
-+
-+      case EVT_DISCONN_COMPLETE:
-+              hci_disconn_complete_evt(hdev, skb);
-+              break;
-+
-+      case EVT_ROLE_CHANGE:
-+              hci_role_change_evt(hdev, skb);
-+              break;
-+
-+      case EVT_AUTH_COMPLETE:
-+              hci_auth_complete_evt(hdev, skb);
-+              break;
-+
-+      case EVT_ENCRYPT_CHANGE:
-+              hci_encrypt_change_evt(hdev, skb);
-+              break;
-+
-+      case EVT_CMD_STATUS:
-+              cs = (evt_cmd_status *) skb->data;
-+              skb_pull(skb, EVT_CMD_STATUS_SIZE);
-+                              
-+              opcode = __le16_to_cpu(cs->opcode);
-+              ogf = cmd_opcode_ogf(opcode);
-+              ocf = cmd_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);
-+              }
-+              break;
-+
-+      case EVT_CMD_COMPLETE:
-+              ec = (evt_cmd_complete *) skb->data;
-+              skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
-+
-+              opcode = __le16_to_cpu(ec->opcode);
-+              ogf = cmd_opcode_ogf(opcode);
-+              ocf = cmd_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 OGF_LINK_CTL:
-+                      hci_cc_link_ctl(hdev, ocf, skb);
-+                      break;
-+
-+              case OGF_LINK_POLICY:
-+                      hci_cc_link_policy(hdev, ocf, skb);
-+                      break;
-+
-+              default:
-+                      BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
-+                      break;
-+              };
-+
-+              if (ec->ncmd) {
-+                      atomic_set(&hdev->cmd_cnt, 1);
-+                      if (!skb_queue_empty(&hdev->cmd_q))
-+                              hci_sched_cmd(hdev);
-+              }
-+              break;
-+      };
-+
-+      kfree_skb(skb);
-+      hdev->stat.evt_rx++;
-+}
-+
-+/* General internal stack event */
-+void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
-+{
-+      hci_event_hdr *eh;
-+      evt_stack_internal *si;
-+      struct sk_buff *skb;
-+      int size;
-+      void *ptr;
-+
-+      size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
-+      skb  = bluez_skb_alloc(size, GFP_ATOMIC);
-+      if (!skb)
-+              return;
-+
-+      ptr = skb_put(skb, size);
-+
-+      eh = ptr;
-+              eh->evt  = EVT_STACK_INTERNAL;
-+      eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
-+      ptr += HCI_EVENT_HDR_SIZE;
-+
-+      si = ptr;
-+      si->type = type;
-+      memcpy(si->data, data, dlen);
-+      
-+      skb->pkt_type = HCI_EVENT_PKT;
-+      skb->dev = (void *) hdev;
-+      hci_send_to_sock(hdev, skb);
-+      kfree_skb(skb);
-+}
---- linux/net/bluetooth/hci_sock.c~bluetooth-2.4.18-mh11       2001-09-07 18:28:38.000000000 +0200
-+++ linux/net/bluetooth/hci_sock.c     2004-01-25 23:37:39.000000000 +0100
-@@ -25,7 +25,7 @@
- /*
-  * BlueZ HCI socket layer.
-  *
-- * $Id: hci_sock.c,v 1.9 2001/08/05 06:02:16 maxk Exp $
-+ * $Id: hci_sock.c,v 1.5 2002/07/22 20:32:54 maxk Exp $
-  */
- #include <linux/config.h>
-@@ -49,45 +49,54 @@
- #include <asm/system.h>
- #include <asm/uaccess.h>
-+#include <asm/unaligned.h>
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
- #ifndef HCI_SOCK_DEBUG
--#undef  DBG
--#define DBG( A... )
-+#undef  BT_DBG
-+#define BT_DBG( A... )
- #endif
--/* HCI socket interface */
-+/* ----- HCI socket interface ----- */
-+
-+/* Security filter */
-+static struct hci_sec_filter hci_sec_filter = {
-+      /* Packet types */
-+      0x10,
-+      /* Events */
-+      { 0x1000d9fe, 0x0000300c },
-+      /* Commands */
-+      {
-+              { 0x0 },
-+              /* OGF_LINK_CTL */
-+              { 0xbe000006, 0x00000001, 0x0000, 0x00 },
-+              /* OGF_LINK_POLICY */
-+              { 0x00005200, 0x00000000, 0x0000, 0x00 },
-+              /* OGF_HOST_CTL */
-+              { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
-+              /* OGF_INFO_PARAM */
-+              { 0x000002be, 0x00000000, 0x0000, 0x00 },
-+              /* OGF_STATUS_PARAM */
-+              { 0x000000ea, 0x00000000, 0x0000, 0x00 }
-+      }
-+};
- static struct bluez_sock_list hci_sk_list = {
-       lock: RW_LOCK_UNLOCKED
- };
--static struct sock *hci_sock_lookup(struct hci_dev *hdev)
--{
--      struct sock *sk;
--
--      read_lock(&hci_sk_list.lock);
--      for (sk = hci_sk_list.head; sk; sk = sk->next) {
--              if (hci_pi(sk)->hdev == hdev)
--                      break;
--      }
--      read_unlock(&hci_sk_list.lock);
--      return sk;
--}
--
- /* Send frame to RAW socket */
- void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
- {
-       struct sock * sk;
--      DBG("hdev %p len %d", hdev, skb->len);
-+      BT_DBG("hdev %p len %d", hdev, skb->len);
-       read_lock(&hci_sk_list.lock);
-       for (sk = hci_sk_list.head; sk; sk = sk->next) {
--              struct hci_filter *flt; 
-+              struct hci_filter *flt;
-               struct sk_buff *nskb;
-               if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
-@@ -100,13 +109,19 @@
-               /* Apply filter */
-               flt = &hci_pi(sk)->filter;
--              if (!test_bit(skb->pkt_type, &flt->type_mask))
-+              if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
-                       continue;
-               if (skb->pkt_type == HCI_EVENT_PKT) {
--                      register int evt = (*(__u8 *)skb->data & 63);
-+                      register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
-+                      
-+                      if (!hci_test_bit(evt, &flt->event_mask))
-+                              continue;
--                      if (!test_bit(evt, &flt->event_mask))
-+                      if (flt->opcode && ((evt == EVT_CMD_COMPLETE && 
-+                                      flt->opcode != *(__u16 *)(skb->data + 3)) ||
-+                                      (evt == EVT_CMD_STATUS && 
-+                                      flt->opcode != *(__u16 *)(skb->data + 4))))
-                               continue;
-               }
-@@ -116,8 +131,8 @@
-               /* Put type byte before the data */
-               memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
--              skb_queue_tail(&sk->receive_queue, nskb);
--              sk->data_ready(sk, nskb->len);
-+              if (sock_queue_rcv_skb(sk, nskb))
-+                      kfree_skb(nskb);
-       }
-       read_unlock(&hci_sk_list.lock);
- }
-@@ -127,7 +142,7 @@
-       struct sock *sk = sock->sk;
-       struct hci_dev *hdev = hci_pi(sk)->hdev;
--      DBG("sock %p sk %p", sock, sk);
-+      BT_DBG("sock %p sk %p", sock, sk);
-       if (!sk)
-               return 0;
-@@ -135,9 +150,7 @@
-       bluez_sock_unlink(&hci_sk_list, sk);
-       if (hdev) {
--              if (!hci_sock_lookup(hdev))
--                      hdev->flags &= ~HCI_SOCK;
--
-+              atomic_dec(&hdev->promisc);
-               hci_dev_put(hdev);
-       }
-@@ -149,24 +162,55 @@
-       sock_put(sk);
-       MOD_DEC_USE_COUNT;
--
-       return 0;
- }
--static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+/* Ioctls that require bound socket */ 
-+static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
- {
--      struct sock *sk = sock->sk;
-       struct hci_dev *hdev = hci_pi(sk)->hdev;
--      __u32 mode;
--      DBG("cmd %x arg %lx", cmd, arg);
-+      if (!hdev)
-+              return -EBADFD;
-       switch (cmd) {
--      case HCIGETINFO:
--              return hci_dev_info(arg);
-+      case HCISETRAW:
-+              if (!capable(CAP_NET_ADMIN))
-+                      return -EACCES;
-+
-+              if (arg)
-+                      set_bit(HCI_RAW, &hdev->flags);
-+              else
-+                      clear_bit(HCI_RAW, &hdev->flags);
-+
-+              return 0;
-+
-+      case HCIGETCONNINFO:
-+              return hci_get_conn_info(hdev, arg);
-+      default:
-+              if (hdev->ioctl)
-+                      return hdev->ioctl(hdev, cmd, arg);
-+              return -EINVAL;
-+      }
-+}
-+
-+static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+      struct sock *sk = sock->sk;
-+      int err;
-+
-+      BT_DBG("cmd %x arg %lx", cmd, arg);
-+
-+      switch (cmd) {
-       case HCIGETDEVLIST:
--              return hci_dev_list(arg);
-+              return hci_get_dev_list(arg);
-+
-+      case HCIGETDEVINFO:
-+              return hci_get_dev_info(arg);
-+
-+      case HCIGETCONNLIST:
-+              return hci_get_conn_list(arg);
-       case HCIDEVUP:
-               if (!capable(CAP_NET_ADMIN))
-@@ -183,48 +227,31 @@
-                       return -EACCES;
-               return hci_dev_reset(arg);
--      case HCIRESETSTAT:
-+      case HCIDEVRESTAT:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EACCES;
-               return hci_dev_reset_stat(arg);
-       case HCISETSCAN:
--              if (!capable(CAP_NET_ADMIN))
--                      return -EACCES;
--              return hci_dev_setscan(arg);
--
-       case HCISETAUTH:
--              if (!capable(CAP_NET_ADMIN))
--                      return -EACCES;
--              return hci_dev_setauth(arg);
--
--      case HCISETRAW:
--              if (!capable(CAP_NET_ADMIN))
--                      return -EACCES;
--
--              if (!hdev)
--                      return -EBADFD;
--
--              if (arg)
--                      mode = HCI_RAW;
--              else
--                      mode = HCI_NORMAL;
--
--              return hci_dev_setmode(hdev, mode);
--
-+      case HCISETENCRYPT:
-       case HCISETPTYPE:
-+      case HCISETLINKPOL:
-+      case HCISETLINKMODE:
-+      case HCISETACLMTU:
-+      case HCISETSCOMTU:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EACCES;
--              return hci_dev_setptype(arg);
-+              return hci_dev_cmd(cmd, arg);
-       case HCIINQUIRY:
-               return hci_inquiry(arg);
--      case HCIGETCONNLIST:
--              return hci_conn_list(arg);
--
-       default:
--              return -EINVAL;
-+              lock_sock(sk);
-+              err = hci_sock_bound_ioctl(sk, cmd, arg);
-+              release_sock(sk);
-+              return err;
-       };
- }
-@@ -233,28 +260,35 @@
-       struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
-       struct sock *sk = sock->sk;
-       struct hci_dev *hdev = NULL;
-+      int err = 0;
--      DBG("sock %p sk %p", sock, sk);
-+      BT_DBG("sock %p sk %p", sock, sk);
-       if (!haddr || haddr->hci_family != AF_BLUETOOTH)
-               return -EINVAL;
-+      lock_sock(sk);
-+
-       if (hci_pi(sk)->hdev) {
--              /* Already bound */
--              return 0;
-+              err = -EALREADY;
-+              goto done;
-       }
-       if (haddr->hci_dev != HCI_DEV_NONE) {
--              if (!(hdev = hci_dev_get(haddr->hci_dev)))
--                      return -ENODEV;
-+              if (!(hdev = hci_dev_get(haddr->hci_dev))) {
-+                      err = -ENODEV;
-+                      goto done;
-+              }
--              hdev->flags |= HCI_SOCK;
-+              atomic_inc(&hdev->promisc);
-       }
-       hci_pi(sk)->hdev = hdev;
-       sk->state = BT_BOUND;
--      return 0;
-+done:
-+      release_sock(sk);
-+      return err;
- }
- static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
-@@ -262,73 +296,44 @@
-       struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
-       struct sock *sk = sock->sk;
--      DBG("sock %p sk %p", sock, sk);
-+      BT_DBG("sock %p sk %p", sock, sk);
-+
-+      lock_sock(sk);
-       *addr_len = sizeof(*haddr);
-       haddr->hci_family = AF_BLUETOOTH;
-       haddr->hci_dev    = hci_pi(sk)->hdev->id;
-+      release_sock(sk);
-       return 0;
- }
--static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
--                            struct scm_cookie *scm)
--{
--      struct sock *sk = sock->sk;
--      struct hci_dev *hdev = hci_pi(sk)->hdev;
--      struct sk_buff *skb;
--      int err;
--
--      DBG("sock %p sk %p", sock, sk);
--
--      if (msg->msg_flags & MSG_OOB)
--              return -EOPNOTSUPP;
--
--      if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
--              return -EINVAL;
--
--      if (!hdev)
--              return -EBADFD;
--
--      if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
--              return err;
--
--      if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
--              kfree_skb(skb);
--              return -EFAULT;
--      }
--
--      skb->dev = (void *) hdev;
--      skb->pkt_type = *((unsigned char *) skb->data);
--      skb_pull(skb, 1);
--
--      /* Send frame to HCI core */
--      hci_send_raw(skb);
--
--      return len;
--}
--
- static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
- {
-       __u32 mask = hci_pi(sk)->cmsg_mask;
-       if (mask & HCI_CMSG_DIR)
-               put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
-+
-+      if (mask & HCI_CMSG_TSTAMP)
-+              put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
- }
-  
--static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
--                            int flags, struct scm_cookie *scm)
-+static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
- {
-       int noblock = flags & MSG_DONTWAIT;
-       struct sock *sk = sock->sk;
-       struct sk_buff *skb;
-       int copied, err;
--      DBG("sock %p sk %p", sock, sk);
-+      BT_DBG("sock %p, sk %p", sock, sk);
--      if (flags & (MSG_OOB | MSG_PEEK))
-+      if (flags & (MSG_OOB))
-               return -EOPNOTSUPP;
-+      if (sk->state == BT_CLOSED)
-+              return 0;
-+
-       if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
-               return err;
-@@ -343,28 +348,107 @@
-       skb->h.raw = skb->data;
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
--      if (hci_pi(sk)->cmsg_mask)
--              hci_sock_cmsg(sk, msg, skb);
--
-+      hci_sock_cmsg(sk, msg, skb);
-+      
-       skb_free_datagram(sk, skb);
-       return err ? : copied;
- }
-+static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+                            struct scm_cookie *scm)
-+{
-+      struct sock *sk = sock->sk;
-+      struct hci_dev *hdev;
-+      struct sk_buff *skb;
-+      int err;
-+
-+      BT_DBG("sock %p sk %p", sock, sk);
-+
-+      if (msg->msg_flags & MSG_OOB)
-+              return -EOPNOTSUPP;
-+
-+      if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
-+              return -EINVAL;
-+
-+      if (len < 4)
-+              return -EINVAL;
-+      
-+      lock_sock(sk);
-+
-+      if (!(hdev = hci_pi(sk)->hdev)) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
-+              goto done;
-+
-+      if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
-+              err = -EFAULT;
-+              goto drop;
-+      }
-+
-+      skb->pkt_type = *((unsigned char *) skb->data);
-+      skb_pull(skb, 1);
-+      skb->dev = (void *) hdev;
-+
-+      if (skb->pkt_type == HCI_COMMAND_PKT) {
-+              u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
-+              u16 ogf = cmd_opcode_ogf(opcode);
-+              u16 ocf = cmd_opcode_ocf(opcode);
-+
-+              if (((ogf > HCI_SFLT_MAX_OGF) || 
-+                              !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
-+                                      !capable(CAP_NET_RAW)) {
-+                      err = -EPERM;
-+                      goto drop;
-+              }
-+
-+              if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
-+                      skb_queue_tail(&hdev->raw_q, skb);
-+                      hci_sched_tx(hdev);
-+              } else {
-+                      skb_queue_tail(&hdev->cmd_q, skb);
-+                      hci_sched_cmd(hdev);
-+              }
-+      } else {
-+              if (!capable(CAP_NET_RAW)) {
-+                      err = -EPERM;
-+                      goto drop;
-+              }
-+
-+              skb_queue_tail(&hdev->raw_q, skb);
-+              hci_sched_tx(hdev);
-+      }
-+
-+      err = len;
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+
-+drop:
-+      kfree_skb(skb);
-+      goto done;
-+}
-+
- int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
- {
-       struct sock *sk = sock->sk;
--      struct hci_filter flt;
-+      struct hci_filter flt = { opcode: 0 };
-       int err = 0, opt = 0;
--      DBG("sk %p, opt %d", sk, optname);
-+      BT_DBG("sk %p, opt %d", sk, optname);
-       lock_sock(sk);
-       switch (optname) {
-       case HCI_DATA_DIR:
--              if (get_user(opt, (int *)optval))
--                      return -EFAULT;
-+              if (get_user(opt, (int *)optval)) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-               if (opt)
-                       hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
-@@ -372,12 +456,31 @@
-                       hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
-               break;
-+      case HCI_TIME_STAMP:
-+              if (get_user(opt, (int *)optval)) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-+
-+              if (opt)
-+                      hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
-+              else
-+                      hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
-+              break;
-+
-       case HCI_FILTER:
-               len = MIN(len, sizeof(struct hci_filter));
-               if (copy_from_user(&flt, optval, len)) {
-                       err = -EFAULT;
-                       break;
-               }
-+
-+              if (!capable(CAP_NET_RAW)) {
-+                      flt.type_mask     &= hci_sec_filter.type_mask;
-+                      flt.event_mask[0] &= hci_sec_filter.event_mask[0];
-+                      flt.event_mask[1] &= hci_sec_filter.event_mask[1];
-+              }
-+              
-               memcpy(&hci_pi(sk)->filter, &flt, len);
-               break;
-@@ -409,6 +512,16 @@
-                       return -EFAULT;
-               break;
-+      case HCI_TIME_STAMP:
-+              if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
-+                      opt = 1;
-+              else 
-+                      opt = 0;
-+
-+              if (put_user(opt, optval))
-+                      return -EFAULT;
-+              break;
-+
-       case HCI_FILTER:
-               len = MIN(len, sizeof(struct hci_filter));
-               if (copy_to_user(optval, &hci_pi(sk)->filter, len))
-@@ -446,7 +559,7 @@
- {
-       struct sock *sk;
--      DBG("sock %p", sock);
-+      BT_DBG("sock %p", sock);
-       if (sock->type != SOCK_RAW)
-               return -ESOCKTNOSUPPORT;
-@@ -464,44 +577,31 @@
-       sk->protocol = protocol;
-       sk->state    = BT_OPEN;
--      /* Initialize filter */
--      hci_pi(sk)->filter.type_mask  = (1<<HCI_EVENT_PKT);
--      hci_pi(sk)->filter.event_mask[0] = ~0L;
--      hci_pi(sk)->filter.event_mask[1] = ~0L;
--
-       bluez_sock_link(&hci_sk_list, sk);
-       MOD_INC_USE_COUNT;
--
-       return 0;
- }
- static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
- {
-       struct hci_dev *hdev = (struct hci_dev *) ptr;
--      struct sk_buff *skb;
--
--      DBG("hdev %s event %ld", hdev->name, event);
-+      evt_si_device sd;
-+      
-+      BT_DBG("hdev %s event %ld", hdev->name, event);
-       /* Send event to sockets */
--      if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
--              hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
--              evt_hci_dev_event he = { event, hdev->id };
--
--              skb->pkt_type = HCI_EVENT_PKT;
--              memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
--              memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
--
--              hci_send_to_sock(NULL, skb);
--              kfree_skb(skb);
--      }
--
-+      sd.event  = event;
-+      sd.dev_id = hdev->id;
-+      hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
-+      
-       if (event == HCI_DEV_UNREG) {
-               struct sock *sk;
-               /* Detach sockets from device */
-               read_lock(&hci_sk_list.lock);
-               for (sk = hci_sk_list.head; sk; sk = sk->next) {
-+                      bh_lock_sock(sk);
-                       if (hci_pi(sk)->hdev == hdev) {
-                               hci_pi(sk)->hdev = NULL;
-                               sk->err = EPIPE;
-@@ -510,6 +610,7 @@
-                               hci_dev_put(hdev);
-                       }
-+                      bh_unlock_sock(sk);
-               }
-               read_unlock(&hci_sk_list.lock);
-       }
-@@ -529,21 +630,19 @@
- int hci_sock_init(void)
- {
-       if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
--              ERR("Can't register HCI socket");
-+              BT_ERR("Can't register HCI socket");
-               return -EPROTO;
-       }
-       hci_register_notifier(&hci_sock_nblock);
--
-       return 0;
- }
- int hci_sock_cleanup(void)
- {
-       if (bluez_sock_unregister(BTPROTO_HCI))
--              ERR("Can't unregister HCI socket");
-+              BT_ERR("Can't unregister HCI socket");
-       hci_unregister_notifier(&hci_sock_nblock);
--
-       return 0;
- }
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/l2cap.c        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,2187 @@
-+/* 
-+   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 L2CAP core and sockets.
-+ *
-+ * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
-+ */
-+#define VERSION "2.3"
-+
-+#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/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/l2cap.h>
-+
-+#ifndef L2CAP_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops l2cap_sock_ops;
-+
-+struct bluez_sock_list l2cap_sk_list = {
-+      lock: RW_LOCK_UNLOCKED
-+};
-+
-+static int l2cap_conn_del(struct hci_conn *conn, int err);
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
-+static void l2cap_chan_del(struct sock *sk, int err);
-+static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
-+
-+static void __l2cap_sock_close(struct sock *sk, int reason);
-+static void l2cap_sock_close(struct sock *sk);
-+static void l2cap_sock_kill(struct sock *sk);
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
-+static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
-+
-+/* ----- L2CAP timers ------ */
-+static void l2cap_sock_timeout(unsigned long arg)
-+{
-+      struct sock *sk = (struct sock *) arg;
-+
-+      BT_DBG("sock %p state %d", sk, sk->state);
-+
-+      bh_lock_sock(sk);
-+      __l2cap_sock_close(sk, ETIMEDOUT);
-+      bh_unlock_sock(sk);
-+
-+      l2cap_sock_kill(sk);
-+      sock_put(sk);
-+}
-+
-+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-+{
-+      BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+      if (!mod_timer(&sk->timer, jiffies + timeout))
-+              sock_hold(sk);
-+}
-+
-+static void l2cap_sock_clear_timer(struct sock *sk)
-+{
-+      BT_DBG("sock %p state %d", sk, sk->state);
-+
-+      if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+              __sock_put(sk);
-+}
-+
-+static void l2cap_sock_init_timer(struct sock *sk)
-+{
-+      init_timer(&sk->timer);
-+      sk->timer.function = l2cap_sock_timeout;
-+      sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- L2CAP connections --------- */
-+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+      struct l2cap_conn *conn;
-+
-+      if ((conn = hcon->l2cap_data))
-+              return conn;
-+
-+      if (status)
-+              return conn;
-+
-+      if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
-+              return NULL;
-+      memset(conn, 0, sizeof(struct l2cap_conn));
-+
-+      hcon->l2cap_data = conn;
-+      conn->hcon = hcon;
-+      
-+      conn->mtu = hcon->hdev->acl_mtu;
-+      conn->src = &hcon->hdev->bdaddr;
-+      conn->dst = &hcon->dst;
-+      
-+      spin_lock_init(&conn->lock);
-+      conn->chan_list.lock = RW_LOCK_UNLOCKED;
-+
-+      BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+      MOD_INC_USE_COUNT;
-+      return conn;
-+}
-+
-+static int l2cap_conn_del(struct hci_conn *hcon, int err)
-+{
-+      struct l2cap_conn *conn;
-+      struct sock *sk;
-+
-+      if (!(conn = hcon->l2cap_data)) 
-+              return 0;
-+
-+      BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+      if (conn->rx_skb)
-+              kfree_skb(conn->rx_skb);
-+
-+      /* Kill channels */
-+      while ((sk = conn->chan_list.head)) {
-+              bh_lock_sock(sk);
-+              l2cap_chan_del(sk, err);
-+              bh_unlock_sock(sk);
-+              l2cap_sock_kill(sk);
-+      }
-+
-+      hcon->l2cap_data = NULL;
-+      kfree(conn);
-+
-+      MOD_DEC_USE_COUNT;
-+      return 0;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
-+{
-+      struct sock *sk;
-+      for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+              if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
-+                      break;
-+      }
-+      return sk;
-+}
-+
-+/* Find socket with psm and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+      struct sock *sk, *sk1 = NULL;
-+
-+      for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+              if (state && sk->state != state)
-+                      continue;
-+
-+              if (l2cap_pi(sk)->psm == psm) {
-+                      /* Exact match. */
-+                      if (!bacmp(&bluez_pi(sk)->src, src))
-+                              break;
-+
-+                      /* Closest match */
-+                      if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+                              sk1 = sk;
-+              }
-+      }
-+      return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (psm, src).
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
-+{
-+      struct sock *s;
-+      read_lock(&l2cap_sk_list.lock);
-+      s = __l2cap_get_sock_by_psm(state, psm, src);
-+      if (s) bh_lock_sock(s);
-+      read_unlock(&l2cap_sk_list.lock);
-+      return s;
-+}
-+
-+static void l2cap_sock_destruct(struct sock *sk)
-+{
-+      BT_DBG("sk %p", sk);
-+
-+      skb_queue_purge(&sk->receive_queue);
-+      skb_queue_purge(&sk->write_queue);
-+
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static void l2cap_sock_cleanup_listen(struct sock *parent)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("parent %p", parent);
-+
-+      /* Close not yet accepted channels */
-+      while ((sk = bluez_accept_dequeue(parent, NULL)))
-+              l2cap_sock_close(sk);
-+
-+      parent->state  = BT_CLOSED;
-+      parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void l2cap_sock_kill(struct sock *sk)
-+{
-+      if (!sk->zapped || sk->socket)
-+              return;
-+
-+      BT_DBG("sk %p state %d", sk, sk->state);
-+
-+      /* Kill poor orphan */
-+      bluez_sock_unlink(&l2cap_sk_list, sk);
-+      sk->dead = 1;
-+      sock_put(sk);
-+}
-+
-+/* Close socket.
-+ */
-+static void __l2cap_sock_close(struct sock *sk, int reason)
-+{
-+      BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+      switch (sk->state) {
-+      case BT_LISTEN:
-+              l2cap_sock_cleanup_listen(sk);
-+              break;
-+
-+      case BT_CONNECTED:
-+      case BT_CONFIG:
-+      case BT_CONNECT2:
-+              if (sk->type == SOCK_SEQPACKET) {
-+                      struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+                      l2cap_disconn_req req;
-+
-+                      sk->state = BT_DISCONN;
-+                      l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+                      req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+                      l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+              } else {
-+                      l2cap_chan_del(sk, reason);
-+              }
-+              break;
-+
-+      case BT_CONNECT:
-+      case BT_DISCONN:
-+              l2cap_chan_del(sk, reason);
-+              break;
-+
-+      default:
-+              sk->zapped = 1;
-+              break;
-+      };
-+}
-+
-+/* Must be called on unlocked socket. */
-+static void l2cap_sock_close(struct sock *sk)
-+{
-+      l2cap_sock_clear_timer(sk);
-+      lock_sock(sk);
-+      __l2cap_sock_close(sk, ECONNRESET);
-+      release_sock(sk);
-+      l2cap_sock_kill(sk);
-+}
-+
-+static void l2cap_sock_init(struct sock *sk, struct sock *parent)
-+{
-+      struct l2cap_pinfo *pi = l2cap_pi(sk);
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (parent) {
-+              sk->type = parent->type;
-+              pi->imtu = l2cap_pi(parent)->imtu;
-+              pi->omtu = l2cap_pi(parent)->omtu;
-+              pi->link_mode = l2cap_pi(parent)->link_mode;
-+      } else {
-+              pi->imtu = L2CAP_DEFAULT_MTU;
-+              pi->omtu = 0;
-+              pi->link_mode = 0;
-+      }
-+
-+      /* Default config options */
-+      pi->conf_mtu = L2CAP_DEFAULT_MTU;
-+      pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
-+}
-+
-+static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+      struct sock *sk;
-+
-+      if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+              return NULL;
-+
-+      bluez_sock_init(sock, sk);
-+      
-+      sk->zapped   = 0;
-+
-+      sk->destruct = l2cap_sock_destruct;
-+      sk->sndtimeo = L2CAP_CONN_TIMEOUT;
-+
-+      sk->protocol = proto;
-+      sk->state    = BT_OPEN;
-+
-+      l2cap_sock_init_timer(sk);
-+
-+      bluez_sock_link(&l2cap_sk_list, sk);
-+
-+      MOD_INC_USE_COUNT;
-+      return sk;
-+}
-+
-+static int l2cap_sock_create(struct socket *sock, int protocol)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("sock %p", sock);
-+
-+      sock->state = SS_UNCONNECTED;
-+
-+      if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
-+              return -ESOCKTNOSUPPORT;
-+
-+      if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
-+              return -EPERM;
-+      
-+      sock->ops = &l2cap_sock_ops;
-+
-+      if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
-+              return -ENOMEM;
-+
-+      l2cap_sock_init(sk, NULL);
-+      return 0;
-+}
-+
-+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
-+
-+      if (!addr || addr->sa_family != AF_BLUETOOTH)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_OPEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      write_lock_bh(&l2cap_sk_list.lock);
-+      if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
-+              err = -EADDRINUSE;
-+      } else {
-+              /* Save source address */
-+              bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
-+              l2cap_pi(sk)->psm = la->l2_psm;
-+              sk->sport = la->l2_psm;
-+              sk->state = BT_BOUND;
-+      }
-+      write_unlock_bh(&l2cap_sk_list.lock);
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_do_connect(struct sock *sk)
-+{
-+      bdaddr_t *src = &bluez_pi(sk)->src;
-+      bdaddr_t *dst = &bluez_pi(sk)->dst;
-+      struct l2cap_conn *conn;
-+      struct hci_conn   *hcon;
-+      struct hci_dev    *hdev;
-+      int err = 0;
-+
-+      BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
-+
-+      if (!(hdev = hci_get_route(dst, src)))
-+              return -EHOSTUNREACH;
-+
-+      hci_dev_lock_bh(hdev);
-+
-+      err = -ENOMEM;
-+
-+      hcon = hci_connect(hdev, ACL_LINK, dst);
-+      if (!hcon)
-+              goto done;
-+
-+      conn = l2cap_conn_add(hcon, 0);
-+      if (!conn) {
-+              hci_conn_put(hcon);
-+              goto done;
-+      }
-+
-+      err = 0;
-+
-+      /* Update source addr of the socket */
-+      bacpy(src, conn->src);
-+
-+      l2cap_chan_add(conn, sk, NULL);
-+
-+      sk->state = BT_CONNECT;
-+      l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+      if (hcon->state == BT_CONNECTED) {
-+              if (sk->type == SOCK_SEQPACKET) {
-+                      l2cap_conn_req req;
-+                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+                      req.psm  = l2cap_pi(sk)->psm;
-+                      l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
-+              } else {
-+                      l2cap_sock_clear_timer(sk);
-+                      sk->state = BT_CONNECTED;
-+              }
-+      }
-+
-+done:
-+      hci_dev_unlock_bh(hdev);
-+      hci_dev_put(hdev);
-+      return err;
-+}
-+
-+static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      lock_sock(sk);
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-+              err = -EINVAL;
-+              goto done;
-+      }
-+
-+      if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
-+              err = -EINVAL;
-+              goto done;
-+      }
-+
-+      switch(sk->state) {
-+      case BT_CONNECT:
-+      case BT_CONNECT2:
-+      case BT_CONFIG:
-+              /* Already connecting */
-+              goto wait;
-+
-+      case BT_CONNECTED:
-+              /* Already connected */
-+              goto done;
-+
-+      case BT_OPEN:
-+      case BT_BOUND:
-+              /* Can connect */
-+              break;
-+
-+      default:
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      /* Set destination address and psm */
-+      bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
-+      l2cap_pi(sk)->psm = la->l2_psm;
-+
-+      if ((err = l2cap_do_connect(sk)))
-+              goto done;
-+
-+wait:
-+      err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+                      sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int l2cap_sock_listen(struct socket *sock, int backlog)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      if (!l2cap_pi(sk)->psm) {
-+              err = -EINVAL;
-+              goto done;
-+      }
-+
-+      sk->max_ack_backlog = backlog;
-+      sk->ack_backlog = 0;
-+      sk->state = BT_LISTEN;
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct sock *sk = sock->sk, *nsk;
-+      long timeo;
-+      int err = 0;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_LISTEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+      BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+      /* Wait for an incoming connection. (wake-one). */
-+      add_wait_queue_exclusive(sk->sleep, &wait);
-+      while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+              if (!timeo) {
-+                      err = -EAGAIN;
-+                      break;
-+              }
-+
-+              release_sock(sk);
-+              timeo = schedule_timeout(timeo);
-+              lock_sock(sk);
-+
-+              if (sk->state != BT_LISTEN) {
-+                      err = -EBADFD;
-+                      break;
-+              }
-+
-+              if (signal_pending(current)) {
-+                      err = sock_intr_errno(timeo);
-+                      break;
-+              }
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+
-+      if (err)
-+              goto done;
-+
-+      newsock->state = SS_CONNECTED;
-+
-+      BT_DBG("new socket %p", nsk);
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
-+      struct sock *sk = sock->sk;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      addr->sa_family = AF_BLUETOOTH;
-+      *len = sizeof(struct sockaddr_l2);
-+
-+      if (peer)
-+              bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
-+      else
-+              bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
-+
-+      la->l2_psm = l2cap_pi(sk)->psm;
-+      return 0;
-+}
-+
-+static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (sk->err)
-+              return sock_error(sk);
-+
-+      if (msg->msg_flags & MSG_OOB)
-+              return -EOPNOTSUPP;
-+
-+      /* Check outgoing MTU */
-+      if (len > l2cap_pi(sk)->omtu)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state == BT_CONNECTED)
-+              err = l2cap_chan_send(sk, msg, len);
-+      else
-+              err = -ENOTCONN;
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      struct l2cap_options opts;
-+      int err = 0, len;
-+      __u32 opt;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      case L2CAP_OPTIONS:
-+              len = MIN(sizeof(opts), optlen);
-+              if (copy_from_user((char *)&opts, optval, len)) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-+              l2cap_pi(sk)->imtu  = opts.imtu;
-+              l2cap_pi(sk)->omtu  = opts.omtu;
-+              break;
-+
-+      case L2CAP_LM:
-+              if (get_user(opt, (__u32 *)optval)) {
-+                      err = -EFAULT;
-+                      break;
-+              }
-+
-+              l2cap_pi(sk)->link_mode = opt;
-+              break;
-+
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      }
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      struct l2cap_options opts;
-+      struct l2cap_conninfo cinfo;
-+      int len, err = 0; 
-+
-+      if (get_user(len, optlen))
-+              return -EFAULT;
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      case L2CAP_OPTIONS:
-+              opts.imtu     = l2cap_pi(sk)->imtu;
-+              opts.omtu     = l2cap_pi(sk)->omtu;
-+              opts.flush_to = l2cap_pi(sk)->flush_to;
-+
-+              len = MIN(len, sizeof(opts));
-+              if (copy_to_user(optval, (char *)&opts, len))
-+                      err = -EFAULT;
-+
-+              break;
-+
-+      case L2CAP_LM:
-+              if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
-+                      err = -EFAULT;
-+              break;
-+
-+      case L2CAP_CONNINFO:
-+              if (sk->state != BT_CONNECTED) {
-+                      err = -ENOTCONN;
-+                      break;
-+              }
-+
-+              cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
-+
-+              len = MIN(len, sizeof(cinfo));
-+              if (copy_to_user(optval, (char *)&cinfo, len))
-+                      err = -EFAULT;
-+
-+              break;
-+
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      }
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_sock_shutdown(struct socket *sock, int how)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (!sk) return 0;
-+
-+      lock_sock(sk);
-+      if (!sk->shutdown) {
-+              sk->shutdown = SHUTDOWN_MASK;
-+              l2cap_sock_clear_timer(sk);
-+              __l2cap_sock_close(sk, 0);
-+
-+              if (sk->linger)
-+                      err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+      }
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int l2cap_sock_release(struct socket *sock)
-+{
-+      struct sock *sk = sock->sk;
-+      int err;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (!sk) return 0;
-+
-+      err = l2cap_sock_shutdown(sock, 2);
-+
-+      sock_orphan(sk);
-+      l2cap_sock_kill(sk);
-+      return err;
-+}
-+
-+/* --------- L2CAP channels --------- */
-+static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+      struct sock *s;
-+      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+              if (l2cap_pi(s)->dcid == cid)
-+                      break;
-+      }
-+      return s;
-+}
-+
-+static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+      struct sock *s;
-+      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
-+              if (l2cap_pi(s)->scid == cid)
-+                      break;
-+      }
-+      return s;
-+}
-+
-+/* Find channel with given SCID.
-+ * Returns locked socket */
-+static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
-+{
-+      struct sock *s;
-+      read_lock(&l->lock);
-+      s = __l2cap_get_chan_by_scid(l, cid);
-+      if (s) bh_lock_sock(s);
-+      read_unlock(&l->lock);
-+      return s;
-+}
-+
-+static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
-+{
-+      __u16 cid = 0x0040;
-+
-+      for (; cid < 0xffff; cid++) {
-+              if(!__l2cap_get_chan_by_scid(l, cid))
-+                      return cid;
-+      }
-+
-+      return 0;
-+}
-+
-+static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+      sock_hold(sk);
-+
-+      if (l->head)
-+              l2cap_pi(l->head)->prev_c = sk;
-+
-+      l2cap_pi(sk)->next_c = l->head;
-+      l2cap_pi(sk)->prev_c = NULL;
-+      l->head = sk;
-+}
-+
-+static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
-+{
-+      struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
-+
-+      write_lock(&l->lock);
-+      if (sk == l->head)
-+              l->head = next;
-+
-+      if (next)
-+              l2cap_pi(next)->prev_c = prev;
-+      if (prev)
-+              l2cap_pi(prev)->next_c = next;
-+      write_unlock(&l->lock);
-+
-+      __sock_put(sk);
-+}
-+
-+static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+      struct l2cap_chan_list *l = &conn->chan_list;
-+
-+      BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
-+
-+      l2cap_pi(sk)->conn = conn;
-+
-+      if (sk->type == SOCK_SEQPACKET) {
-+              /* Alloc CID for connection-oriented socket */
-+              l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
-+      } else if (sk->type == SOCK_DGRAM) {
-+              /* Connectionless socket */
-+              l2cap_pi(sk)->scid = 0x0002;
-+              l2cap_pi(sk)->dcid = 0x0002;
-+              l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+      } else {
-+              /* Raw socket can send/recv signalling messages only */
-+              l2cap_pi(sk)->scid = 0x0001;
-+              l2cap_pi(sk)->dcid = 0x0001;
-+              l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
-+      }
-+
-+      __l2cap_chan_link(l, sk);
-+
-+      if (parent)
-+              bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+      struct l2cap_chan_list *l = &conn->chan_list;
-+      write_lock(&l->lock);
-+      __l2cap_chan_add(conn, sk, parent);
-+      write_unlock(&l->lock);
-+}
-+
-+/* Delete channel. 
-+ * Must be called on the locked socket. */
-+static void l2cap_chan_del(struct sock *sk, int err)
-+{
-+      struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+      struct sock *parent = bluez_pi(sk)->parent;
-+
-+      l2cap_sock_clear_timer(sk);
-+
-+      BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+      if (conn) { 
-+              /* Unlink from channel list */
-+              l2cap_chan_unlink(&conn->chan_list, sk);
-+              l2cap_pi(sk)->conn = NULL;
-+              hci_conn_put(conn->hcon);
-+      }
-+
-+      sk->state  = BT_CLOSED;
-+      sk->zapped = 1;
-+
-+      if (err)
-+              sk->err = err;
-+
-+      if (parent)
-+              parent->data_ready(parent, 0);
-+      else
-+              sk->state_change(sk);
-+}
-+
-+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->type != SOCK_SEQPACKET) {
-+                      l2cap_sock_clear_timer(sk);
-+                      sk->state = BT_CONNECTED;
-+                      sk->state_change(sk);
-+              } else if (sk->state == BT_CONNECT) {
-+                      l2cap_conn_req req;
-+                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+                      req.psm  = l2cap_pi(sk)->psm;
-+                      l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &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->err = err;
-+      }
-+      read_unlock(&l->lock);
-+}
-+
-+static void l2cap_chan_ready(struct sock *sk)
-+{
-+      struct sock *parent = bluez_pi(sk)->parent;
-+
-+      BT_DBG("sk %p, parent %p", sk, parent);
-+
-+      l2cap_pi(sk)->conf_state = 0;
-+      l2cap_sock_clear_timer(sk);
-+
-+      if (!parent) {
-+              /* Outgoing channel.
-+               * Wake up socket sleeping on connect.
-+               */
-+              sk->state = BT_CONNECTED;
-+              sk->state_change(sk);
-+      } else {
-+              /* Incomming channel.
-+               * Wake up socket sleeping on accept.
-+               */
-+              parent->data_ready(parent, 0);
-+      }
-+}
-+
-+/* Copy frame to all raw sockets on that connection */
-+void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+      struct l2cap_chan_list *l = &conn->chan_list;
-+      struct sk_buff *nskb;
-+      struct sock * sk;
-+
-+      BT_DBG("conn %p", conn);
-+
-+      read_lock(&l->lock);
-+      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-+              if (sk->type != SOCK_RAW)
-+                      continue;
-+
-+              /* Don't send frame to the socket it came from */
-+              if (skb->sk == sk)
-+                      continue;
-+
-+              if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
-+                      continue;
-+
-+              if (sock_queue_rcv_skb(sk, nskb))
-+                      kfree_skb(nskb);
-+      }
-+      read_unlock(&l->lock);
-+}
-+
-+static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
-+{
-+      struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-+      struct sk_buff *skb, **frag;
-+      int err, hlen, count, sent=0;
-+      l2cap_hdr *lh;
-+
-+      BT_DBG("sk %p len %d", sk, len);
-+
-+      /* First fragment (with L2CAP header) */
-+      if (sk->type == SOCK_DGRAM)
-+              hlen = L2CAP_HDR_SIZE + 2;
-+      else
-+              hlen = L2CAP_HDR_SIZE;
-+
-+      count = MIN(conn->mtu - hlen, len);
-+
-+      skb = bluez_skb_send_alloc(sk, hlen + count,
-+                      msg->msg_flags & MSG_DONTWAIT, &err);
-+      if (!skb)
-+              return err;
-+
-+      /* Create L2CAP header */
-+      lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+      lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+      lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-+
-+      if (sk->type == SOCK_DGRAM)
-+              put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
-+
-+      if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+              err = -EFAULT;
-+              goto fail;
-+      }
-+
-+      sent += count;
-+      len  -= count;
-+
-+      /* Continuation fragments (no L2CAP header) */
-+      frag = &skb_shinfo(skb)->frag_list;
-+      while (len) {
-+              count = MIN(conn->mtu, len);
-+
-+              *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
-+              if (!*frag)
-+                      goto fail;
-+              
-+              if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
-+                      err = -EFAULT;
-+                      goto fail;
-+              }
-+
-+              sent += count;
-+              len  -= count;
-+
-+              frag = &(*frag)->next;
-+      }
-+
-+      if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
-+              goto fail;
-+
-+      return sent;
-+
-+fail:
-+      kfree_skb(skb);
-+      return err;
-+}
-+
-+/* --------- L2CAP signalling commands --------- */
-+static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
-+{
-+      __u8 id;
-+
-+      /* Get next available identificator.
-+       *    1 - 199 are used by kernel.
-+       *  200 - 254 are used by utilities like l2ping, etc 
-+       */
-+
-+      spin_lock(&conn->lock);
-+
-+      if (++conn->tx_ident > 199)
-+              conn->tx_ident = 1;
-+
-+      id = conn->tx_ident;
-+
-+      spin_unlock(&conn->lock);
-+
-+      return id;
-+}
-+
-+static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
-+                              __u8 code, __u8 ident, __u16 dlen, void *data)
-+{
-+      struct sk_buff *skb, **frag;
-+      l2cap_cmd_hdr *cmd;
-+      l2cap_hdr *lh;
-+      int len, count;
-+
-+      BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
-+
-+      len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
-+      count = MIN(conn->mtu, len);
-+      
-+      skb = bluez_skb_alloc(count, GFP_ATOMIC);
-+      if (!skb)
-+              return NULL;
-+
-+      lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-+      lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
-+      lh->cid = __cpu_to_le16(0x0001);
-+
-+      cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
-+      cmd->code  = code;
-+      cmd->ident = ident;
-+      cmd->len   = __cpu_to_le16(dlen);
-+
-+      if (dlen) {
-+              count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
-+              memcpy(skb_put(skb, count), data, count);
-+              data += count;
-+      }
-+
-+      len -= skb->len;
-+      
-+      /* Continuation fragments (no L2CAP header) */
-+      frag = &skb_shinfo(skb)->frag_list;
-+      while (len) {
-+              count = MIN(conn->mtu, len);
-+
-+              *frag = bluez_skb_alloc(count, GFP_ATOMIC);
-+              if (!*frag)
-+                      goto fail;
-+              
-+              memcpy(skb_put(*frag, count), data, count);
-+
-+              len  -= count;
-+              data += count;
-+              
-+              frag = &(*frag)->next;
-+      }
-+
-+      return skb;
-+
-+fail:
-+      kfree_skb(skb);
-+      return NULL;
-+}
-+
-+static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
-+{
-+      __u8 ident = l2cap_get_ident(conn);
-+      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);
-+}
-+
-+static int l2cap_send_rsp(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);
-+}
-+
-+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
-+{
-+      l2cap_conf_opt *opt = *ptr;
-+      int len;
-+
-+      len = L2CAP_CONF_OPT_SIZE + opt->len;
-+      *ptr += len;
-+
-+      *type = opt->type;
-+      *olen = opt->len;
-+
-+      switch (opt->len) {
-+      case 1:
-+              *val = *((__u8 *) opt->val);
-+              break;
-+
-+      case 2:
-+              *val = __le16_to_cpu(*((__u16 *)opt->val));
-+              break;
-+
-+      case 4:
-+              *val = __le32_to_cpu(*((__u32 *)opt->val));
-+              break;
-+
-+      default:
-+              *val = (unsigned long) opt->val;
-+              break;
-+      };
-+
-+      BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
-+      return len;
-+}
-+
-+static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
-+{
-+      int type, hint, olen; 
-+      unsigned long val;
-+      void *ptr = data;
-+
-+      BT_DBG("sk %p len %d", sk, len);
-+
-+      while (len >= L2CAP_CONF_OPT_SIZE) {
-+              len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
-+
-+              hint  = type & 0x80;
-+              type &= 0x7f;
-+
-+              switch (type) {
-+              case L2CAP_CONF_MTU:
-+                      l2cap_pi(sk)->conf_mtu = val;
-+                      break;
-+
-+              case L2CAP_CONF_FLUSH_TO:
-+                      l2cap_pi(sk)->flush_to = val;
-+                      break;
-+
-+              case L2CAP_CONF_QOS:
-+                      break;
-+              
-+              default:
-+                      if (hint)
-+                              break;
-+
-+                      /* FIXME: Reject unknown option */
-+                      break;
-+              };
-+      }
-+}
-+
-+static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
-+{
-+      register l2cap_conf_opt *opt = *ptr;
-+
-+      BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
-+
-+      opt->type = type;
-+      opt->len  = len;
-+
-+      switch (len) {
-+      case 1:
-+              *((__u8 *) opt->val)  = val;
-+              break;
-+
-+      case 2:
-+              *((__u16 *) opt->val) = __cpu_to_le16(val);
-+              break;
-+
-+      case 4:
-+              *((__u32 *) opt->val) = __cpu_to_le32(val);
-+              break;
-+
-+      default:
-+              memcpy(opt->val, (void *) val, len);
-+              break;
-+      };
-+
-+      *ptr += L2CAP_CONF_OPT_SIZE + len;
-+}
-+
-+static int l2cap_build_conf_req(struct sock *sk, void *data)
-+{
-+      struct l2cap_pinfo *pi = l2cap_pi(sk);
-+      l2cap_conf_req *req = (l2cap_conf_req *) data;
-+      void *ptr = req->data;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (pi->imtu != L2CAP_DEFAULT_MTU)
-+              l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
-+
-+      /* FIXME. Need actual value of the flush timeout */
-+      //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
-+      //   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
-+
-+      req->dcid  = __cpu_to_le16(pi->dcid);
-+      req->flags = __cpu_to_le16(0);
-+
-+      return ptr - data;
-+}
-+
-+static inline int l2cap_conf_output(struct sock *sk, void **ptr)
-+{
-+      struct l2cap_pinfo *pi = l2cap_pi(sk);
-+      int result = 0;
-+
-+      /* Configure output options and let the other side know
-+       * which ones we don't like.
-+       */
-+      if (pi->conf_mtu < pi->omtu) {
-+              l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
-+              result = L2CAP_CONF_UNACCEPT;
-+      } else {
-+              pi->omtu = pi->conf_mtu;
-+      }
-+
-+      BT_DBG("sk %p result %d", sk, result);
-+      return result;
-+}
-+
-+static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
-+{
-+      l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
-+      void *ptr = rsp->data;
-+      u16 flags = 0;
-+
-+      BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
-+
-+      if (result)
-+              *result = l2cap_conf_output(sk, &ptr);
-+      else    
-+              flags |= 0x0001;
-+
-+      rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+      rsp->result = __cpu_to_le16(result ? *result : 0);
-+      rsp->flags  = __cpu_to_le16(flags);
-+
-+      return ptr - data;
-+}
-+
-+static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      struct l2cap_chan_list *list = &conn->chan_list;
-+      l2cap_conn_req *req = (l2cap_conn_req *) data;
-+      l2cap_conn_rsp rsp;
-+      struct sock *sk, *parent;
-+      int result = 0, status = 0;
-+
-+      __u16 dcid = 0, scid = __le16_to_cpu(req->scid);
-+      __u16 psm  = req->psm;
-+
-+      BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
-+
-+      /* Check if we have socket listening on psm */
-+      parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
-+      if (!parent) {
-+              result = L2CAP_CR_BAD_PSM;
-+              goto sendresp;
-+      }
-+
-+      result = L2CAP_CR_NO_MEM;
-+
-+      /* Check for backlog size */
-+      if (parent->ack_backlog > parent->max_ack_backlog) {
-+              BT_DBG("backlog full %d", parent->ack_backlog); 
-+              goto response;
-+      }
-+
-+      sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
-+      if (!sk)
-+              goto response;
-+
-+      write_lock(&list->lock);
-+
-+      /* Check if we already have channel with that dcid */
-+      if (__l2cap_get_chan_by_dcid(list, scid)) {
-+              write_unlock(&list->lock);
-+              sk->zapped = 1;
-+              l2cap_sock_kill(sk);
-+              goto response;
-+      }
-+
-+      hci_conn_hold(conn->hcon);
-+
-+      l2cap_sock_init(sk, parent);
-+      bacpy(&bluez_pi(sk)->src, conn->src);
-+      bacpy(&bluez_pi(sk)->dst, conn->dst);
-+      l2cap_pi(sk)->psm  = psm;
-+      l2cap_pi(sk)->dcid = scid;
-+
-+      __l2cap_chan_add(conn, sk, parent);
-+      dcid = l2cap_pi(sk)->scid;
-+
-+      l2cap_sock_set_timer(sk, sk->sndtimeo);
-+
-+      /* Service level security */
-+      result = L2CAP_CR_PEND;
-+      status = L2CAP_CS_AUTHEN_PEND;
-+      sk->state = BT_CONNECT2;
-+      l2cap_pi(sk)->ident = cmd->ident;
-+      
-+      if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
-+              if (!hci_conn_encrypt(conn->hcon))
-+                      goto done;
-+      } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
-+              if (!hci_conn_auth(conn->hcon))
-+                      goto done;
-+      }
-+
-+      sk->state = BT_CONFIG;
-+      result = status = 0;
-+
-+done:
-+      write_unlock(&list->lock);
-+
-+response:
-+      bh_unlock_sock(parent);
-+
-+sendresp:
-+      rsp.scid   = __cpu_to_le16(scid);
-+      rsp.dcid   = __cpu_to_le16(dcid);
-+      rsp.result = __cpu_to_le16(result);
-+      rsp.status = __cpu_to_le16(status);
-+      l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
-+      return 0;
-+}
-+
-+static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
-+      __u16 scid, dcid, result, status;
-+      struct sock *sk;
-+      char req[128];
-+
-+      scid   = __le16_to_cpu(rsp->scid);
-+      dcid   = __le16_to_cpu(rsp->dcid);
-+      result = __le16_to_cpu(rsp->result);
-+      status = __le16_to_cpu(rsp->status);
-+
-+      BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
-+
-+      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+              return -ENOENT;
-+
-+      switch (result) {
-+      case L2CAP_CR_SUCCESS:
-+              sk->state = BT_CONFIG;
-+              l2cap_pi(sk)->dcid = dcid;
-+              l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-+
-+              l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+              break;
-+
-+      case L2CAP_CR_PEND:
-+              break;
-+
-+      default:
-+              l2cap_chan_del(sk, ECONNREFUSED);
-+              break;
-+      }
-+
-+      bh_unlock_sock(sk);
-+      return 0;
-+}
-+
-+static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      l2cap_conf_req * req = (l2cap_conf_req *) data;
-+      __u16 dcid, flags;
-+      __u8 rsp[64];
-+      struct sock *sk;
-+      int result;
-+
-+      dcid  = __le16_to_cpu(req->dcid);
-+      flags = __le16_to_cpu(req->flags);
-+
-+      BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
-+
-+      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+              return -ENOENT;
-+
-+      l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
-+
-+      if (flags & 0x0001) {
-+              /* Incomplete config. Send empty response. */
-+              l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
-+              goto unlock;
-+      }
-+
-+      /* Complete config. */
-+      l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
-+
-+      if (result)
-+              goto unlock;
-+
-+      /* Output config done */
-+      l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
-+
-+      if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
-+              sk->state = BT_CONNECTED;
-+              l2cap_chan_ready(sk);
-+      } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
-+              char req[64];
-+              l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
-+      }
-+
-+unlock:
-+      bh_unlock_sock(sk);
-+      return 0;
-+}
-+
-+static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
-+      __u16 scid, flags, result;
-+      struct sock *sk;
-+      int err = 0;
-+
-+      scid   = __le16_to_cpu(rsp->scid);
-+      flags  = __le16_to_cpu(rsp->flags);
-+      result = __le16_to_cpu(rsp->result);
-+
-+      BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
-+
-+      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+              return -ENOENT;
-+
-+      switch (result) {
-+      case L2CAP_CONF_SUCCESS:
-+              break;
-+
-+      case L2CAP_CONF_UNACCEPT:
-+              if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
-+                      char req[128];
-+                      /* 
-+                         It does not make sense to adjust L2CAP parameters 
-+                         that are currently defined in the spec. We simply 
-+                         resend config request that we sent earlier. It is
-+                         stupid :) but it helps qualification testing
-+                         which expects at least some response from us.
-+                      */
-+                      l2cap_send_req(conn, L2CAP_CONF_REQ,
-+                              l2cap_build_conf_req(sk, req), req);
-+                      goto done;
-+              }
-+      default: 
-+              sk->state = BT_DISCONN;
-+              sk->err   = ECONNRESET;
-+              l2cap_sock_set_timer(sk, HZ * 5);
-+              {
-+                      l2cap_disconn_req req;
-+                      req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+                      l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
-+              }
-+              goto done;
-+      }
-+
-+      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) {
-+              sk->state = BT_CONNECTED;
-+              l2cap_chan_ready(sk);
-+      }
-+
-+done:
-+      bh_unlock_sock(sk);
-+      return err;
-+}
-+
-+static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      l2cap_disconn_req *req = (l2cap_disconn_req *) data;
-+      l2cap_disconn_rsp rsp;
-+      __u16 dcid, scid;
-+      struct sock *sk;
-+
-+      scid = __le16_to_cpu(req->scid);
-+      dcid = __le16_to_cpu(req->dcid);
-+
-+      BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
-+
-+      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
-+              return 0;
-+
-+      rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
-+      rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+      l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
-+
-+      sk->shutdown = SHUTDOWN_MASK;
-+      
-+      l2cap_chan_del(sk, ECONNRESET);
-+      bh_unlock_sock(sk);
-+
-+      l2cap_sock_kill(sk);
-+      return 0;
-+}
-+
-+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
-+{
-+      l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
-+      __u16 dcid, scid;
-+      struct sock *sk;
-+
-+      scid = __le16_to_cpu(rsp->scid);
-+      dcid = __le16_to_cpu(rsp->dcid);
-+
-+      BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
-+
-+      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
-+              return 0;
-+      l2cap_chan_del(sk, 0);
-+      bh_unlock_sock(sk);
-+
-+      l2cap_sock_kill(sk);
-+      return 0;
-+}
-+
-+static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+      __u8 *data = skb->data;
-+      int len = skb->len;
-+      l2cap_cmd_hdr cmd;
-+      int err = 0;
-+
-+      while (len >= L2CAP_CMD_HDR_SIZE) {
-+              memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
-+              data += L2CAP_CMD_HDR_SIZE;
-+              len  -= L2CAP_CMD_HDR_SIZE;
-+
-+              cmd.len = __le16_to_cpu(cmd.len);
-+
-+              BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
-+
-+              if (cmd.len > len || !cmd.ident) {
-+                      BT_DBG("corrupted command");
-+                      break;
-+              }
-+
-+              switch (cmd.code) {
-+              case L2CAP_CONN_REQ:
-+                      err = l2cap_connect_req(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_CONN_RSP:
-+                      err = l2cap_connect_rsp(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_CONF_REQ:
-+                      err = l2cap_config_req(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_CONF_RSP:
-+                      err = l2cap_config_rsp(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_DISCONN_REQ:
-+                      err = l2cap_disconnect_req(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_DISCONN_RSP:
-+                      err = l2cap_disconnect_rsp(conn, &cmd, data);
-+                      break;
-+
-+              case L2CAP_COMMAND_REJ:
-+                      /* FIXME: We should process this */
-+                      l2cap_raw_recv(conn, skb);
-+                      break;
-+
-+              case L2CAP_ECHO_REQ:
-+                      l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
-+                      break;
-+
-+              case L2CAP_ECHO_RSP:
-+              case L2CAP_INFO_REQ:
-+              case L2CAP_INFO_RSP:
-+                      l2cap_raw_recv(conn, skb);
-+                      break;
-+
-+              default:
-+                      BT_ERR("Uknown signaling command 0x%2.2x", cmd.code);
-+                      err = -EINVAL;
-+                      break;
-+              };
-+
-+              if (err) {
-+                      l2cap_cmd_rej rej;
-+                      BT_DBG("error %d", err);
-+
-+                      /* FIXME: Map err to a valid reason. */
-+                      rej.reason = __cpu_to_le16(0);
-+                      l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
-+              }
-+
-+              data += cmd.len;
-+              len  -= cmd.len;
-+      }
-+
-+      kfree_skb(skb);
-+}
-+
-+static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
-+{
-+      struct sock *sk;
-+
-+      sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
-+      if (!sk) {
-+              BT_DBG("unknown cid 0x%4.4x", cid);
-+              goto drop;
-+      }
-+
-+      BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+      if (sk->state != BT_CONNECTED)
-+              goto drop;
-+
-+      if (l2cap_pi(sk)->imtu < skb->len)
-+              goto drop;
-+
-+      /* If socket recv buffers overflows we drop data here 
-+       * which is *bad* because L2CAP has to be reliable. 
-+       * But we don't have any other choice. L2CAP doesn't 
-+       * provide flow control mechanism */ 
-+      
-+      if (!sock_queue_rcv_skb(sk, skb))
-+              goto done;
-+
-+drop:
-+      kfree_skb(skb);
-+
-+done:
-+      if (sk) bh_unlock_sock(sk);
-+      return 0;
-+}
-+
-+static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
-+{
-+      struct sock *sk;
-+
-+      sk = l2cap_get_sock_by_psm(0, psm, conn->src);
-+      if (!sk)
-+              goto drop;
-+
-+      BT_DBG("sk %p, len %d", sk, skb->len);
-+
-+      if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
-+              goto drop;
-+
-+      if (l2cap_pi(sk)->imtu < skb->len)
-+              goto drop;
-+
-+      if (!sock_queue_rcv_skb(sk, skb))
-+              goto done;
-+
-+drop:
-+      kfree_skb(skb);
-+
-+done:
-+      if (sk) bh_unlock_sock(sk);
-+      return 0;
-+}
-+
-+static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
-+{
-+      l2cap_hdr *lh = (l2cap_hdr *) skb->data;
-+      __u16 cid, psm, len;
-+
-+      skb_pull(skb, L2CAP_HDR_SIZE);
-+      cid = __le16_to_cpu(lh->cid);
-+      len = __le16_to_cpu(lh->len);
-+
-+      BT_DBG("len %d, cid 0x%4.4x", len, cid);
-+
-+      switch (cid) {
-+      case 0x0001:
-+              l2cap_sig_channel(conn, skb);
-+              break;
-+
-+      case 0x0002:
-+              psm = get_unaligned((__u16 *) skb->data);
-+              skb_pull(skb, 2);
-+              l2cap_conless_channel(conn, psm, skb);
-+              break;
-+              
-+      default:
-+              l2cap_data_channel(conn, cid, skb);
-+              break;
-+      }
-+}
-+
-+/* ------------ L2CAP interface with lower layer (HCI) ------------- */
-+
-+static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+      int exact = 0, lm1 = 0, lm2 = 0;
-+      register struct sock *sk;
-+
-+      if (type != ACL_LINK)
-+              return 0;
-+
-+      BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+      /* Find listening sockets and check their link_mode */
-+      read_lock(&l2cap_sk_list.lock);
-+      for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
-+              if (sk->state != BT_LISTEN)
-+                      continue;
-+
-+              if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) {
-+                      lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+                      exact++;
-+              } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+                      lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
-+      }
-+      read_unlock(&l2cap_sk_list.lock);
-+
-+      return exact ? lm1 : lm2;
-+}
-+
-+static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+      BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-+
-+      if (hcon->type != ACL_LINK)
-+              return 0;
-+
-+      if (!status) {
-+              struct l2cap_conn *conn;
-+
-+              conn = l2cap_conn_add(hcon, status);
-+              if (conn)
-+                      l2cap_conn_ready(conn);
-+      } else 
-+              l2cap_conn_del(hcon, bterr(status));
-+      
-+      return 0;
-+}
-+
-+static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+      BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+      if (hcon->type != ACL_LINK)
-+              return 0;
-+
-+      l2cap_conn_del(hcon, bterr(reason));
-+      return 0;
-+}
-+
-+static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+      struct l2cap_chan_list *l;
-+      struct l2cap_conn *conn;
-+      l2cap_conn_rsp rsp;
-+      struct sock *sk;
-+      int result;
-+      
-+      if (!(conn = hcon->l2cap_data))
-+              return 0;
-+      l = &conn->chan_list;
-+
-+      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->state != BT_CONNECT2 ||
-+                              (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) {
-+                      bh_unlock_sock(sk);
-+                      continue;
-+              }
-+
-+              if (!status) {
-+                      sk->state = BT_CONFIG;
-+                      result = 0;
-+              } else {
-+                      sk->state = BT_DISCONN;
-+                      l2cap_sock_set_timer(sk, HZ/10);
-+                      result = L2CAP_CR_SEC_BLOCK;
-+              }
-+
-+              rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+              rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
-+              rsp.result = __cpu_to_le16(result);
-+              rsp.status = __cpu_to_le16(0);
-+              l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
-+                      L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+              bh_unlock_sock(sk);
-+      }
-+
-+      read_unlock(&l->lock);
-+      return 0;
-+}
-+
-+static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
-+{
-+      struct l2cap_chan_list *l;
-+      struct l2cap_conn *conn;
-+      l2cap_conn_rsp rsp;
-+      struct sock *sk;
-+      int result;
-+      
-+      if (!(conn = hcon->l2cap_data))
-+              return 0;
-+      l = &conn->chan_list;
-+
-+      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->state != BT_CONNECT2) {
-+                      bh_unlock_sock(sk);
-+                      continue;
-+              }
-+
-+              if (!status) {
-+                      sk->state = BT_CONFIG;
-+                      result = 0;
-+              } else {
-+                      sk->state = BT_DISCONN;
-+                      l2cap_sock_set_timer(sk, HZ/10);
-+                      result = L2CAP_CR_SEC_BLOCK;
-+              }
-+
-+              rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
-+              rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
-+              rsp.result = __cpu_to_le16(result);
-+              rsp.status = __cpu_to_le16(0);
-+              l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, 
-+                      L2CAP_CONN_RSP_SIZE, &rsp);
-+
-+              bh_unlock_sock(sk);
-+      }
-+
-+      read_unlock(&l->lock);
-+      return 0;
-+}
-+
-+static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
-+{
-+      struct l2cap_conn *conn = hcon->l2cap_data;
-+
-+      if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
-+              goto drop;
-+
-+      BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
-+
-+      if (flags & ACL_START) {
-+              l2cap_hdr *hdr;
-+              int len;
-+
-+              if (conn->rx_len) {
-+                      BT_ERR("Unexpected start frame (len %d)", skb->len);
-+                      kfree_skb(conn->rx_skb);
-+                      conn->rx_skb = NULL;
-+                      conn->rx_len = 0;
-+                      l2cap_conn_unreliable(conn, ECOMM);
-+              }
-+
-+              if (skb->len < 2) {
-+                      BT_ERR("Frame is too short (len %d)", skb->len);
-+                      l2cap_conn_unreliable(conn, ECOMM);
-+                      goto drop;
-+              }
-+
-+              hdr = (l2cap_hdr *) skb->data;
-+              len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
-+
-+              if (len == skb->len) {
-+                      /* Complete frame received */
-+                      l2cap_recv_frame(conn, skb);
-+                      return 0;
-+              }
-+
-+              BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-+
-+              if (skb->len > len) {
-+                      BT_ERR("Frame is too long (len %d, expected len %d)",
-+                              skb->len, len);
-+                      l2cap_conn_unreliable(conn, ECOMM);
-+                      goto drop;
-+              }
-+
-+              /* Allocate skb for the complete frame including header */
-+              conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
-+              if (!conn->rx_skb)
-+                      goto drop;
-+
-+              memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+              conn->rx_len = len - skb->len;
-+      } else {
-+              BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
-+
-+              if (!conn->rx_len) {
-+                      BT_ERR("Unexpected continuation frame (len %d)", skb->len);
-+                      l2cap_conn_unreliable(conn, ECOMM);
-+                      goto drop;
-+              }
-+
-+              if (skb->len > conn->rx_len) {
-+                      BT_ERR("Fragment is too long (len %d, expected %d)",
-+                                      skb->len, conn->rx_len);
-+                      kfree_skb(conn->rx_skb);
-+                      conn->rx_skb = NULL;
-+                      conn->rx_len = 0;
-+                      l2cap_conn_unreliable(conn, ECOMM);
-+                      goto drop;
-+              }
-+
-+              memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
-+              conn->rx_len -= skb->len;
-+
-+              if (!conn->rx_len) {
-+                      /* Complete frame received */
-+                      l2cap_recv_frame(conn, conn->rx_skb);
-+                      conn->rx_skb = NULL;
-+              }
-+      }
-+
-+drop:
-+      kfree_skb(skb);
-+      return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+      struct l2cap_pinfo *pi;
-+      struct sock *sk;
-+      char *ptr = buf;
-+
-+      read_lock_bh(&list->lock);
-+
-+      for (sk = list->head; sk; sk = sk->next) {
-+              pi = l2cap_pi(sk);
-+              ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-+                              batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), 
-+                              sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
-+                              pi->link_mode);
-+      }
-+
-+      read_unlock_bh(&list->lock);
-+
-+      ptr += sprintf(ptr, "\n");
-+      return ptr - buf;
-+}
-+
-+static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+      char *ptr = buf;
-+      int len;
-+
-+      BT_DBG("count %d, offset %ld", count, offset);
-+
-+      ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
-+      len  = ptr - buf;
-+
-+      if (len <= count + offset)
-+              *eof = 1;
-+
-+      *start = buf + offset;
-+      len -= offset;
-+
-+      if (len > count)
-+              len = count;
-+      if (len < 0)
-+              len = 0;
-+
-+      return len;
-+}
-+
-+static struct proto_ops l2cap_sock_ops = {
-+      family:         PF_BLUETOOTH,
-+      release:        l2cap_sock_release,
-+      bind:           l2cap_sock_bind,
-+      connect:        l2cap_sock_connect,
-+      listen:         l2cap_sock_listen,
-+      accept:         l2cap_sock_accept,
-+      getname:        l2cap_sock_getname,
-+      sendmsg:        l2cap_sock_sendmsg,
-+      recvmsg:        bluez_sock_recvmsg,
-+      poll:           bluez_sock_poll,
-+      socketpair:     sock_no_socketpair,
-+      ioctl:          sock_no_ioctl,
-+      shutdown:       l2cap_sock_shutdown,
-+      setsockopt:     l2cap_sock_setsockopt,
-+      getsockopt:     l2cap_sock_getsockopt,
-+      mmap:           sock_no_mmap
-+};
-+
-+static struct net_proto_family l2cap_sock_family_ops = {
-+      family:         PF_BLUETOOTH,
-+      create:         l2cap_sock_create
-+};
-+
-+static struct hci_proto l2cap_hci_proto = {
-+      name:           "L2CAP",
-+      id:             HCI_PROTO_L2CAP,
-+      connect_ind:    l2cap_connect_ind,
-+      connect_cfm:    l2cap_connect_cfm,
-+      disconn_ind:    l2cap_disconn_ind,
-+      recv_acldata:   l2cap_recv_acldata,
-+      auth_cfm:       l2cap_auth_cfm,
-+      encrypt_cfm:    l2cap_encrypt_cfm
-+};
-+
-+int __init l2cap_init(void)
-+{
-+      int err;
-+
-+      if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
-+              BT_ERR("Can't register L2CAP socket");
-+              return err;
-+      }
-+
-+      if ((err = hci_register_proto(&l2cap_hci_proto))) {
-+              BT_ERR("Can't register L2CAP protocol");
-+              return err;
-+      }
-+
-+      create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
-+
-+      BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+      BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+      return 0;
-+}
-+
-+void l2cap_cleanup(void)
-+{
-+      remove_proc_entry("bluetooth/l2cap", NULL);
-+
-+      /* Unregister socket and protocol */
-+      if (bluez_sock_unregister(BTPROTO_L2CAP))
-+              BT_ERR("Can't unregister L2CAP socket");
-+
-+      if (hci_unregister_proto(&l2cap_hci_proto))
-+              BT_ERR("Can't unregister L2CAP protocol");
-+}
-+
-+void l2cap_load(void)
-+{
-+      /* Dummy function to trigger automatic L2CAP module loading by 
-+         other modules that use L2CAP sockets but do not use any other
-+         symbols from it. */
-+      return;
-+}
-+
-+EXPORT_SYMBOL(l2cap_load);
-+
-+module_init(l2cap_init);
-+module_exit(l2cap_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
-+MODULE_LICENSE("GPL");
---- linux/net/bluetooth/l2cap_core.c~bluetooth-2.4.18-mh11
-+++ linux/net/bluetooth/l2cap_core.c
--/* 
--   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 L2CAP core and sockets.
-- *
-- * $Id: l2cap_core.c,v 1.19 2001/08/03 04:19:50 maxk Exp $
-- */
--#define VERSION "1.1"
--
--#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/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef  DBG
--#define DBG( A... )
--#endif
--
--struct proto_ops l2cap_sock_ops;
--
--struct bluez_sock_list l2cap_sk_list = {
--      lock: RW_LOCK_UNLOCKED
--};
--
--struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
--rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
--
--static int  l2cap_conn_del(struct l2cap_conn *conn, int err);
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
--static void l2cap_chan_del(struct sock *sk, int err);
--static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
--
--static void l2cap_sock_close(struct sock *sk);
--static void l2cap_sock_kill(struct sock *sk);
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
--
--/* -------- L2CAP interfaces & routing --------- */
--/* Add/delete L2CAP interface.
-- * Must be called with locked rt_lock
-- */ 
--
--static void l2cap_iff_add(struct hci_dev *hdev)
--{
--      struct l2cap_iff *iff;
--
--      DBG("%s", hdev->name);
--
--      DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
--
--      /* Allocate new interface and lock HCI device */
--      if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
--              ERR("Can't allocate new interface %s", hdev->name);
--              return;
--      }
--      memset(iff, 0, sizeof(struct l2cap_iff));
--
--      hci_dev_hold(hdev);
--      hdev->l2cap_data = iff;
--      iff->hdev   = hdev;
--      iff->mtu    = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
--      iff->bdaddr = &hdev->bdaddr;
--
--      spin_lock_init(&iff->lock);
--      INIT_LIST_HEAD(&iff->conn_list);
--
--      list_add(&iff->list, &l2cap_iff_list);
--}
--
--static void l2cap_iff_del(struct hci_dev *hdev)
--{
--      struct l2cap_iff *iff;
--
--      if (!(iff = hdev->l2cap_data))
--              return;
--
--      DBG("%s iff %p", hdev->name, iff);
--
--      list_del(&iff->list);
--
--      l2cap_iff_lock(iff);
--
--      /* Drop connections */
--      while (!list_empty(&iff->conn_list)) {
--              struct l2cap_conn *c;
--
--              c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
--              l2cap_conn_del(c, ENODEV);
--      }
--
--      l2cap_iff_unlock(iff);
--
--      /* Unlock HCI device */
--      hdev->l2cap_data = NULL;
--      hci_dev_put(hdev);
--
--      kfree(iff);
--}
--
--/* Get route. Returns L2CAP interface.
-- * Must be called with locked rt_lock
-- */
--static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
--{
--      struct list_head *p;
--      int use_src;
--
--      DBG("%s -> %s", batostr(src), batostr(dst));
--
--      use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
--      
--      /* Simple routing: 
--       *      No source address - find interface with bdaddr != dst 
--       *      Source address    - find interface with bdaddr == src 
--       */
--
--      list_for_each(p, &l2cap_iff_list) {
--              struct l2cap_iff *iff;
--
--              iff = list_entry(p, struct l2cap_iff, list);
--
--              if (use_src && !bacmp(iff->bdaddr, src))
--                      return iff;
--              else if (bacmp(iff->bdaddr, dst))
--                      return iff;
--      }
--      return NULL;
--}
--
--/* ----- L2CAP timers ------ */
--static void l2cap_sock_timeout(unsigned long arg)
--{
--      struct sock *sk = (struct sock *) arg;
--
--      DBG("sock %p state %d", sk, sk->state);
--
--      bh_lock_sock(sk);
--      switch (sk->state) {
--      case BT_DISCONN:
--              l2cap_chan_del(sk, ETIMEDOUT);
--              break;
--
--      default:
--              sk->err = ETIMEDOUT;
--              sk->state_change(sk);
--              break;
--      };
--      bh_unlock_sock(sk);
--
--      l2cap_sock_kill(sk);
--      sock_put(sk);
--}
--
--static void l2cap_sock_set_timer(struct sock *sk, long timeout)
--{
--      DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
--
--      if (!mod_timer(&sk->timer, jiffies + timeout))
--              sock_hold(sk);
--}
--
--static void l2cap_sock_clear_timer(struct sock *sk)
--{
--      DBG("sock %p state %d", sk, sk->state);
--
--      if (timer_pending(&sk->timer) && del_timer(&sk->timer))
--              __sock_put(sk);
--}
--
--static void l2cap_sock_init_timer(struct sock *sk)
--{
--      init_timer(&sk->timer);
--      sk->timer.function = l2cap_sock_timeout;
--      sk->timer.data = (unsigned long)sk;
--}
--
--static void l2cap_conn_timeout(unsigned long arg)
--{
--      struct l2cap_conn *conn = (void *)arg;
--      
--      DBG("conn %p state %d", conn, conn->state);
--
--      if (conn->state == BT_CONNECTED) {
--              hci_disconnect(conn->hconn, 0x13);
--      }
--              
--      return;
--}
--
--static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
--{
--      DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
--
--      mod_timer(&conn->timer, jiffies + timeout);
--}
--
--static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
--{
--      DBG("conn %p state %d", conn, conn->state);
--
--      del_timer(&conn->timer);
--}
--
--static void l2cap_conn_init_timer(struct l2cap_conn *conn)
--{
--      init_timer(&conn->timer);
--      conn->timer.function = l2cap_conn_timeout;
--      conn->timer.data = (unsigned long)conn;
--}
--
--/* -------- L2CAP connections --------- */
--/* Add new connection to the interface.
-- * Interface must be locked
-- */
--static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
--{
--      struct l2cap_conn *conn;
--      bdaddr_t *src = iff->bdaddr;
--
--      if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
--              return NULL;
--
--      memset(conn, 0, sizeof(struct l2cap_conn));
--
--      conn->state = BT_OPEN;
--      conn->iff   = iff;
--      bacpy(&conn->src, src);
--      bacpy(&conn->dst, dst);
--
--      spin_lock_init(&conn->lock);
--      conn->chan_list.lock = RW_LOCK_UNLOCKED;
--
--      l2cap_conn_init_timer(conn);
--      
--      __l2cap_conn_link(iff, conn);
--
--      DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
--
--      MOD_INC_USE_COUNT;
--
--      return conn;
--}
--
--/* Delete connection on the interface.
-- * Interface must be locked
-- */
--static int l2cap_conn_del(struct l2cap_conn *conn, int err)
--{
--      struct sock *sk;
--
--      DBG("conn %p, state %d, err %d", conn, conn->state, err);
--
--      l2cap_conn_clear_timer(conn);
--      __l2cap_conn_unlink(conn->iff, conn);
--
--      conn->state = BT_CLOSED;
--
--      if (conn->rx_skb)
--              kfree_skb(conn->rx_skb);
--
--      /* Kill channels */
--      while ((sk = conn->chan_list.head)) {
--              bh_lock_sock(sk);
--              l2cap_sock_clear_timer(sk);
--              l2cap_chan_del(sk, err);
--              bh_unlock_sock(sk);
--
--              l2cap_sock_kill(sk);
--      }
--
--      kfree(conn);
--
--      MOD_DEC_USE_COUNT;
--      return 0;
--}
--
--static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
--{
--      struct list_head *p;
--
--      list_for_each(p, &iff->conn_list) {
--              struct l2cap_conn *c;
--
--              c = list_entry(p, struct l2cap_conn, list);
--              if (!bacmp(&c->dst, dst))
--                      return c;
--      }
--      return NULL;
--}
--
--int l2cap_connect(struct sock *sk)
--{
--      bdaddr_t *src = &l2cap_pi(sk)->src;
--      bdaddr_t *dst = &l2cap_pi(sk)->dst;
--      struct l2cap_conn *conn;
--      struct l2cap_iff *iff;
--      int err = 0;
--
--      DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
--
--      read_lock_bh(&l2cap_rt_lock);
--
--      /* Get route to remote BD address */
--      if (!(iff = l2cap_get_route(src, dst))) {
--              err = -EHOSTUNREACH;
--              goto done;
--      }
--
--      /* Update source addr of the socket */
--      bacpy(src, iff->bdaddr);
--
--      l2cap_iff_lock(iff);
--
--      if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
--              /* Connection doesn't exist */
--              if (!(conn = l2cap_conn_add(iff, dst))) {
--                      l2cap_iff_unlock(iff);
--                      err = -ENOMEM;
--                      goto done;
--              }
--              conn->out = 1;
--      }
--
--      l2cap_iff_unlock(iff);
--
--      l2cap_chan_add(conn, sk, NULL);
--
--      sk->state = BT_CONNECT;
--      l2cap_sock_set_timer(sk, sk->sndtimeo);
--
--      switch (conn->state) {
--      case BT_CONNECTED:
--              if (sk->type == SOCK_SEQPACKET) {
--                      l2cap_conn_req req;
--                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
--                      req.psm  = l2cap_pi(sk)->psm;
--                      l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
--              } else {
--                      l2cap_sock_clear_timer(sk);
--                      sk->state = BT_CONNECTED;
--              }
--              break;
--
--      case BT_CONNECT:
--              break;
--
--      default:
--              /* Create ACL connection */
--              conn->state = BT_CONNECT;
--              hci_connect(iff->hdev, dst);
--              break;
--      };
--
--done:
--      read_unlock_bh(&l2cap_rt_lock);
--      return err;
--}
--
--/* ------ Channel queues for listening sockets ------ */
--void l2cap_accept_queue(struct sock *parent, struct sock *sk)
--{
--      struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
--
--      DBG("parent %p, sk %p", parent, sk);
--
--      sock_hold(sk);
--      l2cap_pi(sk)->parent = parent;
--      l2cap_pi(sk)->next_q = NULL;
--
--      if (!q->head) {
--              q->head = q->tail = sk;
--      } else {
--              struct sock *tail = q->tail;
--
--              l2cap_pi(sk)->prev_q = tail;
--              l2cap_pi(tail)->next_q = sk;
--              q->tail = sk;
--      }
--
--      parent->ack_backlog++;
--}
--
--void l2cap_accept_unlink(struct sock *sk)
--{
--      struct sock *parent = l2cap_pi(sk)->parent;
--      struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
--      struct sock *next, *prev;
--
--      DBG("sk %p", sk);
--
--      next = l2cap_pi(sk)->next_q;
--      prev = l2cap_pi(sk)->prev_q;
--
--      if (sk == q->head)
--              q->head = next;
--      if (sk == q->tail)
--              q->tail = prev;
--
--      if (next)
--              l2cap_pi(next)->prev_q = prev;
--      if (prev)
--              l2cap_pi(prev)->next_q = next;
--
--      l2cap_pi(sk)->parent = NULL;
--
--      parent->ack_backlog--;
--      __sock_put(sk);
--}
--
--/* Get next connected channel in queue. */
--struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
--{
--      struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
--      struct sock *sk;
--
--      for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
--              if (!state || sk->state == state) {
--                      l2cap_accept_unlink(sk);
--                      break;
--              }
--      }
--
--      DBG("parent %p, sk %p", parent, sk);
--
--      return sk;
--}
--
--/* -------- Socket interface ---------- */
--static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
--{
--      bdaddr_t *src = &addr->l2_bdaddr;
--      __u16 psm = addr->l2_psm;
--      struct sock *sk;
--
--      for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
--              if (l2cap_pi(sk)->psm == psm &&
--                  !bacmp(&l2cap_pi(sk)->src, src))
--                      break;
--      }
--
--      return sk;
--}
--
--/* Find socket listening on psm and source bdaddr.
-- * Returns closest match.
-- */
--static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
--{
--      struct sock *sk, *sk1 = NULL;
--
--      read_lock(&l2cap_sk_list.lock);
--
--      for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
--              struct l2cap_pinfo *pi;
--
--              if (sk->state != BT_LISTEN)
--                      continue;
--
--              pi = l2cap_pi(sk);
--
--              if (pi->psm == psm) {
--                      /* Exact match. */
--                      if (!bacmp(&pi->src, src))
--                              break;
--
--                      /* Closest match */
--                      if (!bacmp(&pi->src, BDADDR_ANY))
--                              sk1 = sk;
--              }
--      }
--
--      read_unlock(&l2cap_sk_list.lock);
--
--      return sk ? sk : sk1;
--}
--
--static void l2cap_sock_destruct(struct sock *sk)
--{
--      DBG("sk %p", sk);
--
--      skb_queue_purge(&sk->receive_queue);
--      skb_queue_purge(&sk->write_queue);
--
--      MOD_DEC_USE_COUNT;
--}
--
--static void l2cap_sock_cleanup_listen(struct sock *parent)
--{
--      struct sock *sk;
--
--      DBG("parent %p", parent);
--
--      /* Close not yet accepted channels */
--      while ((sk = l2cap_accept_dequeue(parent, 0)))
--              l2cap_sock_close(sk);
--
--      parent->state  = BT_CLOSED;
--      parent->zapped = 1;
--}
--
--/* Kill socket (only if zapped and orphan)
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_kill(struct sock *sk)
--{
--      if (!sk->zapped || sk->socket)
--              return;
--
--      DBG("sk %p state %d", sk, sk->state);
--
--      /* Kill poor orphan */
--      bluez_sock_unlink(&l2cap_sk_list, sk);
--      sk->dead = 1;
--      sock_put(sk);
--}
--
--/* Close socket.
-- * Must be called on unlocked socket.
-- */
--static void l2cap_sock_close(struct sock *sk)
--{
--      struct l2cap_conn *conn;
--
--      l2cap_sock_clear_timer(sk);
--
--      lock_sock(sk);
--
--      conn = l2cap_pi(sk)->conn;
--
--      DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
--
--      switch (sk->state) {
--      case BT_LISTEN:
--              l2cap_sock_cleanup_listen(sk);
--              break;
--
--      case BT_CONNECTED:
--      case BT_CONFIG:
--              if (sk->type == SOCK_SEQPACKET) {
--                      l2cap_disconn_req req;
--
--                      sk->state = BT_DISCONN;
--
--                      req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
--                      l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
--                      l2cap_sock_set_timer(sk, sk->sndtimeo);
--              } else {
--                      l2cap_chan_del(sk, ECONNRESET);
--              }
--              break;
--
--      case BT_CONNECT:
--      case BT_DISCONN:
--              l2cap_chan_del(sk, ECONNRESET);
--              break;
--
--      default:
--              sk->zapped = 1;
--              break;
--      };
--
--      release_sock(sk);
--
--      l2cap_sock_kill(sk);
--}
--
--static void l2cap_sock_init(struct sock *sk, struct sock *parent)
--{
--      struct l2cap_pinfo *pi = l2cap_pi(sk);
--
--      DBG("sk %p", sk);
--
--      if (parent) {
--              sk->type = parent->type;
--
--              pi->imtu = l2cap_pi(parent)->imtu;
--              pi->omtu = l2cap_pi(parent)->omtu;
--      } else {
--              pi->imtu = L2CAP_DEFAULT_MTU;
--              pi->omtu = 0;
--      }
--
--      /* Default config options */
--      pi->conf_mtu = L2CAP_DEFAULT_MTU;
--      pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
--}
--
--static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
--{
--      struct sock *sk;
--
--      if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
--              return NULL;
--
--      sock_init_data(sock, sk);
--
--      sk->zapped   = 0;
--
--      sk->destruct = l2cap_sock_destruct;
--      sk->sndtimeo = L2CAP_CONN_TIMEOUT;
--
--      sk->protocol = proto;
--      sk->state    = BT_OPEN;
--
--      l2cap_sock_init_timer(sk);
--
--      bluez_sock_link(&l2cap_sk_list, sk);
--
--      MOD_INC_USE_COUNT;
--
--      return sk;
--}
--
--static int l2cap_sock_create(struct socket *sock, int protocol)
--{
--      struct sock *sk;
--
--      DBG("sock %p", sock);
--
--      sock->state = SS_UNCONNECTED;
--
--      if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
--              return -ESOCKTNOSUPPORT;
--
--      sock->ops = &l2cap_sock_ops;
--
--      if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
--              return -ENOMEM;
--
--      l2cap_sock_init(sk, NULL);
--
--      return 0;
--}
--
--static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
--{
--      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
--      struct sock *sk = sock->sk;
--      int err = 0;
--
--      DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
--
--      if (!addr || addr->sa_family != AF_BLUETOOTH)
--              return -EINVAL;
--
--      lock_sock(sk);
--
--      if (sk->state != BT_OPEN) {
--              err = -EBADFD;
--              goto done;
--      }
--
--      write_lock(&l2cap_sk_list.lock);
--
--      if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
--              err = -EADDRINUSE;
--              goto unlock;
--      }
--
--      /* Save source address */
--      bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
--      l2cap_pi(sk)->psm = la->l2_psm;
--      sk->state = BT_BOUND;
--
--unlock:
--      write_unlock(&l2cap_sk_list.lock);
--
--done:
--      release_sock(sk);
--
--      return err;
--}
--
--static int l2cap_sock_w4_connect(struct sock *sk, int flags)
--{
--      DECLARE_WAITQUEUE(wait, current);
--      long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
--      int err = 0;
--
--      DBG("sk %p", sk);
--
--      add_wait_queue(sk->sleep, &wait);
--      current->state = TASK_INTERRUPTIBLE;
--
--      while (sk->state != BT_CONNECTED) {
--              if (!timeo) {
--                      err = -EAGAIN;
--                      break;
--              }
--
--              release_sock(sk);
--              timeo = schedule_timeout(timeo);
--              lock_sock(sk);
--
--              err = 0;
--              if (sk->state == BT_CONNECTED)
--                      break;
--
--              if (sk->err) {
--                      err = sock_error(sk);
--                      break;
--              }
--
--              if (signal_pending(current)) {
--                      err = sock_intr_errno(timeo);
--                      break;
--              }
--      }
--      current->state = TASK_RUNNING;
--      remove_wait_queue(sk->sleep, &wait);
--
--      return err;
--}
--
--static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
--{
--      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
--      struct sock *sk = sock->sk;
--      int err = 0;
--
--      lock_sock(sk);
--
--      DBG("sk %p", sk);
--
--      if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
--              err = -EINVAL;
--              goto done;
--      }
--
--      if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
--              err = -EBADFD;
--              goto done;
--      }
--
--      if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
--              err = -EINVAL;
--              goto done;
--      }
--
--      /* Set destination address and psm */
--      bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
--      l2cap_pi(sk)->psm = la->l2_psm;
--
--      if ((err = l2cap_connect(sk)))
--              goto done;
--
--      err = l2cap_sock_w4_connect(sk, flags);
--
--done:
--      release_sock(sk);
--      return err;
--}
--
--int l2cap_sock_listen(struct socket *sock, int backlog)
--{
--      struct sock *sk = sock->sk;
--      int err = 0;
--
--      DBG("sk %p backlog %d", sk, backlog);
--
--      lock_sock(sk);
--
--      if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
--              err = -EBADFD;
--              goto done;
--      }
--
--      if (!l2cap_pi(sk)->psm) {
--              err = -EINVAL;
--              goto done;
--      }
--
--      sk->max_ack_backlog = backlog;
--      sk->ack_backlog = 0;
--      sk->state = BT_LISTEN;
--
--done:
--      release_sock(sk);
--      return err;
--}
--
--int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
--{
--      DECLARE_WAITQUEUE(wait, current);
--      struct sock *sk = sock->sk, *ch;
--      long timeo;
--      int err = 0;
--
--      lock_sock(sk);
--
--      if (sk->state != BT_LISTEN) {
--              err = -EBADFD;
--              goto done;
--      }
--
--      timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
--
--      DBG("sk %p timeo %ld", sk, timeo);
--
--      /* Wait for an incoming connection. (wake-one). */
--      add_wait_queue_exclusive(sk->sleep, &wait);
--      current->state = TASK_INTERRUPTIBLE;
--      while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
--              if (!timeo) {
--                      err = -EAGAIN;
--                      break;
--              }
--
--              release_sock(sk);
--              timeo = schedule_timeout(timeo);
--              lock_sock(sk);
--
--              if (sk->state != BT_LISTEN) {
--                      err = -EBADFD;
--                      break;
--              }
--
--              if (signal_pending(current)) {
--                      err = sock_intr_errno(timeo);
--                      break;
--              }
--      }
--      current->state = TASK_RUNNING;
--      remove_wait_queue(sk->sleep, &wait);
--
--      if (err)
--              goto done;
--
--      sock_graft(ch, newsock);
--      newsock->state = SS_CONNECTED;
--
--      DBG("new socket %p", ch);
--
--done:
--      release_sock(sk);
--
--      return err;
--}
--
--static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
--{
--      struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
--      struct sock *sk = sock->sk;
--
--      DBG("sock %p, sk %p", sock, sk);
--
--      addr->sa_family = AF_BLUETOOTH;
--      *len = sizeof(struct sockaddr_l2);
--
--      if (peer)
--              bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
--      else
--              bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
--
--      la->l2_psm = l2cap_pi(sk)->psm;
--
--      return 0;
--}
--
--static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
--{
--      struct sock *sk = sock->sk;
--      int err = 0;
--
--      DBG("sock %p, sk %p", sock, sk);
--
--      if (sk->err)
--              return sock_error(sk);
--
--      if (msg->msg_flags & MSG_OOB)
--              return -EOPNOTSUPP;
--
--      lock_sock(sk);
--
--      if (sk->state == BT_CONNECTED)
--              err = l2cap_chan_send(sk, msg, len);
--      else
--              err = -ENOTCONN;
--
--      release_sock(sk);
--      return err;
--}
--
--static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
--{
--      struct sock *sk = sock->sk;
--      int noblock = flags & MSG_DONTWAIT;
--      int copied, err;
--      struct sk_buff *skb;
--
--      DBG("sock %p, sk %p", sock, sk);
--
--      if (flags & (MSG_OOB))
--              return -EOPNOTSUPP;
--
--      if (sk->state == BT_CLOSED)
--              return 0;
--
--      if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
--              return err;
--
--      msg->msg_namelen = 0;
--
--      copied = skb->len;
--      if (len < copied) {
--              msg->msg_flags |= MSG_TRUNC;
--              copied = len;
--      }
--
--      skb->h.raw = skb->data;
--      err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
--
--      skb_free_datagram(sk, skb);
--
--      return err ? : copied;
--}
--
--int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
--{
--      struct sock *sk = sock->sk;
--      struct l2cap_options opts;
--      int err = 0;
--
--      DBG("sk %p", sk);
--
--      lock_sock(sk);
--
--      switch (optname) {
--      case L2CAP_OPTIONS:
--              if (copy_from_user((char *)&opts, optval, optlen)) {
--                      err = -EFAULT;
--                      break;
--              }
--              l2cap_pi(sk)->imtu = opts.imtu;
--              l2cap_pi(sk)->omtu = opts.omtu;
--              break;
--
--      default:
--              err = -ENOPROTOOPT;
--              break;
--      };
--
--      release_sock(sk);
--      return err;
--}
--
--int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
--{
--      struct sock *sk = sock->sk;
--      struct l2cap_options opts;
--      struct l2cap_conninfo cinfo;
--      int len, err = 0; 
--
--      if (get_user(len, optlen))
--              return -EFAULT;
--
--      lock_sock(sk);
--
--      switch (optname) {
--      case L2CAP_OPTIONS:
--              opts.imtu     = l2cap_pi(sk)->imtu;
--              opts.omtu     = l2cap_pi(sk)->omtu;
--              opts.flush_to = l2cap_pi(sk)->flush_to;
--
--              len = MIN(len, sizeof(opts));
--              if (copy_to_user(optval, (char *)&opts, len))
--                      err = -EFAULT;
--
--              break;
--
--      case L2CAP_CONNINFO:
--              if (sk->state != BT_CONNECTED) {
--                      err = -ENOTCONN;
--                      break;
--              }
--
--              cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
--
--              len = MIN(len, sizeof(cinfo));
--              if (copy_to_user(optval, (char *)&cinfo, len))
--                      err = -EFAULT;
--
--              break;
--
--      default:
--              err = -ENOPROTOOPT;
--              break;
--      };
--
--      release_sock(sk);
--      return err;
--}
--
--static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
--{
--      struct sock *sk = sock->sk;
--      struct l2cap_accept_q *aq;
--      unsigned int mask;
--
--      DBG("sock %p, sk %p", sock, sk);
--
--      poll_wait(file, sk->sleep, wait);
--      mask = 0;
--
--      if (sk->err || !skb_queue_empty(&sk->error_queue))
--              mask |= POLLERR;
--
--      if (sk->shutdown == SHUTDOWN_MASK)
--              mask |= POLLHUP;
--
--      aq = &l2cap_pi(sk)->accept_q;
--      if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
--              mask |= POLLIN | POLLRDNORM;
--
--      if (sk->state == BT_CLOSED)
--              mask |= POLLHUP;
--
--      if (sock_writeable(sk))
--              mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
--      else
--              set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
--
--      return mask;
--}
--
--static int l2cap_sock_release(struct socket *sock)
--{
--      struct sock *sk = sock->sk;
--
--      DBG("sock %p, sk %p", sock, sk);
--
--      if (!sk)
--              return 0;
--
--      sock_orphan(sk);
--
--      l2cap_sock_close(sk);
--
--      return 0;
--}
--
--/* --------- L2CAP channels --------- */
--static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
--      struct sock *s;
--
--      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
--              if (l2cap_pi(s)->dcid == cid)
--                      break;
--      }
--
--      return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
--{
--      struct sock *s;
--
--      read_lock(&l->lock);
--      s = __l2cap_get_chan_by_dcid(l, cid);
--      read_unlock(&l->lock);
--
--      return s;
--}
--
--static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
--      struct sock *s;
--
--      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
--              if (l2cap_pi(s)->scid == cid)
--                      break;
--      }
--
--      return s;
--}
--static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
--{
--      struct sock *s;
--
--      read_lock(&l->lock);
--      s = __l2cap_get_chan_by_scid(l, cid);
--      read_unlock(&l->lock);
--
--      return s;
--}
--
--static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
--      struct sock *s;
--
--      for (s = l->head; s; s = l2cap_pi(s)->next_c) {
--              if (l2cap_pi(s)->ident == ident)
--                      break;
--      }
--
--      return s;
--}
--
--static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
--{
--      struct sock *s;
--
--      read_lock(&l->lock);
--      s = __l2cap_get_chan_by_ident(l, ident);
--      read_unlock(&l->lock);
--
--      return s;
--}
--
--static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
--{
--      __u16 cid = 0x0040;
--
--      for (; cid < 0xffff; cid++) {
--              if(!__l2cap_get_chan_by_scid(l, cid))
--                      return cid;
--      }
--
--      return 0;
--}
--
--static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
--{
--      sock_hold(sk);
--
--      if (l->head)
--              l2cap_pi(l->head)->prev_c = sk;
--
--      l2cap_pi(sk)->next_c = l->head;
--      l2cap_pi(sk)->prev_c = NULL;
--      l->head = sk;
--}
--
--static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
--{
--      struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
--
--      write_lock(&l->lock);
--      if (sk == l->head)
--              l->head = next;
--
--      if (next)
--              l2cap_pi(next)->prev_c = prev;
--      if (prev)
--              l2cap_pi(prev)->next_c = next;
--      write_unlock(&l->lock);
--
--      __sock_put(sk);
--}
--
--static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
--      struct l2cap_chan_list *l = &conn->chan_list;
--
--      DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
--
--      l2cap_conn_clear_timer(conn);
--
--      atomic_inc(&conn->refcnt);
--      l2cap_pi(sk)->conn = conn;
--
--      if (sk->type == SOCK_SEQPACKET) {
--              /* Alloc CID for normal socket */
--              l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
--      } else {
--              /* Raw socket can send only signalling messages */
--              l2cap_pi(sk)->scid = 0x0001;
--              l2cap_pi(sk)->dcid = 0x0001;
--              l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
--      }
--
--      __l2cap_chan_link(l, sk);
--
--      if (parent)
--              l2cap_accept_queue(parent, sk);
--}
--
--static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
--{
--      struct l2cap_chan_list *l = &conn->chan_list;
--
--      write_lock(&l->lock);
--      __l2cap_chan_add(conn, sk, parent);
--      write_unlock(&l->lock);
--}
--
--/* Delete channel. 
-- * Must be called on the locked socket. */
--static void l2cap_chan_del(struct sock *sk, int err)
--{
--      struct l2cap_conn *conn;
--      struct sock *parent;
--
--      conn = l2cap_pi(sk)->conn;
--      parent = l2cap_pi(sk)->parent;
--
--      DBG("sk %p, conn %p, err %d", sk, conn, err);
--
--      if (parent) {
--              /* Unlink from parent accept queue */
--              bh_lock_sock(parent);
--              l2cap_accept_unlink(sk);
--              bh_unlock_sock(parent);
--      }
--
--      if (conn) { 
--              long timeout;
--
--              /* Unlink from channel list */
--              l2cap_chan_unlink(&conn->chan_list, sk);
--              l2cap_pi(sk)->conn = NULL;
--
--              if (conn->out)
--                      timeout = L2CAP_DISCONN_TIMEOUT;
--              else
--                      timeout = L2CAP_CONN_IDLE_TIMEOUT;
--              
--              if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
--                      /* Schedule Baseband disconnect */
--                      l2cap_conn_set_timer(conn, timeout);
--              }
--      }
--
--      sk->state  = BT_CLOSED;
--      sk->err    = err;
--      sk->state_change(sk);
--
--      sk->zapped = 1;
--}
--
--static void l2cap_conn_ready(struct l2cap_conn *conn)
--{
--      struct l2cap_chan_list *l = &conn->chan_list;
--      struct sock *sk;
--
--      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->type != SOCK_SEQPACKET) {
--                      sk->state = BT_CONNECTED;
--                      sk->state_change(sk);
--                      l2cap_sock_clear_timer(sk);
--              } else if (sk->state == BT_CONNECT) {
--                      l2cap_conn_req req;
--                      req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
--                      req.psm  = l2cap_pi(sk)->psm;
--                      l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
--
--                      l2cap_sock_set_timer(sk, sk->sndtimeo);
--              }
--
--              bh_unlock_sock(sk);
--      }
--
--      read_unlock(&l->lock);
--}
--
--static void l2cap_chan_ready(struct sock *sk)
--{
--      struct sock *parent = l2cap_pi(sk)->parent;
--
--      DBG("sk %p, parent %p", sk, parent);
--
--      l2cap_pi(sk)->conf_state = 0;
--      l2cap_sock_clear_timer(sk);
--
--      if (!parent) {
--              /* Outgoing channel.
--               * Wake up socket sleeping on connect.
--               */
--              sk->state = BT_CONNECTED;
--              sk->state_change(sk);
--      } else {
--              /* Incomming channel.
--               * Wake up socket sleeping on accept.
--               */
--              parent->data_ready(parent, 1);
--      }
--}
--
--/* Copy frame to all raw sockets on that connection */
--void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
--{
--      struct l2cap_chan_list *l = &conn->chan_list;
--      struct sk_buff *nskb;
--      struct sock * sk;
--
--      DBG("conn %p", conn);
--
--      read_lock(&l->lock);
--      for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
--              if (sk->type != SOCK_RAW)
--                      continue;
--
--              /* Don't send frame to the socket it came from */
--              if (skb->sk == sk)
--                      continue;
--
--              if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
--                      continue;
--
--              skb_queue_tail(&sk->receive_queue, nskb);
--              sk->data_ready(sk, nskb->len);
--      }
--      read_unlock(&l->lock);
--}
--
--static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
--{
--      struct l2cap_conn *conn = l2cap_pi(sk)->conn;
--      struct sk_buff *skb, **frag;
--      int err, size, count, sent=0;
--      l2cap_hdr *lh;
--
--      /* Check outgoing MTU */
--      if (len > l2cap_pi(sk)->omtu)
--              return -EINVAL;
--
--      DBG("sk %p len %d", sk, len);
--
--      /* First fragment (with L2CAP header) */
--      count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
--      size  = L2CAP_HDR_SIZE + count;
--      if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
--              return err;
--
--      /* Create L2CAP header */
--      lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
--      lh->len = __cpu_to_le16(len);
--      lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--
--      if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
--              err = -EFAULT;
--              goto fail;
--      }
--
--      sent += count;
--      len  -= count;
--
--      /* Continuation fragments (no L2CAP header) */
--      frag = &skb_shinfo(skb)->frag_list;
--      while (len) {
--              count = MIN(conn->iff->mtu, len);
--
--              *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
--              if (!*frag)
--                      goto fail;
--              
--              if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
--                      err = -EFAULT;
--                      goto fail;
--              }
--
--              sent += count;
--              len  -= count;
--
--              frag = &(*frag)->next;
--      }
--
--      if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
--              goto fail;
--
--      return sent;
--
--fail:
--      kfree_skb(skb);
--      return err;
--}
--
--/* --------- L2CAP signalling commands --------- */
--static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
--{
--      __u8 id;
--
--      /* Get next available identificator.
--       *    1 - 199 are used by kernel.
--       *  200 - 254 are used by utilities like l2ping, etc 
--       */
--
--      spin_lock(&conn->lock);
--
--      if (++conn->tx_ident > 199)
--              conn->tx_ident = 1;
--
--      id = conn->tx_ident;
--
--      spin_unlock(&conn->lock);
--
--      return id;
--}
--
--static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
--{
--      struct sk_buff *skb;
--      l2cap_cmd_hdr *cmd;
--      l2cap_hdr *lh;
--      int size;
--
--      DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
--
--      size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
--      if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
--              return NULL;
--
--      lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
--      lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
--      lh->cid = __cpu_to_le16(0x0001);
--
--      cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
--      cmd->code  = code;
--      cmd->ident = ident;
--      cmd->len   = __cpu_to_le16(len);
--
--      if (len)
--              memcpy(skb_put(skb, len), data, len);
--
--      return skb;
--}
--
--static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
--{
--      struct sk_buff *skb;
--      __u8 ident;
--
--      DBG("code 0x%2.2x", code);
--
--      ident = l2cap_get_ident(conn);
--      if (!(skb = l2cap_build_cmd(code, ident, len, data)))
--              return -ENOMEM;
--      return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
--{
--      struct sk_buff *skb;
--
--      DBG("code 0x%2.2x", code);
--
--      if (!(skb = l2cap_build_cmd(code, ident, len, data)))
--              return -ENOMEM;
--      return hci_send_acl(conn->hconn, skb, 0);
--}
--
--static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
--{
--      l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
--      int len;
--
--      *type = opt->type;
--      switch (opt->len) {
--      case 1:
--              *val = *((__u8 *) opt->val);
--              break;
--
--      case 2:
--              *val = __le16_to_cpu(*((__u16 *)opt->val));
--              break;
--
--      case 4:
--              *val = __le32_to_cpu(*((__u32 *)opt->val));
--              break;
--
--      default:
--              *val = 0L;
--              break;
--      };
--
--      DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
--
--      len = L2CAP_CONF_OPT_SIZE + opt->len;
--
--      *ptr += len;
--
--      return len;
--}
--
--static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
--{
--      __u8 type, hint; __u32 val;
--      __u8 *ptr = data;
--
--      DBG("sk %p len %d", sk, len);
--
--      while (len >= L2CAP_CONF_OPT_SIZE) {
--              len -= l2cap_get_conf_opt(&ptr, &type, &val);
--
--              hint  = type & 0x80;
--              type &= 0x7f;
--
--              switch (type) {
--              case L2CAP_CONF_MTU:
--                      l2cap_pi(sk)->conf_mtu = val;
--                      break;
--
--              case L2CAP_CONF_FLUSH_TO:
--                      l2cap_pi(sk)->flush_to = val;
--                      break;
--
--              case L2CAP_CONF_QOS:
--                      break;
--              
--              default:
--                      if (hint)
--                              break;
--
--                      /* FIXME: Reject unknon option */
--                      break;
--              };
--      }
--}
--
--static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
--{
--      register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
--
--      DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
--
--      opt->type = type;
--      opt->len  = len;
--      switch (len) {
--      case 1:
--              *((__u8 *) opt->val)  = val;
--              break;
--
--      case 2:
--              *((__u16 *) opt->val) = __cpu_to_le16(val);
--              break;
--
--      case 4:
--              *((__u32 *) opt->val) = __cpu_to_le32(val);
--              break;
--      };
--
--      *ptr += L2CAP_CONF_OPT_SIZE + len;
--}
--
--static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
--{
--      struct l2cap_pinfo *pi = l2cap_pi(sk);
--      l2cap_conf_req *req = (l2cap_conf_req *) data;
--      __u8 *ptr = req->data;
--
--      DBG("sk %p", sk);
--
--      if (pi->imtu != L2CAP_DEFAULT_MTU)
--              l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
--
--      /* FIXME. Need actual value of the flush timeout */
--      //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
--      //   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
--
--      req->dcid  = __cpu_to_le16(pi->dcid);
--      req->flags = __cpu_to_le16(0);
--
--      return ptr - data;
--}
--
--static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
--{
--      struct l2cap_pinfo *pi = l2cap_pi(sk);
--      int result = 0;
--
--      /* Configure output options and let other side know
--       * which ones we don't like.
--       */
--      if (pi->conf_mtu < pi->omtu) {
--              l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
--              result = L2CAP_CONF_UNACCEPT;
--      } else {
--              pi->omtu = pi->conf_mtu;
--      }
--
--      DBG("sk %p result %d", sk, result);
--      return result;
--}
--
--static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
--{
--      l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
--      __u8 *ptr = rsp->data;
--
--      DBG("sk %p complete %d", sk, result ? 1 : 0);
--
--      if (result)
--              *result = l2cap_conf_output(sk, &ptr);
--
--      rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
--      rsp->result = __cpu_to_le16(result ? *result : 0);
--      rsp->flags  = __cpu_to_le16(0);
--
--      return ptr - data;
--}
--
--static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      struct l2cap_chan_list *list = &conn->chan_list;
--      l2cap_conn_req *req = (l2cap_conn_req *) data;
--      l2cap_conn_rsp rsp;
--      struct sock *sk, *parent;
--
--      __u16 scid = __le16_to_cpu(req->scid);
--      __u16 psm  = req->psm;
--
--      DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
--
--      /* Check if we have socket listening on psm */
--      if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
--              goto reject;
--
--      bh_lock_sock(parent);
--      write_lock(&list->lock);
--
--      /* Check if we already have channel with that dcid */
--      if (__l2cap_get_chan_by_dcid(list, scid))
--              goto unlock;
--
--      /* Check for backlog size */
--      if (parent->ack_backlog > parent->max_ack_backlog)
--              goto unlock;
--
--      if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
--              goto unlock;
--
--      l2cap_sock_init(sk, parent);
--
--      bacpy(&l2cap_pi(sk)->src, &conn->src);
--      bacpy(&l2cap_pi(sk)->dst, &conn->dst);
--      l2cap_pi(sk)->psm  = psm;
--      l2cap_pi(sk)->dcid = scid;
--
--      __l2cap_chan_add(conn, sk, parent);
--      sk->state = BT_CONFIG;
--
--      write_unlock(&list->lock);
--      bh_unlock_sock(parent);
--
--      rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
--      rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
--      rsp.result = __cpu_to_le16(0);
--      rsp.status = __cpu_to_le16(0);
--      l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
--      return 0;
--
--unlock:
--      write_unlock(&list->lock);
--      bh_unlock_sock(parent);
--
--reject:
--      rsp.scid   = __cpu_to_le16(scid);
--      rsp.dcid   = __cpu_to_le16(0);
--      rsp.status = __cpu_to_le16(0);
--      rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
--      l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
--
--      return 0;
--}
--
--static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
--      __u16 scid, dcid, result, status;
--      struct sock *sk;
--
--      scid   = __le16_to_cpu(rsp->scid);
--      dcid   = __le16_to_cpu(rsp->dcid);
--      result = __le16_to_cpu(rsp->result);
--      status = __le16_to_cpu(rsp->status);
--
--      DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
--              return -ENOENT;
--
--      bh_lock_sock(sk);
--
--      if (!result) {
--              char req[64];
--
--              sk->state = BT_CONFIG;
--              l2cap_pi(sk)->dcid = dcid;
--              l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
--
--              l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
--      } else {
--              l2cap_chan_del(sk, ECONNREFUSED);
--      }
--
--      bh_unlock_sock(sk);
--      return 0;
--}
--
--static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      l2cap_conf_req * req = (l2cap_conf_req *) data;
--      __u16 dcid, flags;
--      __u8 rsp[64];
--      struct sock *sk;
--      int result;
--
--      dcid  = __le16_to_cpu(req->dcid);
--      flags = __le16_to_cpu(req->flags);
--
--      DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
--              return -ENOENT;
--
--      bh_lock_sock(sk);
--
--      l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
--
--      if (flags & 0x01) {
--              /* Incomplete config. Send empty response. */
--              l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
--              goto unlock;
--      }
--
--      /* Complete config. */
--      l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
--
--      if (result)
--              goto unlock;
--
--      /* Output config done */
--      l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
--
--      if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
--              sk->state = BT_CONNECTED;
--              l2cap_chan_ready(sk);
--      } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
--              char req[64];
--              l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
--      }
--
--unlock:
--      bh_unlock_sock(sk);
--
--      return 0;
--}
--
--static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
--      __u16 scid, flags, result;
--      struct sock *sk;
--      int err = 0;
--
--      scid   = __le16_to_cpu(rsp->scid);
--      flags  = __le16_to_cpu(rsp->flags);
--      result = __le16_to_cpu(rsp->result);
--
--      DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
--              return -ENOENT;
--
--      bh_lock_sock(sk);
--
--      if (result) {
--              l2cap_disconn_req req;
--
--              /* They didn't like our options. Well... we do not negotiate.
--               * Close channel.
--               */
--              sk->state = BT_DISCONN;
--
--              req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--              req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
--              l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
--
--              l2cap_sock_set_timer(sk, sk->sndtimeo);
--              goto done;
--      }
--
--      if (flags & 0x01)
--              goto done;
--
--      /* Input config done */
--      l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
--
--      if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
--              sk->state = BT_CONNECTED;
--              l2cap_chan_ready(sk);
--      }
--
--done:
--      bh_unlock_sock(sk);
--
--      return err;
--}
--
--static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      l2cap_disconn_req *req = (l2cap_disconn_req *) data;
--      l2cap_disconn_rsp rsp;
--      __u16 dcid, scid;
--      struct sock *sk;
--
--      scid = __le16_to_cpu(req->scid);
--      dcid = __le16_to_cpu(req->dcid);
--
--      DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
--              return 0;
--
--      bh_lock_sock(sk);
--
--      rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
--      rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
--      l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
--
--      l2cap_chan_del(sk, ECONNRESET);
--
--      bh_unlock_sock(sk);
--
--      l2cap_sock_kill(sk);
--
--      return 0;
--}
--
--static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
--{
--      l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
--      __u16 dcid, scid;
--      struct sock *sk;
--
--      scid = __le16_to_cpu(rsp->scid);
--      dcid = __le16_to_cpu(rsp->dcid);
--
--      DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
--              return -ENOENT;
--
--      bh_lock_sock(sk);
--      l2cap_sock_clear_timer(sk);
--      l2cap_chan_del(sk, ECONNABORTED);
--      bh_unlock_sock(sk);
--
--      l2cap_sock_kill(sk);
--
--      return 0;
--}
--
--static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
--{
--      __u8 *data = skb->data;
--      int len = skb->len;
--      l2cap_cmd_hdr cmd;
--      int err = 0;
--
--      while (len >= L2CAP_CMD_HDR_SIZE) {
--              memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
--              data += L2CAP_CMD_HDR_SIZE;
--              len  -= L2CAP_CMD_HDR_SIZE;
--
--              cmd.len = __le16_to_cpu(cmd.len);
--
--              DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
--
--              if (cmd.len > len || !cmd.ident) {
--                      DBG("corrupted command");
--                      break;
--              }
--
--              switch (cmd.code) {
--              case L2CAP_CONN_REQ:
--                      err = l2cap_connect_req(conn, &cmd, data);
--                      break;
--
--              case L2CAP_CONN_RSP:
--                      err = l2cap_connect_rsp(conn, &cmd, data);
--                      break;
--
--              case L2CAP_CONF_REQ:
--                      err = l2cap_config_req(conn, &cmd, data);
--                      break;
--
--              case L2CAP_CONF_RSP:
--                      err = l2cap_config_rsp(conn, &cmd, data);
--                      break;
--
--              case L2CAP_DISCONN_REQ:
--                      err = l2cap_disconnect_req(conn, &cmd, data);
--                      break;
--
--              case L2CAP_DISCONN_RSP:
--                      err = l2cap_disconnect_rsp(conn, &cmd, data);
--                      break;
--
--              case L2CAP_COMMAND_REJ:
--                      /* FIXME: We should process this */
--                      l2cap_raw_recv(conn, skb);
--                      break;
--
--              case L2CAP_ECHO_REQ:
--                      l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
--                      break;
--
--              case L2CAP_ECHO_RSP:
--              case L2CAP_INFO_REQ:
--              case L2CAP_INFO_RSP:
--                      l2cap_raw_recv(conn, skb);
--                      break;
--
--              default:
--                      ERR("Uknown signaling command 0x%2.2x", cmd.code);
--                      err = -EINVAL;
--                      break;
--              };
--
--              if (err) {
--                      l2cap_cmd_rej rej;
--                      DBG("error %d", err);
--
--                      /* FIXME: Map err to a valid reason. */
--                      rej.reason = __cpu_to_le16(0);
--                      l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
--              }
--
--              data += cmd.len;
--              len  -= cmd.len;
--      }
--
--      kfree_skb(skb);
--}
--
--static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
--{
--      struct sock *sk;
--
--      if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
--              DBG("unknown cid 0x%4.4x", cid);
--              goto drop;
--      }
--
--      DBG("sk %p, len %d", sk, skb->len);
--
--      if (sk->state != BT_CONNECTED)
--              goto drop;
--
--      if (l2cap_pi(sk)->imtu < skb->len)
--              goto drop;
--
--      skb_queue_tail(&sk->receive_queue, skb);
--      sk->data_ready(sk, skb->len);
--
--      return 0;
--
--drop:
--      kfree_skb(skb);
--
--      return 0;
--}
--
--static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
--{
--      l2cap_hdr *lh = (l2cap_hdr *) skb->data;
--      __u16 cid, len;
--
--      skb_pull(skb, L2CAP_HDR_SIZE);
--      cid = __le16_to_cpu(lh->cid);
--      len = __le16_to_cpu(lh->len);
--
--      DBG("len %d, cid 0x%4.4x", len, cid);
--
--      if (cid == 0x0001)
--              l2cap_sig_channel(conn, skb);
--      else    
--              l2cap_data_channel(conn, cid, skb);
--}
--
--/* ------------ L2CAP interface with lower layer (HCI) ------------- */
--static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
--{
--      struct hci_dev *hdev = (struct hci_dev *) ptr;
--
--      DBG("hdev %s, event %ld", hdev->name, event);
--
--      write_lock(&l2cap_rt_lock);
--
--      switch (event) {
--      case HCI_DEV_UP:
--              l2cap_iff_add(hdev);
--              break;
--
--      case HCI_DEV_DOWN:
--              l2cap_iff_del(hdev);
--              break;
--      };
--
--      write_unlock(&l2cap_rt_lock);
--
--      return NOTIFY_DONE;
--}
--
--int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
--{
--      struct l2cap_iff *iff;
--
--      DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
--
--      if (!(iff = hdev->l2cap_data)) {
--              ERR("unknown interface");
--              return 0;
--      }
--
--      /* Always accept connection */
--      return 1;
--}
--
--int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
--{
--      struct l2cap_conn *conn;
--      struct l2cap_iff *iff;
--      int err = 0;
--
--      DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
--
--      if (!(iff = hdev->l2cap_data)) {
--              ERR("unknown interface");
--              return 0;
--      }
--
--      l2cap_iff_lock(iff);
--
--      conn = l2cap_get_conn_by_addr(iff, bdaddr);
--
--      if (conn) {
--              /* Outgoing connection */
--              DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
--
--              if (!status && hconn) {
--                      conn->state = BT_CONNECTED;
--                      conn->hconn = hconn;
--
--                      hconn->l2cap_data = (void *)conn;
--
--                      /* Establish channels */
--                      l2cap_conn_ready(conn);
--              } else {
--                      l2cap_conn_del(conn, bterr(status));
--              }
--      } else {
--              /* Incomming connection */
--              DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
--      
--              if (status || !hconn)
--                      goto done;
--
--              if (!(conn = l2cap_conn_add(iff, bdaddr))) {
--                      err = -ENOMEM;
--                      goto done;
--              }
--
--              conn->hconn = hconn;
--              hconn->l2cap_data = (void *)conn;
--
--              conn->state = BT_CONNECTED;
--      }
--
--done:
--      l2cap_iff_unlock(iff);
--
--      return err;
--}
--
--int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
--{
--      struct l2cap_conn *conn = hconn->l2cap_data;
--
--      DBG("hconn %p reason %d", hconn, reason);
--
--      if (!conn) {
--              ERR("unknown connection");
--              return 0;
--      }
--      conn->hconn = NULL;
--
--      l2cap_iff_lock(conn->iff);
--      l2cap_conn_del(conn, bterr(reason));
--      l2cap_iff_unlock(conn->iff);
--
--      return 0;
--}
--
--int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
--{
--      struct l2cap_conn *conn = hconn->l2cap_data;
--
--      if (!conn) {
--              ERR("unknown connection %p", hconn);
--              goto drop;
--      }
--
--      DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
--
--      if (flags & ACL_START) {
--              int flen, tlen, size;
--              l2cap_hdr *lh;
--
--              if (conn->rx_len) {
--                      ERR("Unexpected start frame (len %d)", skb->len);
--                      kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
--                      conn->rx_len = 0;
--              }
--
--              if (skb->len < L2CAP_HDR_SIZE) {
--                      ERR("Frame is too small (len %d)", skb->len);
--                      goto drop;
--              }
--
--              lh = (l2cap_hdr *)skb->data;
--              tlen = __le16_to_cpu(lh->len);
--              flen = skb->len - L2CAP_HDR_SIZE;
--
--              DBG("Start: total len %d, frag len %d", tlen, flen);
--
--              if (flen == tlen) {
--                      /* Complete frame received */
--                      l2cap_recv_frame(conn, skb);
--                      return 0;
--              }
--
--              /* Allocate skb for the complete frame (with header) */
--              size = L2CAP_HDR_SIZE + tlen;
--              if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
--                      goto drop;
--
--              memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
--
--              conn->rx_len = tlen - flen;
--      } else {
--              DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
--
--              if (!conn->rx_len) {
--                      ERR("Unexpected continuation frame (len %d)", skb->len);
--                      goto drop;
--              }
--
--              if (skb->len > conn->rx_len) {
--                      ERR("Fragment is too large (len %d)", skb->len);
--                      kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
--                      goto drop;
--              }
--
--              memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
--              conn->rx_len -= skb->len;
--
--              if (!conn->rx_len) {
--                      /* Complete frame received */
--                      l2cap_recv_frame(conn, conn->rx_skb);
--                      conn->rx_skb = NULL;
--              }
--      }
--
--drop:
--      kfree_skb(skb);
--      return 0;
--}
--
--struct proto_ops l2cap_sock_ops = {
--      family:         PF_BLUETOOTH,
--      release:        l2cap_sock_release,
--      bind:           l2cap_sock_bind,
--      connect:        l2cap_sock_connect,
--      listen:         l2cap_sock_listen,
--      accept:         l2cap_sock_accept,
--      getname:        l2cap_sock_getname,
--      sendmsg:        l2cap_sock_sendmsg,
--      recvmsg:        l2cap_sock_recvmsg,
--      poll:           l2cap_sock_poll,
--      socketpair:     sock_no_socketpair,
--      ioctl:          sock_no_ioctl,
--      shutdown:       sock_no_shutdown,
--      setsockopt:     l2cap_sock_setsockopt,
--      getsockopt:     l2cap_sock_getsockopt,
--      mmap:           sock_no_mmap
--};
--
--struct net_proto_family l2cap_sock_family_ops = {
--      family:         PF_BLUETOOTH,
--      create:         l2cap_sock_create
--};
--
--struct hci_proto l2cap_hci_proto = {
--      name:           "L2CAP",
--      id:             HCI_PROTO_L2CAP,
--      connect_ind:    l2cap_connect_ind,
--      connect_cfm:    l2cap_connect_cfm,
--      disconn_ind:    l2cap_disconn_ind,
--      recv_acldata:   l2cap_recv_acldata,
--};
--
--struct notifier_block l2cap_nblock = {
--      notifier_call: l2cap_dev_event
--};
--
--int __init l2cap_init(void)
--{
--      INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
--              VERSION);
--      INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
--
--      if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
--              ERR("Can't register L2CAP socket");
--              return -EPROTO;
--      }
--
--      if (hci_register_proto(&l2cap_hci_proto) < 0) {
--              ERR("Can't register L2CAP protocol");
--              return -EPROTO;
--      }
--
--      hci_register_notifier(&l2cap_nblock);
--
--      l2cap_register_proc();
--
--      return 0;
--}
--
--void l2cap_cleanup(void)
--{
--      l2cap_unregister_proc();
--
--      /* Unregister socket, protocol and notifier */
--      if (bluez_sock_unregister(BTPROTO_L2CAP))
--              ERR("Can't unregister L2CAP socket");
--
--      if (hci_unregister_proto(&l2cap_hci_proto) < 0)
--              ERR("Can't unregister L2CAP protocol");
--
--      hci_unregister_notifier(&l2cap_nblock);
--
--      /* We _must_ not have any sockets and/or connections
--       * at this stage.
--       */
--
--      /* Free interface list and unlock HCI devices */
--      {
--              struct list_head *list = &l2cap_iff_list;
--
--              while (!list_empty(list)) {
--                      struct l2cap_iff *iff;
--
--                      iff = list_entry(list->next, struct l2cap_iff, list);
--                      l2cap_iff_del(iff->hdev);
--              }
--      }
--}
--
--module_init(l2cap_init);
--module_exit(l2cap_cleanup);
--
--MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
--MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
--MODULE_LICENSE("GPL");
--
---- linux/net/bluetooth/l2cap_proc.c~bluetooth-2.4.18-mh11
-+++ linux/net/bluetooth/l2cap_proc.c
--/* 
--   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 L2CAP proc fs support.
-- *
-- * $Id: l2cap_proc.c,v 1.2 2001/06/02 01:40:09 maxk Exp $
-- */
--
--#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/init.h>
--#include <linux/skbuff.h>
--#include <linux/interrupt.h>
--#include <linux/socket.h>
--#include <linux/skbuff.h>
--#include <linux/proc_fs.h>
--#include <linux/list.h>
--#include <net/sock.h>
--
--#include <asm/system.h>
--#include <asm/uaccess.h>
--
--#include <net/bluetooth/bluez.h>
--#include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/hci_core.h>
--#include <net/bluetooth/l2cap_core.h>
--
--#ifndef L2CAP_DEBUG
--#undef  DBG
--#define DBG( A... )
--#endif
--
--/* ----- PROC fs support ----- */
--static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
--{
--      struct list_head *p;
--      char *ptr = buf;
--
--      list_for_each(p, &iff->conn_list) {
--              struct l2cap_conn *c;
--
--              c = list_entry(p, struct l2cap_conn, list);
--              ptr += sprintf(ptr, "    %p %d %p %p %s %s\n", 
--                              c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
--      }
--
--      return ptr - buf;
--}
--
--static int l2cap_iff_dump(char *buf)
--{
--      struct list_head *p;
--      char *ptr = buf;
--
--      ptr += sprintf(ptr, "Interfaces:\n");
--
--      write_lock(&l2cap_rt_lock);
--
--      list_for_each(p, &l2cap_iff_list) {
--              struct l2cap_iff *iff;
--
--              iff = list_entry(p, struct l2cap_iff, list);
--
--              ptr += sprintf(ptr, "  %s %p %p\n", iff->hdev->name, iff, iff->hdev);
--              
--              l2cap_iff_lock(iff);
--              ptr += l2cap_conn_dump(ptr, iff);
--              l2cap_iff_unlock(iff);
--      }
--
--      write_unlock(&l2cap_rt_lock);
--
--      ptr += sprintf(ptr, "\n");
--
--      return ptr - buf;
--}
--
--static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
--{
--      struct l2cap_pinfo *pi;
--      struct sock *sk;
--      char *ptr = buf;
--
--      ptr += sprintf(ptr, "Sockets:\n");
--
--      write_lock(&list->lock);
--
--      for (sk = list->head; sk; sk = sk->next) {
--              pi = l2cap_pi(sk);
--              ptr += sprintf(ptr, "  %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
--                             batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
--      }
--
--      write_unlock(&list->lock);
--
--      ptr += sprintf(ptr, "\n");
--
--      return ptr - buf;
--}
--
--static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
--{
--      char *ptr = buf;
--      int len;
--
--      DBG("count %d, offset %ld", count, offset);
--
--      ptr += l2cap_iff_dump(ptr);
--      ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
--      len  = ptr - buf;
--
--      if (len <= count + offset)
--              *eof = 1;
--
--      *start = buf + offset;
--      len -= offset;
--
--      if (len > count)
--              len = count;
--      if (len < 0)
--              len = 0;
--
--      return len;
--}
--
--void l2cap_register_proc(void)
--{
--      create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
--}
--
--void l2cap_unregister_proc(void)
--{
--      remove_proc_entry("bluetooth/l2cap", NULL);
--}
---- linux/net/bluetooth/lib.c~bluetooth-2.4.18-mh11    2001-09-07 18:28:38.000000000 +0200
-+++ linux/net/bluetooth/lib.c  2004-01-25 23:37:39.000000000 +0100
-@@ -25,7 +25,7 @@
- /*
-  * BlueZ kernel library.
-  *
-- * $Id: lib.c,v 1.3 2001/06/22 23:14:23 maxk Exp $
-+ * $Id: lib.c,v 1.2 2002/06/20 19:55:08 maxk Exp $
-  */
- #include <linux/kernel.h>
-@@ -105,7 +105,7 @@
-               return EACCES;
-       case 0x06:
--              return EINVAL;
-+              return EBADE;
-       case 0x07:
-               return ENOMEM;
---- linux/net/bluetooth/Makefile~bluetooth-2.4.18-mh11 2001-06-12 04:15:27.000000000 +0200
-+++ linux/net/bluetooth/Makefile       2004-01-25 23:37:39.000000000 +0100
-@@ -1,20 +1,31 @@
- #
--# Makefile for the Bluetooth subsystem
-+# Makefile for the Linux Bluetooth subsystem
- #
--O_TARGET      := bluetooth.o
--list-multi    := hci.o l2cap.o
--export-objs   := syms.o
--hci-objs      := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
--l2cap-objs    := l2cap_core.o l2cap_proc.o
-+O_TARGET    := bluetooth.o
--obj-$(CONFIG_BLUEZ) += hci.o
-+list-multi  := bluez.o
-+export-objs := syms.o l2cap.o
-+
-+bluez-objs  := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
-+
-+obj-$(CONFIG_BLUEZ) += bluez.o
- obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
-+obj-$(CONFIG_BLUEZ_SCO) += sco.o
--include $(TOPDIR)/Rules.make
-+subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
-+subdir-$(CONFIG_BLUEZ_BNEP) += bnep
-+subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
--hci.o: $(hci-objs)
--      $(LD) -r -o $@ $(hci-objs)
-+ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
-+obj-y += rfcomm/rfcomm.o
-+endif
--l2cap.o: $(l2cap-objs)
--      $(LD) -r -o $@ $(l2cap-objs)
-+ifeq ($(CONFIG_BLUEZ_BNEP),y)
-+obj-y += bnep/bnep.o
-+endif
-+
-+include $(TOPDIR)/Rules.make
-+
-+bluez.o: $(bluez-objs)
-+      $(LD) -r -o $@ $(bluez-objs)
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/Config.in       2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,10 @@
-+#
-+# Bluetooth RFCOMM layer configuration
-+#
-+
-+dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
-+
-+if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
-+   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
-+fi
-+
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/core.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,1939 @@
-+/* 
-+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2002 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.
-+*/
-+
-+/* 
-+   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
-+*/
-+
-+/*
-+ * RFCOMM core.
-+ *
-+ * $Id: core.c,v 1.46 2002/10/18 20:12:12 maxk Exp $
-+ */
-+
-+#define __KERNEL_SYSCALLS__
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/init.h>
-+#include <linux/wait.h>
-+#include <linux/net.h>
-+#include <linux/proc_fs.h>
-+#include <net/sock.h>
-+#include <asm/uaccess.h>
-+#include <asm/unaligned.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/l2cap.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#define VERSION "1.1"
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+struct task_struct *rfcomm_thread;
-+DECLARE_MUTEX(rfcomm_sem);
-+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);
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d);
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s);
-+
-+/* ---- RFCOMM frame parsing macros ---- */
-+#define __get_dlci(b)     ((b & 0xfc) >> 2)
-+#define __get_channel(b)  ((b & 0xf8) >> 3)
-+#define __get_dir(b)      ((b & 0x04) >> 2)
-+#define __get_type(b)     ((b & 0xef))
-+
-+#define __test_ea(b)      ((b & 0x01))
-+#define __test_cr(b)      ((b & 0x02))
-+#define __test_pf(b)      ((b & 0x10))
-+
-+#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
-+#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
-+#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)
-+#define __srv_channel(dlci)    (dlci >> 1)
-+#define __dir(dlci)            (dlci & 0x01)
-+
-+#define __len8(len)       (((len) << 1) | 1)
-+#define __len16(len)      ((len) << 1)
-+
-+/* MCC macros */
-+#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))
-+#define __get_mcc_type(b) ((b & 0xfc) >> 2)
-+#define __get_mcc_len(b)  ((b & 0xfe) >> 1)
-+
-+/* RPN macros */
-+#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
-+#define __get_rpn_data_bits(line) ((line) & 0x3)
-+#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
-+#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
-+
-+/* ---- RFCOMM FCS computation ---- */
-+
-+/* CRC on 2 bytes */
-+#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
-+
-+/* FCS on 2 bytes */ 
-+static inline u8 __fcs(u8 *data)
-+{
-+      return (0xff - __crc(data));
-+}
-+
-+/* FCS on 3 bytes */ 
-+static inline u8 __fcs2(u8 *data)
-+{
-+      return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
-+}
-+
-+/* Check FCS */
-+static inline int __check_fcs(u8 *data, int type, u8 fcs)
-+{
-+      u8 f = __crc(data);
-+
-+      if (type != RFCOMM_UIH)
-+              f = rfcomm_crc_table[f ^ data[2]];
-+
-+      return rfcomm_crc_table[f ^ fcs] != 0xcf;
-+}
-+
-+/* ---- L2CAP callbacks ---- */
-+static void rfcomm_l2state_change(struct sock *sk)
-+{
-+      BT_DBG("%p state %d", sk, sk->state);
-+      rfcomm_schedule(RFCOMM_SCHED_STATE);
-+}
-+
-+static void rfcomm_l2data_ready(struct sock *sk, int bytes)
-+{
-+      BT_DBG("%p bytes %d", sk, bytes);
-+      rfcomm_schedule(RFCOMM_SCHED_RX);
-+}
-+
-+static int rfcomm_l2sock_create(struct socket **sock)
-+{
-+      int err;
-+
-+      BT_DBG("");
-+
-+      err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
-+      if (!err) {
-+              struct sock *sk = (*sock)->sk;
-+              sk->data_ready   = rfcomm_l2data_ready;
-+              sk->state_change = rfcomm_l2state_change;
-+      }
-+      return err;
-+}
-+
-+/* ---- RFCOMM DLCs ---- */
-+static void rfcomm_dlc_timeout(unsigned long arg)
-+{
-+      struct rfcomm_dlc *d = (void *) arg;
-+
-+      BT_DBG("dlc %p state %ld", d, d->state);
-+
-+      set_bit(RFCOMM_TIMED_OUT, &d->flags);
-+      rfcomm_dlc_put(d);
-+      rfcomm_schedule(RFCOMM_SCHED_TIMEO);
-+}
-+
-+static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
-+{
-+      BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
-+
-+      if (!mod_timer(&d->timer, jiffies + timeout))
-+              rfcomm_dlc_hold(d);
-+}
-+
-+static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
-+{
-+      BT_DBG("dlc %p state %ld", d, d->state);
-+
-+      if (timer_pending(&d->timer) && del_timer(&d->timer))
-+              rfcomm_dlc_put(d);
-+}
-+
-+static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
-+{
-+      BT_DBG("%p", d);
-+
-+      d->state      = BT_OPEN;
-+      d->flags      = 0;
-+      d->mscex      = 0;
-+      d->mtu        = RFCOMM_DEFAULT_MTU;
-+      d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
-+
-+      d->cfc        = RFCOMM_CFC_DISABLED;
-+      d->rx_credits = RFCOMM_DEFAULT_CREDITS;
-+}
-+
-+struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
-+{
-+      struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
-+      if (!d)
-+              return NULL;
-+      memset(d, 0, sizeof(*d));
-+
-+      init_timer(&d->timer);
-+      d->timer.function = rfcomm_dlc_timeout;
-+      d->timer.data = (unsigned long) d;
-+
-+      skb_queue_head_init(&d->tx_queue);
-+      spin_lock_init(&d->lock);
-+      atomic_set(&d->refcnt, 1);
-+
-+      rfcomm_dlc_clear_state(d);
-+      
-+      BT_DBG("%p", d);
-+      return d;
-+}
-+
-+void rfcomm_dlc_free(struct rfcomm_dlc *d)
-+{
-+      BT_DBG("%p", d);
-+
-+      skb_queue_purge(&d->tx_queue);
-+      kfree(d);
-+}
-+
-+static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
-+{
-+      BT_DBG("dlc %p session %p", d, s);
-+
-+      rfcomm_session_hold(s);
-+
-+      rfcomm_dlc_hold(d);
-+      list_add(&d->list, &s->dlcs);
-+      d->session = s;
-+}
-+
-+static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
-+{
-+      struct rfcomm_session *s = d->session;
-+
-+      BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
-+
-+      list_del(&d->list);
-+      d->session = NULL;
-+      rfcomm_dlc_put(d);
-+
-+      rfcomm_session_put(s);
-+}
-+
-+static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_dlc *d;
-+      struct list_head *p;
-+
-+      list_for_each(p, &s->dlcs) {
-+              d = list_entry(p, struct rfcomm_dlc, list);
-+              if (d->dlci == dlci)
-+                      return d;
-+      }
-+      return NULL;
-+}
-+
-+static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+      struct rfcomm_session *s;
-+      int err = 0;
-+      u8 dlci;
-+
-+      BT_DBG("dlc %p state %ld %s %s channel %d", 
-+                      d, d->state, batostr(src), batostr(dst), channel);
-+
-+      if (channel < 1 || channel > 30)
-+              return -EINVAL;
-+
-+      if (d->state != BT_OPEN && d->state != BT_CLOSED)
-+              return 0;
-+
-+      s = rfcomm_session_get(src, dst);
-+      if (!s) {
-+              s = rfcomm_session_create(src, dst, &err);
-+              if (!s)
-+                      return err;
-+      }
-+
-+      dlci = __dlci(!s->initiator, channel);
-+
-+      /* Check if DLCI already exists */
-+      if (rfcomm_dlc_get(s, dlci))
-+              return -EBUSY;
-+
-+      rfcomm_dlc_clear_state(d);
-+
-+      d->dlci     = dlci;
-+      d->addr     = __addr(s->initiator, dlci);
-+      d->priority = 7;
-+
-+      d->state    = BT_CONFIG;
-+      rfcomm_dlc_link(s, d);
-+
-+      d->mtu = s->mtu;
-+      d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
-+
-+      if (s->state == BT_CONNECTED)
-+              rfcomm_send_pn(s, 1, d);
-+      rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-+      return 0;
-+}
-+
-+int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
-+{
-+      mm_segment_t fs;
-+      int r;
-+
-+      rfcomm_lock();
-+
-+      fs = get_fs(); set_fs(KERNEL_DS);
-+      r = __rfcomm_dlc_open(d, src, dst, channel);
-+      set_fs(fs);
-+
-+      rfcomm_unlock();
-+      return r;
-+}
-+
-+static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+      struct rfcomm_session *s = d->session;
-+      if (!s)
-+              return 0;
-+
-+      BT_DBG("dlc %p state %ld dlci %d err %d session %p",
-+                      d, d->state, d->dlci, err, s);
-+
-+      switch (d->state) {
-+      case BT_CONNECTED:
-+      case BT_CONFIG:
-+      case BT_CONNECT:
-+              d->state = BT_DISCONN;
-+              if (skb_queue_empty(&d->tx_queue)) {
-+                      rfcomm_send_disc(s, d->dlci);
-+                      rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
-+              } else {
-+                      rfcomm_queue_disc(d);
-+                      rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
-+              }
-+              break;
-+
-+      default:
-+              rfcomm_dlc_clear_timer(d);
-+
-+              rfcomm_dlc_lock(d);
-+              d->state = BT_CLOSED;
-+              d->state_change(d, err);
-+              rfcomm_dlc_unlock(d);
-+
-+              skb_queue_purge(&d->tx_queue);
-+              rfcomm_dlc_unlink(d);
-+      }
-+
-+      return 0;
-+}
-+
-+int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
-+{
-+      mm_segment_t fs;
-+      int r;
-+
-+      rfcomm_lock();
-+
-+      fs = get_fs(); set_fs(KERNEL_DS);
-+      r = __rfcomm_dlc_close(d, err);
-+      set_fs(fs);
-+
-+      rfcomm_unlock();
-+      return r;
-+}
-+
-+int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+      int len = skb->len;
-+
-+      if (d->state != BT_CONNECTED)
-+              return -ENOTCONN;
-+
-+      BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
-+
-+      if (len > d->mtu)
-+              return -EINVAL;
-+
-+      rfcomm_make_uih(skb, d->addr);
-+      skb_queue_tail(&d->tx_queue, skb);
-+
-+      if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+              rfcomm_schedule(RFCOMM_SCHED_TX);
-+      return len;
-+}
-+
-+void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
-+{
-+      BT_DBG("dlc %p state %ld", d, d->state);
-+
-+      if (!d->cfc) {
-+              d->v24_sig |= RFCOMM_V24_FC;
-+              set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+      }
-+      rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
-+{
-+      BT_DBG("dlc %p state %ld", d, d->state);
-+
-+      if (!d->cfc) {
-+              d->v24_sig &= ~RFCOMM_V24_FC;
-+              set_bit(RFCOMM_MSC_PENDING, &d->flags);
-+      }
-+      rfcomm_schedule(RFCOMM_SCHED_TX);
-+}
-+
-+/* 
-+   Set/get modem status functions use _local_ status i.e. what we report
-+   to the other side.
-+   Remote status is provided by dlc->modem_status() callback.
-+ */
-+int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
-+{
-+      BT_DBG("dlc %p state %ld v24_sig 0x%x", 
-+                      d, d->state, v24_sig);
-+
-+      if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
-+              v24_sig |= RFCOMM_V24_FC;
-+      else
-+              v24_sig &= ~RFCOMM_V24_FC;
-+      
-+      d->v24_sig = v24_sig;
-+
-+      if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
-+              rfcomm_schedule(RFCOMM_SCHED_TX);
-+
-+      return 0;
-+}
-+
-+int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
-+{
-+      BT_DBG("dlc %p state %ld v24_sig 0x%x", 
-+                      d, d->state, d->v24_sig);
-+
-+      *v24_sig = d->v24_sig;
-+      return 0;
-+}
-+
-+/* ---- RFCOMM sessions ---- */
-+struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
-+{
-+      struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
-+      if (!s)
-+              return NULL;
-+      memset(s, 0, sizeof(*s));
-+      
-+      BT_DBG("session %p sock %p", s, sock);
-+
-+      INIT_LIST_HEAD(&s->dlcs);
-+      s->state = state;
-+      s->sock  = sock;
-+
-+      s->mtu   = RFCOMM_DEFAULT_MTU;
-+      s->cfc   = RFCOMM_CFC_UNKNOWN;
-+      
-+      list_add(&s->list, &session_list);
-+
-+      /* Do not increment module usage count for listeting sessions.
-+       * Otherwise we won't be able to unload the module. */
-+      if (state != BT_LISTEN)
-+              MOD_INC_USE_COUNT;
-+      return s;
-+}
-+
-+void rfcomm_session_del(struct rfcomm_session *s)
-+{
-+      int state = s->state;
-+      
-+      BT_DBG("session %p state %ld", s, s->state);
-+
-+      list_del(&s->list);
-+
-+      if (state == BT_CONNECTED)
-+              rfcomm_send_disc(s, 0);
-+
-+      sock_release(s->sock);
-+      kfree(s);
-+
-+      if (state != BT_LISTEN)
-+              MOD_DEC_USE_COUNT;
-+}
-+
-+struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
-+{
-+      struct rfcomm_session *s;
-+      struct list_head *p, *n;
-+      struct bluez_pinfo *pi;
-+      list_for_each_safe(p, n, &session_list) {
-+              s = list_entry(p, struct rfcomm_session, list);
-+              pi = bluez_pi(s->sock->sk); 
-+
-+              if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
-+                              !bacmp(&pi->dst, dst))
-+                      return s;
-+      }
-+      return NULL;
-+}
-+
-+void rfcomm_session_close(struct rfcomm_session *s, int err)
-+{
-+      struct rfcomm_dlc *d;
-+      struct list_head *p, *n;
-+
-+      BT_DBG("session %p state %ld err %d", s, s->state, err);
-+
-+      rfcomm_session_hold(s);
-+
-+      s->state = BT_CLOSED;
-+
-+      /* Close all dlcs */
-+      list_for_each_safe(p, n, &s->dlcs) {
-+              d = list_entry(p, struct rfcomm_dlc, list);
-+              d->state = BT_CLOSED;
-+              __rfcomm_dlc_close(d, err);
-+      }
-+
-+      rfcomm_session_put(s);
-+}
-+
-+struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
-+{
-+      struct rfcomm_session *s = NULL;
-+      struct sockaddr_l2 addr;
-+      struct l2cap_options opts;
-+      struct socket *sock;
-+      int    size;
-+
-+      BT_DBG("%s %s", batostr(src), batostr(dst));
-+
-+      *err = rfcomm_l2sock_create(&sock);
-+      if (*err < 0)
-+              return NULL;
-+
-+      bacpy(&addr.l2_bdaddr, src);
-+      addr.l2_family = AF_BLUETOOTH;
-+      addr.l2_psm    = 0;
-+      *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+      if (*err < 0)
-+              goto failed;
-+
-+      /* Set L2CAP options */
-+      size = sizeof(opts);
-+      sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+      
-+      opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+      sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+      s = rfcomm_session_add(sock, BT_BOUND);
-+      if (!s) {
-+              *err = -ENOMEM;
-+              goto failed;
-+      }
-+
-+      s->initiator = 1;
-+
-+      bacpy(&addr.l2_bdaddr, dst);
-+      addr.l2_family = AF_BLUETOOTH;
-+      addr.l2_psm    = htobs(RFCOMM_PSM);
-+      *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
-+      if (*err == 0 || *err == -EAGAIN)
-+              return s;
-+
-+      rfcomm_session_del(s);
-+      return NULL;
-+
-+failed:
-+      sock_release(sock);
-+      return NULL;
-+}
-+
-+void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
-+{
-+      struct sock *sk = s->sock->sk;
-+      if (src)
-+              bacpy(src, &bluez_pi(sk)->src);
-+      if (dst)
-+              bacpy(dst, &bluez_pi(sk)->dst);
-+}
-+
-+/* ---- RFCOMM frame sending ---- */
-+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
-+{
-+      struct socket *sock = s->sock;
-+      struct iovec iv = { data, len };
-+      struct msghdr msg;
-+      int err;
-+
-+      BT_DBG("session %p len %d", s, len);
-+
-+      memset(&msg, 0, sizeof(msg));
-+      msg.msg_iovlen = 1;
-+      msg.msg_iov = &iv;
-+
-+      err = sock->ops->sendmsg(sock, &msg, len, 0);
-+      return err;
-+}
-+
-+static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_cmd cmd;
-+
-+      BT_DBG("%p dlci %d", s, dlci);
-+
-+      cmd.addr = __addr(s->initiator, dlci);
-+      cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
-+      cmd.len  = __len8(0);
-+      cmd.fcs  = __fcs2((u8 *) &cmd);
-+
-+      return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_cmd cmd;
-+
-+      BT_DBG("%p dlci %d", s, dlci);
-+
-+      cmd.addr = __addr(!s->initiator, dlci);
-+      cmd.ctrl = __ctrl(RFCOMM_UA, 1);
-+      cmd.len  = __len8(0);
-+      cmd.fcs  = __fcs2((u8 *) &cmd);
-+
-+      return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_cmd cmd;
-+
-+      BT_DBG("%p dlci %d", s, dlci);
-+
-+      cmd.addr = __addr(s->initiator, dlci);
-+      cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
-+      cmd.len  = __len8(0);
-+      cmd.fcs  = __fcs2((u8 *) &cmd);
-+
-+      return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_queue_disc(struct rfcomm_dlc *d)
-+{
-+      struct rfcomm_cmd *cmd;
-+      struct sk_buff *skb;
-+
-+      BT_DBG("dlc %p dlci %d", d, d->dlci);
-+
-+      skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
-+      if (!skb)
-+              return -ENOMEM;
-+
-+      cmd = (void *) __skb_put(skb, sizeof(*cmd));
-+      cmd->addr = d->addr;
-+      cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
-+      cmd->len  = __len8(0);
-+      cmd->fcs  = __fcs2((u8 *) cmd);
-+
-+      skb_queue_tail(&d->tx_queue, skb);
-+      rfcomm_schedule(RFCOMM_SCHED_TX);
-+      return 0;
-+}
-+
-+static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_cmd cmd;
-+
-+      BT_DBG("%p dlci %d", s, dlci);
-+
-+      cmd.addr = __addr(!s->initiator, dlci);
-+      cmd.ctrl = __ctrl(RFCOMM_DM, 1);
-+      cmd.len  = __len8(0);
-+      cmd.fcs  = __fcs2((u8 *) &cmd);
-+
-+      return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
-+}
-+
-+static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d type %d", s, cr, type);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc) + 1);
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_NSC);
-+      mcc->len  = __len8(1);
-+
-+      /* Type that we didn't like */
-+      *ptr = __mcc_type(cr, type); ptr++;
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      struct rfcomm_pn  *pn;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc) + sizeof(*pn));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_PN);
-+      mcc->len  = __len8(sizeof(*pn));
-+
-+      pn = (void *) ptr; ptr += sizeof(*pn);
-+      pn->dlci        = d->dlci;
-+      pn->priority    = d->priority;
-+      pn->ack_timer   = 0;
-+      pn->max_retrans = 0;
-+
-+      if (s->cfc) {
-+              pn->flow_ctrl = cr ? 0xf0 : 0xe0;
-+              pn->credits = RFCOMM_DEFAULT_CREDITS;
-+      } else {
-+              pn->flow_ctrl = 0;
-+              pn->credits   = 0;
-+      }
-+
-+      pn->mtu = htobs(d->mtu);
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
-+                         u8 bit_rate, u8 data_bits, u8 stop_bits,
-+                         u8 parity, u8 flow_ctrl_settings, 
-+                         u8 xon_char, u8 xoff_char, u16 param_mask)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      struct rfcomm_rpn *rpn;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
-+             "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
-+                      s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
-+                      flow_ctrl_settings, xon_char, xoff_char, param_mask);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc) + sizeof(*rpn));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_RPN);
-+      mcc->len  = __len8(sizeof(*rpn));
-+
-+      rpn = (void *) ptr; ptr += sizeof(*rpn);
-+      rpn->dlci          = __addr(1, dlci);
-+      rpn->bit_rate      = bit_rate;
-+      rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
-+      rpn->flow_ctrl     = flow_ctrl_settings;
-+      rpn->xon_char      = xon_char;
-+      rpn->xoff_char     = xoff_char;
-+      rpn->param_mask    = param_mask;
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      struct rfcomm_rls *rls;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d status 0x%x", s, cr, status);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc) + sizeof(*rls));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_RLS);
-+      mcc->len  = __len8(sizeof(*rls));
-+
-+      rls = (void *) ptr; ptr += sizeof(*rls);
-+      rls->dlci   = __addr(1, dlci);
-+      rls->status = status;
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      struct rfcomm_msc *msc;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc) + sizeof(*msc));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_MSC);
-+      mcc->len  = __len8(sizeof(*msc));
-+
-+      msc = (void *) ptr; ptr += sizeof(*msc);
-+      msc->dlci    = __addr(1, dlci);
-+      msc->v24_sig = v24_sig | 0x01;
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d", s, cr);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
-+      mcc->len  = __len8(0);
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
-+{
-+      struct rfcomm_hdr *hdr;
-+      struct rfcomm_mcc *mcc;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p cr %d", s, cr);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = __addr(s->initiator, 0);
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+      hdr->len  = __len8(sizeof(*mcc));
-+
-+      mcc = (void *) ptr; ptr += sizeof(*mcc);
-+      mcc->type = __mcc_type(cr, RFCOMM_FCON);
-+      mcc->len  = __len8(0);
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
-+{
-+      struct socket *sock = s->sock;
-+      struct iovec iv[3];
-+      struct msghdr msg;
-+      unsigned char hdr[5], crc[1];
-+
-+      if (len > 125)
-+              return -EINVAL;
-+
-+      BT_DBG("%p cr %d", s, cr);
-+
-+      hdr[0] = __addr(s->initiator, 0);
-+      hdr[1] = __ctrl(RFCOMM_UIH, 0);
-+      hdr[2] = 0x01 | ((len + 2) << 1);
-+      hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
-+      hdr[4] = 0x01 | (len << 1);
-+
-+      crc[0] = __fcs(hdr);
-+
-+      iv[0].iov_base = hdr;
-+      iv[0].iov_len  = 5;
-+      iv[1].iov_base = pattern;
-+      iv[1].iov_len  = len;
-+      iv[2].iov_base = crc;
-+      iv[2].iov_len  = 1;
-+
-+      memset(&msg, 0, sizeof(msg));
-+      msg.msg_iovlen = 3;
-+      msg.msg_iov = iv;
-+      return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
-+}
-+
-+static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
-+{
-+      struct rfcomm_hdr *hdr;
-+      u8 buf[16], *ptr = buf;
-+
-+      BT_DBG("%p addr %d credits %d", s, addr, credits);
-+
-+      hdr = (void *) ptr; ptr += sizeof(*hdr);
-+      hdr->addr = addr;
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
-+      hdr->len  = __len8(0);
-+
-+      *ptr = credits; ptr++;
-+
-+      *ptr = __fcs(buf); ptr++;
-+
-+      return rfcomm_send_frame(s, buf, ptr - buf);
-+}
-+
-+static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
-+{
-+      struct rfcomm_hdr *hdr;
-+      int len = skb->len;
-+      u8 *crc;
-+
-+      if (len > 127) {
-+              hdr = (void *) skb_push(skb, 4);
-+              put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
-+      } else {
-+              hdr = (void *) skb_push(skb, 3);
-+              hdr->len = __len8(len);
-+      }
-+      hdr->addr = addr;
-+      hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
-+
-+      crc = skb_put(skb, 1);
-+      *crc = __fcs((void *) hdr);
-+}
-+
-+/* ---- RFCOMM frame reception ---- */
-+static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
-+{
-+      BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+      if (dlci) {
-+              /* Data channel */
-+              struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+              if (!d) {
-+                      rfcomm_send_dm(s, dlci);
-+                      return 0;
-+              }
-+
-+              switch (d->state) {
-+              case BT_CONNECT:
-+                      rfcomm_dlc_clear_timer(d);
-+
-+                      rfcomm_dlc_lock(d);
-+                      d->state = BT_CONNECTED;
-+                      d->state_change(d, 0);
-+                      rfcomm_dlc_unlock(d);
-+
-+                      rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+                      break;
-+
-+              case BT_DISCONN:
-+                      d->state = BT_CLOSED;
-+                      __rfcomm_dlc_close(d, 0);
-+                      break;
-+              }
-+      } else {
-+              /* Control channel */
-+              switch (s->state) {
-+              case BT_CONNECT:
-+                      s->state = BT_CONNECTED;
-+                      rfcomm_process_connect(s);
-+                      break;
-+              }
-+      }
-+      return 0;
-+}
-+
-+static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
-+{
-+      int err = 0;
-+
-+      BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+      if (dlci) {
-+              /* Data DLC */
-+              struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+              if (d) {
-+                      if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+                              err = ECONNREFUSED;
-+                      else
-+                              err = ECONNRESET;
-+
-+                      d->state = BT_CLOSED;
-+                      __rfcomm_dlc_close(d, err);
-+              }
-+      } else {
-+              if (s->state == BT_CONNECT)
-+                      err = ECONNREFUSED;
-+              else
-+                      err = ECONNRESET;
-+
-+              s->state = BT_CLOSED;
-+              rfcomm_session_close(s, err);
-+      }
-+      return 0;
-+}
-+
-+static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
-+{
-+      int err = 0;
-+
-+      BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+      if (dlci) {
-+              struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
-+              if (d) {
-+                      rfcomm_send_ua(s, dlci);
-+
-+                      if (d->state == BT_CONNECT || d->state == BT_CONFIG)
-+                              err = ECONNREFUSED;
-+                      else
-+                              err = ECONNRESET;
-+
-+                      d->state = BT_CLOSED;
-+                      __rfcomm_dlc_close(d, err);
-+              } else 
-+                      rfcomm_send_dm(s, dlci);
-+                      
-+      } else {
-+              rfcomm_send_ua(s, 0);
-+
-+              if (s->state == BT_CONNECT)
-+                      err = ECONNREFUSED;
-+              else
-+                      err = ECONNRESET;
-+
-+              s->state = BT_CLOSED;
-+              rfcomm_session_close(s, err);
-+      }
-+
-+      return 0;
-+}
-+
-+static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
-+{
-+      struct rfcomm_dlc *d;
-+      u8 channel;
-+
-+      BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+      if (!dlci) {
-+              rfcomm_send_ua(s, 0);
-+
-+              if (s->state == BT_OPEN) {
-+                      s->state = BT_CONNECTED;
-+                      rfcomm_process_connect(s);
-+              }
-+              return 0;
-+      }
-+
-+      /* Check if DLC exists */
-+      d = rfcomm_dlc_get(s, dlci);
-+      if (d) {
-+              if (d->state == BT_OPEN) {
-+                      /* DLC was previously opened by PN request */
-+                      rfcomm_send_ua(s, dlci);
-+
-+                      rfcomm_dlc_lock(d);
-+                      d->state = BT_CONNECTED;
-+                      d->state_change(d, 0);
-+                      rfcomm_dlc_unlock(d);
-+
-+                      rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+              }
-+              return 0;
-+      }
-+
-+      /* Notify socket layer about incomming connection */
-+      channel = __srv_channel(dlci);
-+      if (rfcomm_connect_ind(s, channel, &d)) {
-+              d->dlci = dlci;
-+              d->addr = __addr(s->initiator, dlci);
-+              rfcomm_dlc_link(s, d);
-+
-+              rfcomm_send_ua(s, dlci);
-+
-+              rfcomm_dlc_lock(d);
-+              d->state = BT_CONNECTED;
-+              d->state_change(d, 0);
-+              rfcomm_dlc_unlock(d);
-+
-+              rfcomm_send_msc(s, 1, dlci, d->v24_sig);
-+      } else {
-+              rfcomm_send_dm(s, dlci);
-+      }
-+
-+      return 0;
-+}
-+
-+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", 
-+                      d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
-+
-+      if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
-+              d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
-+              d->tx_credits = pn->credits;
-+      } else {
-+              d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
-+              set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+      }
-+
-+      d->priority = pn->priority;
-+
-+      d->mtu = s->mtu = btohs(pn->mtu);
-+
-+      return 0;
-+}
-+
-+static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+      struct rfcomm_pn *pn = (void *) skb->data;
-+      struct rfcomm_dlc *d;
-+      u8 dlci = pn->dlci;
-+
-+      BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
-+
-+      if (!dlci)
-+              return 0;
-+
-+      d = rfcomm_dlc_get(s, dlci);
-+      if (d) {
-+              if (cr) {
-+                      /* PN request */
-+                      rfcomm_apply_pn(d, cr, pn);
-+                      rfcomm_send_pn(s, 0, d);
-+              } else {
-+                      /* PN response */
-+                      switch (d->state) {
-+                      case BT_CONFIG:
-+                              rfcomm_apply_pn(d, cr, pn);
-+
-+                              d->state = BT_CONNECT;
-+                              rfcomm_send_sabm(s, d->dlci);
-+                              break;
-+                      }
-+              }
-+      } else {
-+              u8 channel = __srv_channel(dlci);
-+
-+              if (!cr)
-+                      return 0;
-+
-+              /* PN request for non existing DLC.
-+               * Assume incomming connection. */
-+              if (rfcomm_connect_ind(s, channel, &d)) {
-+                      d->dlci = dlci;
-+                      d->addr = __addr(s->initiator, dlci);
-+                      rfcomm_dlc_link(s, d);
-+
-+                      rfcomm_apply_pn(d, cr, pn);
-+
-+                      d->state = BT_OPEN;
-+                      rfcomm_send_pn(s, 0, d);
-+              } else {
-+                      rfcomm_send_dm(s, dlci);
-+              }
-+      }
-+      return 0;
-+}
-+
-+static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
-+{
-+      struct rfcomm_rpn *rpn = (void *) skb->data;
-+      u8 dlci = __get_dlci(rpn->dlci);
-+
-+      u8 bit_rate  = 0;
-+      u8 data_bits = 0;
-+      u8 stop_bits = 0;
-+      u8 parity    = 0;
-+      u8 flow_ctrl = 0;
-+      u8 xon_char  = 0;
-+      u8 xoff_char = 0;
-+      u16 rpn_mask = RFCOMM_RPN_PM_ALL;
-+      
-+      BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
-+             dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
-+             rpn->xon_char, rpn->xoff_char, rpn->param_mask);
-+      
-+      if (!cr) 
-+              return 0;
-+      
-+      if (len == 1) {
-+              /* request: return default setting */
-+              bit_rate  = RFCOMM_RPN_BR_115200;
-+              data_bits = RFCOMM_RPN_DATA_8;
-+              stop_bits = RFCOMM_RPN_STOP_1;
-+              parity    = RFCOMM_RPN_PARITY_NONE;
-+              flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+              xon_char  = RFCOMM_RPN_XON_CHAR;
-+              xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+
-+              goto rpn_out;
-+      }
-+      /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
-+                                no flow control lines, normal XON/XOFF chars */
-+      if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
-+              bit_rate = rpn->bit_rate;
-+              if (bit_rate != RFCOMM_RPN_BR_115200) {
-+                      BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
-+                      bit_rate = RFCOMM_RPN_BR_115200;
-+                      rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
-+              data_bits = __get_rpn_data_bits(rpn->line_settings);
-+              if (data_bits != RFCOMM_RPN_DATA_8) {
-+                      BT_DBG("RPN data bits mismatch 0x%x", data_bits);
-+                      data_bits = RFCOMM_RPN_DATA_8;
-+                      rpn_mask ^= RFCOMM_RPN_PM_DATA;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
-+              stop_bits = __get_rpn_stop_bits(rpn->line_settings);
-+              if (stop_bits != RFCOMM_RPN_STOP_1) {
-+                      BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
-+                      stop_bits = RFCOMM_RPN_STOP_1;
-+                      rpn_mask ^= RFCOMM_RPN_PM_STOP;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
-+              parity = __get_rpn_parity(rpn->line_settings);
-+              if (parity != RFCOMM_RPN_PARITY_NONE) {
-+                      BT_DBG("RPN parity mismatch 0x%x", parity);
-+                      parity = RFCOMM_RPN_PARITY_NONE;
-+                      rpn_mask ^= RFCOMM_RPN_PM_PARITY;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
-+              flow_ctrl = rpn->flow_ctrl;
-+              if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
-+                      BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
-+                      flow_ctrl = RFCOMM_RPN_FLOW_NONE;
-+                      rpn_mask ^= RFCOMM_RPN_PM_FLOW;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
-+              xon_char = rpn->xon_char;
-+              if (xon_char != RFCOMM_RPN_XON_CHAR) {
-+                      BT_DBG("RPN XON char mismatch 0x%x", xon_char);
-+                      xon_char = RFCOMM_RPN_XON_CHAR;
-+                      rpn_mask ^= RFCOMM_RPN_PM_XON;
-+              }
-+      }
-+      if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
-+              xoff_char = rpn->xoff_char;
-+              if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
-+                      BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
-+                      xoff_char = RFCOMM_RPN_XOFF_CHAR;
-+                      rpn_mask ^= RFCOMM_RPN_PM_XOFF;
-+              }
-+      }
-+
-+rpn_out:
-+      rfcomm_send_rpn(s, 0, dlci, 
-+                      bit_rate, data_bits, stop_bits, parity, flow_ctrl,
-+                      xon_char, xoff_char, rpn_mask);
-+
-+      return 0;
-+}
-+
-+static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+      struct rfcomm_rls *rls = (void *) skb->data;
-+      u8 dlci = __get_dlci(rls->dlci);
-+
-+      BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
-+      
-+      if (!cr)
-+              return 0;
-+
-+      /* FIXME: We should probably do something with this
-+         information here. But for now it's sufficient just
-+         to reply -- Bluetooth 1.1 says it's mandatory to 
-+         recognise and respond to RLS */
-+
-+      rfcomm_send_rls(s, 0, dlci, rls->status);
-+
-+      return 0;
-+}
-+
-+static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
-+{
-+      struct rfcomm_msc *msc = (void *) skb->data;
-+      struct rfcomm_dlc *d;
-+      u8 dlci = __get_dlci(msc->dlci);
-+
-+      BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
-+
-+      d = rfcomm_dlc_get(s, dlci);
-+      if (!d)
-+              return 0;
-+
-+      if (cr) {
-+              if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
-+                      set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+              else
-+                      clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+              
-+              rfcomm_dlc_lock(d);
-+              if (d->modem_status)
-+                      d->modem_status(d, msc->v24_sig);
-+              rfcomm_dlc_unlock(d);
-+              
-+              rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-+
-+              d->mscex |= RFCOMM_MSCEX_RX;
-+      } else 
-+              d->mscex |= RFCOMM_MSCEX_TX;
-+
-+      return 0;
-+}
-+
-+static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+      struct rfcomm_mcc *mcc = (void *) skb->data;
-+      u8 type, cr, len;
-+
-+      cr   = __test_cr(mcc->type);
-+      type = __get_mcc_type(mcc->type);
-+      len  = __get_mcc_len(mcc->len);
-+
-+      BT_DBG("%p type 0x%x cr %d", s, type, cr);
-+
-+      skb_pull(skb, 2);
-+
-+      switch (type) {
-+      case RFCOMM_PN:
-+              rfcomm_recv_pn(s, cr, skb);
-+              break;
-+
-+      case RFCOMM_RPN:
-+              rfcomm_recv_rpn(s, cr, len, skb);
-+              break;
-+
-+      case RFCOMM_RLS:
-+              rfcomm_recv_rls(s, cr, skb);
-+              break;
-+
-+      case RFCOMM_MSC:
-+              rfcomm_recv_msc(s, cr, skb);
-+              break;
-+
-+      case RFCOMM_FCOFF:
-+              if (cr) {
-+                      set_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+                      rfcomm_send_fcoff(s, 0);
-+              }
-+              break;
-+
-+      case RFCOMM_FCON:
-+              if (cr) {
-+                      clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
-+                      rfcomm_send_fcon(s, 0);
-+              }
-+              break;
-+
-+      case RFCOMM_TEST:
-+              if (cr)
-+                      rfcomm_send_test(s, 0, skb->data, skb->len);
-+              break;
-+
-+      case RFCOMM_NSC:
-+              break;
-+
-+      default:
-+              BT_ERR("Unknown control type 0x%02x", type);
-+              rfcomm_send_nsc(s, cr, type);
-+              break;
-+      }
-+      return 0;
-+}
-+
-+static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
-+{
-+      struct rfcomm_dlc *d;
-+
-+      BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
-+
-+      d = rfcomm_dlc_get(s, dlci);
-+      if (!d) {
-+              rfcomm_send_dm(s, dlci);
-+              goto drop;
-+      }
-+
-+      if (pf && d->cfc) {
-+              u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
-+
-+              d->tx_credits += credits;
-+              if (d->tx_credits)
-+                      clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+      }
-+
-+      if (skb->len && d->state == BT_CONNECTED) {
-+              rfcomm_dlc_lock(d);
-+              d->rx_credits--;
-+              d->data_ready(d, skb);
-+              rfcomm_dlc_unlock(d);
-+              return 0;
-+      }
-+
-+drop:
-+      kfree_skb(skb);
-+      return 0;
-+}
-+
-+static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
-+{
-+      struct rfcomm_hdr *hdr = (void *) skb->data;
-+      u8 type, dlci, fcs;
-+
-+      dlci = __get_dlci(hdr->addr);
-+      type = __get_type(hdr->ctrl);
-+
-+      /* Trim FCS */
-+      skb->len--; skb->tail--;
-+      fcs = *(u8 *) skb->tail;
-+      
-+      if (__check_fcs(skb->data, type, fcs)) {
-+              BT_ERR("bad checksum in packet");
-+              kfree_skb(skb);
-+              return -EILSEQ;
-+      }
-+
-+      if (__test_ea(hdr->len))
-+              skb_pull(skb, 3);
-+      else
-+              skb_pull(skb, 4);
-+      
-+      switch (type) {
-+      case RFCOMM_SABM:
-+              if (__test_pf(hdr->ctrl))
-+                      rfcomm_recv_sabm(s, dlci);
-+              break;
-+
-+      case RFCOMM_DISC:
-+              if (__test_pf(hdr->ctrl))
-+                      rfcomm_recv_disc(s, dlci);
-+              break;
-+
-+      case RFCOMM_UA:
-+              if (__test_pf(hdr->ctrl))
-+                      rfcomm_recv_ua(s, dlci);
-+              break;
-+
-+      case RFCOMM_DM:
-+              rfcomm_recv_dm(s, dlci);
-+              break;
-+
-+      case RFCOMM_UIH:
-+              if (dlci)
-+                      return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-+
-+              rfcomm_recv_mcc(s, skb);
-+              break;
-+
-+      default:
-+              BT_ERR("Unknown packet type 0x%02x\n", type);
-+              break;
-+      }
-+      kfree_skb(skb);
-+      return 0;
-+}
-+
-+/* ---- Connection and data processing ---- */
-+
-+static void rfcomm_process_connect(struct rfcomm_session *s)
-+{
-+      struct rfcomm_dlc *d;
-+      struct list_head *p, *n;
-+
-+      BT_DBG("session %p state %ld", s, s->state);
-+
-+      list_for_each_safe(p, n, &s->dlcs) {
-+              d = list_entry(p, struct rfcomm_dlc, list);
-+              if (d->state == BT_CONFIG) {
-+                      d->mtu = s->mtu;
-+                      rfcomm_send_pn(s, 1, d);
-+              }
-+      }
-+}
-+
-+/* Send data queued for the DLC.
-+ * Return number of frames left in the queue.
-+ */
-+static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
-+{
-+      struct sk_buff *skb;
-+      int err;
-+
-+      BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", 
-+                      d, d->state, d->cfc, d->rx_credits, d->tx_credits);
-+
-+      /* Send pending MSC */
-+      if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
-+              rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
-+      
-+      if (d->cfc) {
-+              /* CFC enabled. 
-+               * Give them some credits */
-+              if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
-+                              d->rx_credits <= (d->cfc >> 2)) {
-+                      rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
-+                      d->rx_credits = d->cfc;
-+              }
-+      } else {
-+              /* CFC disabled. 
-+               * Give ourselves some credits */
-+              d->tx_credits = 5;
-+      }
-+
-+      if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
-+              return skb_queue_len(&d->tx_queue);
-+
-+      while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-+              err = rfcomm_send_frame(d->session, skb->data, skb->len);
-+              if (err < 0) {
-+                      skb_queue_head(&d->tx_queue, skb);
-+                      break;
-+              }
-+              kfree_skb(skb);
-+              d->tx_credits--;
-+      }
-+
-+      if (d->cfc && !d->tx_credits) {
-+              /* We're out of TX credits.
-+               * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
-+              set_bit(RFCOMM_TX_THROTTLED, &d->flags);
-+      }
-+
-+      return skb_queue_len(&d->tx_queue);
-+}
-+
-+static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
-+{
-+      struct rfcomm_dlc *d;
-+      struct list_head *p, *n;
-+
-+      BT_DBG("session %p state %ld", s, s->state);
-+
-+      list_for_each_safe(p, n, &s->dlcs) {
-+              d = list_entry(p, struct rfcomm_dlc, list);
-+              if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
-+                      __rfcomm_dlc_close(d, ETIMEDOUT);
-+                      continue;
-+              }
-+
-+              if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
-+                      continue;
-+
-+              if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
-+                              d->mscex == RFCOMM_MSCEX_OK)
-+                      rfcomm_process_tx(d);
-+      }
-+}
-+
-+static inline void rfcomm_process_rx(struct rfcomm_session *s)
-+{
-+      struct socket *sock = s->sock;
-+      struct sock *sk = sock->sk;
-+      struct sk_buff *skb;
-+
-+      BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
-+
-+      /* Get data directly from socket receive queue without copying it. */
-+      while ((skb = skb_dequeue(&sk->receive_queue))) {
-+              skb_orphan(skb);
-+              rfcomm_recv_frame(s, skb);
-+      }
-+
-+      if (sk->state == BT_CLOSED) {
-+              if (!s->initiator)
-+                      rfcomm_session_put(s);
-+
-+              rfcomm_session_close(s, sk->err);
-+      }
-+}
-+
-+static inline void rfcomm_accept_connection(struct rfcomm_session *s)
-+{
-+      struct socket *sock = s->sock, *nsock;
-+      int err;
-+
-+      /* Fast check for a new connection.
-+       * Avoids unnesesary socket allocations. */
-+      if (list_empty(&bluez_pi(sock->sk)->accept_q))
-+              return;
-+
-+      BT_DBG("session %p", s);
-+
-+      nsock = sock_alloc();
-+      if (!nsock)
-+              return;
-+
-+      nsock->type = sock->type;
-+      nsock->ops  = sock->ops;
-+      
-+      err = sock->ops->accept(sock, nsock, O_NONBLOCK);
-+      if (err < 0) {
-+              sock_release(nsock);
-+              return;
-+      }
-+
-+      /* Set our callbacks */
-+      nsock->sk->data_ready   = rfcomm_l2data_ready;
-+      nsock->sk->state_change = rfcomm_l2state_change;
-+
-+      s = rfcomm_session_add(nsock, BT_OPEN);
-+      if (s)
-+              rfcomm_session_hold(s);
-+      else
-+              sock_release(nsock);
-+}
-+
-+static inline void rfcomm_check_connection(struct rfcomm_session *s)
-+{
-+      struct sock *sk = s->sock->sk;
-+
-+      BT_DBG("%p state %ld", s, s->state);
-+
-+      switch(sk->state) {
-+      case BT_CONNECTED:
-+              s->state = BT_CONNECT;
-+
-+              /* We can adjust MTU on outgoing sessions.
-+               * L2CAP MTU minus UIH header and FCS. */
-+              s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
-+
-+              rfcomm_send_sabm(s, 0);
-+              break;
-+
-+      case BT_CLOSED:
-+              s->state = BT_CLOSED;
-+              rfcomm_session_close(s, sk->err);
-+              break;
-+      }
-+}
-+
-+static inline void rfcomm_process_sessions(void)
-+{
-+      struct list_head *p, *n;
-+
-+      rfcomm_lock();
-+
-+      list_for_each_safe(p, n, &session_list) {
-+              struct rfcomm_session *s;
-+              s = list_entry(p, struct rfcomm_session, list);
-+
-+              if (s->state == BT_LISTEN) {
-+                      rfcomm_accept_connection(s);
-+                      continue;
-+              }
-+
-+              rfcomm_session_hold(s);
-+
-+              switch (s->state) {
-+              case BT_BOUND:
-+                      rfcomm_check_connection(s);
-+                      break;
-+
-+              default:
-+                      rfcomm_process_rx(s);
-+                      break;
-+              }
-+
-+              rfcomm_process_dlcs(s);
-+
-+              rfcomm_session_put(s);
-+      }
-+      
-+      rfcomm_unlock();
-+}
-+
-+static void rfcomm_worker(void)
-+{
-+      BT_DBG("");
-+
-+      daemonize(); reparent_to_init();
-+      set_fs(KERNEL_DS);
-+
-+      while (!atomic_read(&terminate)) {
-+              BT_DBG("worker loop event 0x%lx", rfcomm_event);
-+
-+              if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
-+                      /* No pending events. Let's sleep.
-+                       * Incomming connections and data will wake us up. */
-+                      set_current_state(TASK_INTERRUPTIBLE);
-+                      schedule();
-+              }
-+
-+              /* Process stuff */
-+              clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
-+              rfcomm_process_sessions();
-+      }
-+      set_current_state(TASK_RUNNING);
-+      return;
-+}
-+
-+static int rfcomm_add_listener(bdaddr_t *ba)
-+{
-+      struct sockaddr_l2 addr;
-+      struct l2cap_options opts;
-+      struct socket *sock;
-+      struct rfcomm_session *s;
-+      int    size, err = 0;
-+
-+      /* Create socket */
-+      err = rfcomm_l2sock_create(&sock);
-+      if (err < 0) { 
-+              BT_ERR("Create socket failed %d", err);
-+              return err;
-+      }
-+
-+      /* Bind socket */
-+      bacpy(&addr.l2_bdaddr, ba);
-+      addr.l2_family = AF_BLUETOOTH;
-+      addr.l2_psm    = htobs(RFCOMM_PSM);
-+      err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-+      if (err < 0) {
-+              BT_ERR("Bind failed %d", err);
-+              goto failed;
-+      }
-+
-+      /* Set L2CAP options */
-+      size = sizeof(opts);
-+      sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
-+
-+      opts.imtu = RFCOMM_MAX_L2CAP_MTU;
-+      sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
-+
-+      /* Start listening on the socket */
-+      err = sock->ops->listen(sock, 10);
-+      if (err) {
-+              BT_ERR("Listen failed %d", err);
-+              goto failed;
-+      }
-+
-+      /* Add listening session */
-+      s = rfcomm_session_add(sock, BT_LISTEN);
-+      if (!s)
-+              goto failed;
-+
-+      rfcomm_session_hold(s);
-+      return 0;
-+failed:
-+      sock_release(sock);
-+      return err;
-+}
-+
-+static void rfcomm_kill_listener(void)
-+{
-+      struct rfcomm_session *s;
-+      struct list_head *p, *n;
-+
-+      BT_DBG("");
-+
-+      list_for_each_safe(p, n, &session_list) {
-+              s = list_entry(p, struct rfcomm_session, list);
-+              rfcomm_session_del(s);
-+      }
-+}
-+
-+static int rfcomm_run(void *unused)
-+{
-+      rfcomm_thread = current;
-+
-+      atomic_inc(&running);
-+
-+      daemonize(); reparent_to_init();
-+
-+      sigfillset(&current->blocked);
-+      set_fs(KERNEL_DS);
-+
-+      sprintf(current->comm, "krfcommd");
-+
-+      BT_DBG("");
-+
-+      rfcomm_add_listener(BDADDR_ANY);
-+
-+      rfcomm_worker();
-+
-+      rfcomm_kill_listener();
-+
-+      atomic_dec(&running);
-+      return 0;
-+}
-+
-+/* ---- Proc fs support ---- */
-+static int rfcomm_dlc_dump(char *buf)
-+{
-+      struct rfcomm_session *s;
-+      struct sock *sk;
-+      struct list_head *p, *pp;
-+      char *ptr = buf;
-+
-+      rfcomm_lock();
-+
-+      list_for_each(p, &session_list) {
-+              s = list_entry(p, struct rfcomm_session, list);
-+              sk = s->sock->sk;
-+
-+              list_for_each(pp, &s->dlcs) {
-+              struct rfcomm_dlc *d;
-+                      d = list_entry(pp, struct rfcomm_dlc, list);
-+
-+                      ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
-+                              batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+                              d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
-+              }
-+      }
-+      
-+      rfcomm_unlock();
-+
-+      return ptr - buf;
-+}
-+
-+extern int rfcomm_sock_dump(char *buf);
-+
-+static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+      char *ptr = buf;
-+      int len;
-+
-+      BT_DBG("count %d, offset %ld", count, offset);
-+
-+      ptr += rfcomm_dlc_dump(ptr);
-+      ptr += rfcomm_sock_dump(ptr);
-+      len  = ptr - buf;
-+
-+      if (len <= count + offset)
-+              *eof = 1;
-+
-+      *start = buf + offset;
-+      len -= offset;
-+
-+      if (len > count)
-+              len = count;
-+      if (len < 0)
-+              len = 0;
-+
-+      return len;
-+}
-+
-+/* ---- Initialization ---- */
-+int __init rfcomm_init(void)
-+{
-+      l2cap_load();
-+
-+      kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-+
-+      rfcomm_init_sockets();
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+      rfcomm_init_ttys();
-+#endif
-+
-+      create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
-+
-+      BT_INFO("BlueZ RFCOMM ver %s", VERSION);
-+      BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
-+      BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
-+      return 0;
-+}
-+
-+void rfcomm_cleanup(void)
-+{
-+      /* 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();
-+
-+      remove_proc_entry("bluetooth/rfcomm", NULL);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+      rfcomm_cleanup_ttys();
-+#endif
-+
-+      rfcomm_cleanup_sockets();
-+      return;
-+}
-+
-+module_init(rfcomm_init);
-+module_exit(rfcomm_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
-+MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/crc.c   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,71 @@
-+/* 
-+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2002 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.
-+*/
-+
-+/*
-+ * RFCOMM FCS calculation.
-+ *
-+ * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $
-+ */
-+
-+/* reversed, 8-bit, poly=0x07 */
-+unsigned char rfcomm_crc_table[256] = { 
-+      0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
-+      0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
-+      0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
-+      0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
-+
-+      0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
-+      0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
-+      0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
-+      0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
-+
-+      0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
-+      0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
-+      0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
-+      0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
-+
-+      0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
-+      0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
-+      0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
-+      0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
-+
-+      0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
-+      0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
-+      0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
-+      0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
-+
-+      0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
-+      0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
-+      0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
-+      0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
-+
-+      0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
-+      0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
-+      0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
-+      0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
-+
-+      0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
-+      0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
-+      0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
-+      0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
-+};
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/Makefile        2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,11 @@
-+#
-+# Makefile for the Linux Bluetooth RFCOMM layer
-+#
-+
-+O_TARGET := rfcomm.o
-+
-+obj-y                         := core.o sock.o crc.o
-+obj-$(CONFIG_BLUEZ_RFCOMM_TTY)        += tty.o
-+obj-m                         += $(O_TARGET)
-+
-+include $(TOPDIR)/Rules.make
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/sock.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,847 @@
-+/* 
-+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2002 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.
-+*/
-+
-+/*
-+ * RFCOMM sockets.
-+ *
-+ * $Id: sock.c,v 1.30 2002/10/18 20:12:12 maxk Exp $
-+ */
-+
-+#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/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+static struct proto_ops rfcomm_sock_ops;
-+
-+static struct bluez_sock_list rfcomm_sk_list = {
-+      lock: RW_LOCK_UNLOCKED
-+};
-+
-+static void rfcomm_sock_close(struct sock *sk);
-+static void rfcomm_sock_kill(struct sock *sk);
-+
-+/* ---- DLC callbacks ----
-+ *
-+ * called under rfcomm_dlc_lock()
-+ */
-+static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
-+{
-+      struct sock *sk = d->owner;
-+      if (!sk)
-+              return;
-+
-+      atomic_add(skb->len, &sk->rmem_alloc);
-+      skb_queue_tail(&sk->receive_queue, skb);
-+      sk->data_ready(sk, skb->len);
-+
-+      if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
-+              rfcomm_dlc_throttle(d);
-+}
-+
-+static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
-+{
-+      struct sock *sk = d->owner, *parent;
-+      if (!sk)
-+              return;
-+
-+      BT_DBG("dlc %p state %ld err %d", d, d->state, err);
-+
-+      bh_lock_sock(sk);
-+
-+      if (err)
-+              sk->err = err;
-+      sk->state = d->state;
-+
-+      parent = bluez_pi(sk)->parent;
-+      if (!parent) {
-+              if (d->state == BT_CONNECTED)
-+                      rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
-+              sk->state_change(sk);
-+      } else
-+              parent->data_ready(parent, 0);
-+
-+      bh_unlock_sock(sk);
-+}
-+
-+/* ---- Socket functions ---- */
-+static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
-+{
-+      struct sock *sk;
-+
-+      for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+              if (rfcomm_pi(sk)->channel == channel && 
-+                              !bacmp(&bluez_pi(sk)->src, src))
-+                      break;
-+      }
-+
-+      return sk;
-+}
-+
-+/* Find socket with channel and source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+      struct sock *sk, *sk1 = NULL;
-+
-+      for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
-+              if (state && sk->state != state)
-+                      continue;
-+
-+              if (rfcomm_pi(sk)->channel == channel) {
-+                      /* Exact match. */
-+                      if (!bacmp(&bluez_pi(sk)->src, src))
-+                              break;
-+
-+                      /* Closest match */
-+                      if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+                              sk1 = sk;
-+              }
-+      }
-+      return sk ? sk : sk1;
-+}
-+
-+/* Find socket with given address (channel, src).
-+ * Returns locked socket */
-+static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-+{
-+      struct sock *s;
-+      read_lock(&rfcomm_sk_list.lock);
-+      s = __rfcomm_get_sock_by_channel(state, channel, src);
-+      if (s) bh_lock_sock(s);
-+      read_unlock(&rfcomm_sk_list.lock);
-+      return s;
-+}
-+
-+static void rfcomm_sock_destruct(struct sock *sk)
-+{
-+      struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+      BT_DBG("sk %p dlc %p", sk, d);
-+
-+      skb_queue_purge(&sk->receive_queue);
-+      skb_queue_purge(&sk->write_queue);
-+
-+      rfcomm_dlc_lock(d);
-+      rfcomm_pi(sk)->dlc = NULL;
-+      
-+      /* Detach DLC if it's owned by this socket */
-+      if (d->owner == sk)
-+              d->owner = NULL;
-+      rfcomm_dlc_unlock(d);
-+
-+      rfcomm_dlc_put(d);
-+
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static void rfcomm_sock_cleanup_listen(struct sock *parent)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("parent %p", parent);
-+
-+      /* Close not yet accepted dlcs */
-+      while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+              rfcomm_sock_close(sk);
-+              rfcomm_sock_kill(sk);
-+      }
-+
-+      parent->state  = BT_CLOSED;
-+      parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_kill(struct sock *sk)
-+{
-+      if (!sk->zapped || sk->socket)
-+              return;
-+
-+      BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
-+
-+      /* Kill poor orphan */
-+      bluez_sock_unlink(&rfcomm_sk_list, sk);
-+      sk->dead = 1;
-+      sock_put(sk);
-+}
-+
-+static void __rfcomm_sock_close(struct sock *sk)
-+{
-+      struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+
-+      BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
-+
-+      switch (sk->state) {
-+      case BT_LISTEN:
-+              rfcomm_sock_cleanup_listen(sk);
-+              break;
-+
-+      case BT_CONNECT:
-+      case BT_CONNECT2:
-+      case BT_CONFIG:
-+      case BT_CONNECTED:
-+              rfcomm_dlc_close(d, 0);
-+
-+      default:
-+              sk->zapped = 1;
-+              break;
-+      }
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void rfcomm_sock_close(struct sock *sk)
-+{
-+      lock_sock(sk);
-+      __rfcomm_sock_close(sk);
-+      release_sock(sk);
-+}
-+
-+static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
-+{
-+      BT_DBG("sk %p", sk);
-+
-+      if (parent) 
-+              sk->type = parent->type;
-+}
-+
-+static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+      struct rfcomm_dlc *d;
-+      struct sock *sk;
-+
-+      sk = sk_alloc(PF_BLUETOOTH, prio, 1);
-+      if (!sk)
-+              return NULL;
-+
-+      d = rfcomm_dlc_alloc(prio);
-+      if (!d) {
-+              sk_free(sk);
-+              return NULL;
-+      }
-+      d->data_ready   = rfcomm_sk_data_ready;
-+      d->state_change = rfcomm_sk_state_change;
-+
-+      rfcomm_pi(sk)->dlc = d;
-+      d->owner = sk;
-+
-+      bluez_sock_init(sock, sk);
-+
-+      sk->zapped   = 0;
-+
-+      sk->destruct = rfcomm_sock_destruct;
-+      sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
-+
-+      sk->sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+      sk->rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
-+
-+      sk->protocol = proto;
-+      sk->state    = BT_OPEN;
-+
-+      bluez_sock_link(&rfcomm_sk_list, sk);
-+
-+      BT_DBG("sk %p", sk);
-+
-+      MOD_INC_USE_COUNT;
-+      return sk;
-+}
-+
-+static int rfcomm_sock_create(struct socket *sock, int protocol)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("sock %p", sock);
-+
-+      sock->state = SS_UNCONNECTED;
-+
-+      if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
-+              return -ESOCKTNOSUPPORT;
-+
-+      sock->ops = &rfcomm_sock_ops;
-+
-+      if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
-+              return -ENOMEM;
-+
-+      rfcomm_sock_init(sk, NULL);
-+      return 0;
-+}
-+
-+static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+      struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
-+
-+      if (!addr || addr->sa_family != AF_BLUETOOTH)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_OPEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      write_lock_bh(&rfcomm_sk_list.lock);
-+
-+      if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
-+              err = -EADDRINUSE;
-+      } else {
-+              /* Save source address */
-+              bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
-+              rfcomm_pi(sk)->channel = sa->rc_channel;
-+              sk->state = BT_BOUND;
-+      }
-+
-+      write_unlock_bh(&rfcomm_sk_list.lock);
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+      struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+      struct sock *sk = sock->sk;
-+      struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+      int err = 0;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
-+              return -EINVAL;
-+
-+      if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+              return -EBADFD;
-+
-+      if (sk->type != SOCK_STREAM)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      sk->state = BT_CONNECT;
-+      bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
-+      rfcomm_pi(sk)->channel = sa->rc_channel;
-+      
-+      err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
-+      if (!err)
-+              err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+                              sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int rfcomm_sock_listen(struct socket *sock, int backlog)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_BOUND) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      sk->max_ack_backlog = backlog;
-+      sk->ack_backlog = 0;
-+      sk->state = BT_LISTEN;
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct sock *sk = sock->sk, *nsk;
-+      long timeo;
-+      int err = 0;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_LISTEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+      BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+      /* Wait for an incoming connection. (wake-one). */
-+      add_wait_queue_exclusive(sk->sleep, &wait);
-+      while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+              if (!timeo) {
-+                      err = -EAGAIN;
-+                      break;
-+              }
-+
-+              release_sock(sk);
-+              timeo = schedule_timeout(timeo);
-+              lock_sock(sk);
-+
-+              if (sk->state != BT_LISTEN) {
-+                      err = -EBADFD;
-+                      break;
-+              }
-+
-+              if (signal_pending(current)) {
-+                      err = sock_intr_errno(timeo);
-+                      break;
-+              }
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+
-+      if (err)
-+              goto done;
-+
-+      newsock->state = SS_CONNECTED;
-+
-+      BT_DBG("new socket %p", nsk);
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+      struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
-+      struct sock *sk = sock->sk;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      sa->rc_family  = AF_BLUETOOTH;
-+      sa->rc_channel = rfcomm_pi(sk)->channel;
-+      if (peer)
-+              bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
-+      else
-+              bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
-+
-+      *len = sizeof(struct sockaddr_rc);
-+      return 0;
-+}
-+
-+static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-+                             struct scm_cookie *scm)
-+{
-+      struct sock *sk = sock->sk;
-+      struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
-+      struct sk_buff *skb;
-+      int err, size;
-+      int sent = 0;
-+
-+      if (msg->msg_flags & MSG_OOB)
-+              return -EOPNOTSUPP;
-+
-+      if (sk->shutdown & SEND_SHUTDOWN)
-+              return -EPIPE;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      lock_sock(sk);
-+
-+      while (len) {
-+              size = min_t(uint, len, d->mtu);
-+              
-+              skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
-+                              msg->msg_flags & MSG_DONTWAIT, &err);
-+              if (!skb)
-+                      break;
-+              skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+              err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
-+              if (err) {
-+                      kfree_skb(skb);
-+                      sent = err;
-+                      break;
-+              }
-+
-+              err = rfcomm_dlc_send(d, skb);
-+              if (err < 0) {
-+                      kfree_skb(skb);
-+                      break;
-+              }
-+
-+              sent += size;
-+              len  -= size;
-+      }
-+
-+      release_sock(sk);
-+
-+      return sent ? sent : err;
-+}
-+
-+static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+
-+      add_wait_queue(sk->sleep, &wait);
-+      for (;;) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
-+                              signal_pending(current) || !timeo)
-+                      break;
-+
-+              set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+              release_sock(sk);
-+              timeo = schedule_timeout(timeo);
-+              lock_sock(sk);
-+              clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
-+      }
-+
-+      __set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+      return timeo;
-+}
-+
-+static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-+                             int flags, struct scm_cookie *scm)
-+{
-+      struct sock *sk = sock->sk;
-+      int target, err = 0, copied = 0;
-+      long timeo;
-+
-+      if (flags & MSG_OOB)
-+              return -EOPNOTSUPP;
-+
-+      msg->msg_namelen = 0;
-+
-+      BT_DBG("sk %p size %d", sk, size);
-+
-+      lock_sock(sk);
-+
-+      target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
-+      timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
-+
-+      do {
-+              struct sk_buff *skb;
-+              int chunk;
-+
-+              skb = skb_dequeue(&sk->receive_queue);
-+              if (!skb) {
-+                      if (copied >= target)
-+                              break;
-+
-+                      if ((err = sock_error(sk)) != 0)
-+                              break;
-+                      if (sk->shutdown & RCV_SHUTDOWN)
-+                              break;
-+
-+                      err = -EAGAIN;
-+                      if (!timeo)
-+                              break;
-+
-+                      timeo = rfcomm_sock_data_wait(sk, timeo);
-+
-+                      if (signal_pending(current)) {
-+                              err = sock_intr_errno(timeo);
-+                              goto out;
-+                      }
-+                      continue;
-+              }
-+
-+              chunk = min_t(unsigned int, skb->len, size);
-+              if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
-+                      skb_queue_head(&sk->receive_queue, skb);
-+                      if (!copied)
-+                              copied = -EFAULT;
-+                      break;
-+              }
-+              copied += chunk;
-+              size   -= chunk;
-+
-+              if (!(flags & MSG_PEEK)) {
-+                      atomic_sub(chunk, &sk->rmem_alloc);
-+
-+                      skb_pull(skb, chunk);
-+                      if (skb->len) {
-+                              skb_queue_head(&sk->receive_queue, skb);
-+                              break;
-+                      }
-+                      kfree_skb(skb);
-+
-+              } else {
-+                      /* put message back and return */
-+                      skb_queue_head(&sk->receive_queue, skb);
-+                      break;
-+              }
-+      } while (size);
-+
-+out:
-+      if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
-+              rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
-+
-+      release_sock(sk);
-+      return copied ? : err;
-+}
-+
-+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      };
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      int len, err = 0; 
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (get_user(len, optlen))
-+              return -EFAULT;
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      };
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
-+{
-+      struct sock *sk = sock->sk;
-+      int err;
-+
-+      lock_sock(sk);
-+
-+#ifdef CONFIG_BLUEZ_RFCOMM_TTY
-+      err = rfcomm_dev_ioctl(sk, cmd, arg);
-+#else
-+      err = -EOPNOTSUPP;
-+#endif
-+
-+      release_sock(sk);
-+
-+      return err;
-+}
-+
-+static int rfcomm_sock_shutdown(struct socket *sock, int how)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (!sk) return 0;
-+
-+      lock_sock(sk);
-+      if (!sk->shutdown) {
-+              sk->shutdown = SHUTDOWN_MASK;
-+              __rfcomm_sock_close(sk);
-+
-+              if (sk->linger)
-+                      err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+      }
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int rfcomm_sock_release(struct socket *sock)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (!sk)
-+              return 0;
-+
-+      err = rfcomm_sock_shutdown(sock, 2);
-+
-+      sock_orphan(sk);
-+      rfcomm_sock_kill(sk);
-+      return err;
-+}
-+
-+/* ---- RFCOMM core layer callbacks ---- 
-+ *
-+ * called under rfcomm_lock()
-+ */
-+int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
-+{
-+      struct sock *sk, *parent;
-+      bdaddr_t src, dst;
-+      int result = 0;
-+
-+      BT_DBG("session %p channel %d", s, channel);
-+
-+      rfcomm_session_getaddr(s, &src, &dst);
-+
-+      /* Check if we have socket listening on this channel */
-+      parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
-+      if (!parent)
-+              return 0;
-+
-+      /* Check for backlog size */
-+      if (parent->ack_backlog > parent->max_ack_backlog) {
-+              BT_DBG("backlog full %d", parent->ack_backlog); 
-+              goto done;
-+      }
-+
-+      sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
-+      if (!sk)
-+              goto done;
-+
-+      rfcomm_sock_init(sk, parent);
-+      bacpy(&bluez_pi(sk)->src, &src);
-+      bacpy(&bluez_pi(sk)->dst, &dst);
-+      rfcomm_pi(sk)->channel = channel;
-+
-+      sk->state = BT_CONFIG;
-+      bluez_accept_enqueue(parent, sk);
-+
-+      /* Accept connection and return socket DLC */
-+      *d = rfcomm_pi(sk)->dlc;
-+      result = 1;
-+
-+done:
-+      bh_unlock_sock(parent);
-+      return result;
-+}
-+
-+/* ---- Proc fs support ---- */
-+int rfcomm_sock_dump(char *buf)
-+{
-+      struct bluez_sock_list *list = &rfcomm_sk_list;
-+      struct rfcomm_pinfo *pi;
-+      struct sock *sk;
-+      char *ptr = buf;
-+
-+      write_lock_bh(&list->lock);
-+
-+      for (sk = list->head; sk; sk = sk->next) {
-+              pi = rfcomm_pi(sk);
-+              ptr += sprintf(ptr, "sk  %s %s %d %d\n",
-+                              batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+                              sk->state, rfcomm_pi(sk)->channel);
-+      }
-+
-+      write_unlock_bh(&list->lock);
-+
-+      return ptr - buf;
-+}
-+
-+static struct proto_ops rfcomm_sock_ops = {
-+      family:         PF_BLUETOOTH,
-+      release:        rfcomm_sock_release,
-+      bind:           rfcomm_sock_bind,
-+      connect:        rfcomm_sock_connect,
-+      listen:         rfcomm_sock_listen,
-+      accept:         rfcomm_sock_accept,
-+      getname:        rfcomm_sock_getname,
-+      sendmsg:        rfcomm_sock_sendmsg,
-+      recvmsg:        rfcomm_sock_recvmsg,
-+      shutdown:       rfcomm_sock_shutdown,
-+      setsockopt:     rfcomm_sock_setsockopt,
-+      getsockopt:     rfcomm_sock_getsockopt,
-+      ioctl:          rfcomm_sock_ioctl,
-+      poll:           bluez_sock_poll,
-+      socketpair:     sock_no_socketpair,
-+      mmap:           sock_no_mmap
-+};
-+
-+static struct net_proto_family rfcomm_sock_family_ops = {
-+      family:         PF_BLUETOOTH,
-+      create:         rfcomm_sock_create
-+};
-+
-+int rfcomm_init_sockets(void)
-+{
-+      int err;
-+
-+      if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
-+              BT_ERR("Can't register RFCOMM socket layer");
-+              return err;
-+      }
-+
-+      return 0;
-+}
-+
-+void rfcomm_cleanup_sockets(void)
-+{
-+      int err;
-+
-+      /* Unregister socket, protocol and notifier */
-+      if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
-+              BT_ERR("Can't unregister RFCOMM socket layer %d", err);
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/rfcomm/tty.c   2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,945 @@
-+/* 
-+   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
-+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
-+   Copyright (C) 2002 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.
-+*/
-+
-+/*
-+ * RFCOMM TTY.
-+ *
-+ * $Id: tty.c,v 1.26 2002/10/18 20:12:12 maxk Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+
-+#include <linux/tty.h>
-+#include <linux/tty_driver.h>
-+#include <linux/tty_flip.h>
-+
-+#include <linux/slab.h>
-+#include <linux/skbuff.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/rfcomm.h>
-+
-+#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG(D...)
-+#endif
-+
-+#define RFCOMM_TTY_MAGIC 0x6d02               /* magic number for rfcomm struct */
-+#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV       /* whole lotta rfcomm devices */
-+#define RFCOMM_TTY_MAJOR 216          /* device node major id of the usb/bluetooth.c driver */
-+#define RFCOMM_TTY_MINOR 0
-+
-+struct rfcomm_dev {
-+      struct list_head        list;
-+      atomic_t                refcnt;
-+
-+      char                    name[12];
-+      int                     id;
-+      unsigned long           flags;
-+      int                     opened;
-+      int                     err;
-+
-+      bdaddr_t                src;
-+      bdaddr_t                dst;
-+      u8                      channel;
-+
-+      uint                    modem_status;
-+
-+      struct rfcomm_dlc       *dlc;
-+      struct tty_struct       *tty;
-+      wait_queue_head_t       wait;
-+      struct tasklet_struct   wakeup_task;
-+
-+      atomic_t                wmem_alloc;
-+};
-+
-+static LIST_HEAD(rfcomm_dev_list);
-+static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
-+
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-+
-+static void rfcomm_tty_wakeup(unsigned long arg);
-+
-+/* ---- Device functions ---- */
-+static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
-+{
-+      struct rfcomm_dlc *dlc = dev->dlc;
-+
-+      BT_DBG("dev %p dlc %p", dev, dlc);
-+
-+      rfcomm_dlc_lock(dlc);
-+      /* Detach DLC if it's owned by this dev */
-+      if (dlc->owner == dev)
-+              dlc->owner = NULL;
-+      rfcomm_dlc_unlock(dlc);
-+
-+      rfcomm_dlc_put(dlc);
-+      kfree(dev);
-+
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-+{
-+      atomic_inc(&dev->refcnt);
-+}
-+
-+static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-+{
-+      if (atomic_dec_and_test(&dev->refcnt))
-+              rfcomm_dev_destruct(dev);
-+}
-+
-+static struct rfcomm_dev *__rfcomm_dev_get(int id)
-+{
-+      struct rfcomm_dev *dev;
-+      struct list_head  *p;
-+
-+      list_for_each(p, &rfcomm_dev_list) {
-+              dev = list_entry(p, struct rfcomm_dev, list);
-+              if (dev->id == id)
-+                      return dev;
-+      }
-+
-+      return NULL;
-+}
-+
-+static inline struct rfcomm_dev *rfcomm_dev_get(int id)
-+{
-+      struct rfcomm_dev *dev;
-+
-+      read_lock(&rfcomm_dev_lock);
-+      dev = __rfcomm_dev_get(id);
-+      read_unlock(&rfcomm_dev_lock);
-+
-+      if (dev) rfcomm_dev_hold(dev);
-+      return dev;
-+}
-+
-+static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
-+{
-+      struct rfcomm_dev *dev;
-+      struct list_head *head = &rfcomm_dev_list, *p;
-+      int err = 0;
-+
-+      BT_DBG("id %d channel %d", req->dev_id, req->channel);
-+      
-+      dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
-+      if (!dev)
-+              return -ENOMEM;
-+      memset(dev, 0, sizeof(struct rfcomm_dev));
-+
-+      write_lock_bh(&rfcomm_dev_lock);
-+
-+      if (req->dev_id < 0) {
-+              dev->id = 0;
-+
-+              list_for_each(p, &rfcomm_dev_list) {
-+                      if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
-+                              break;
-+
-+                      dev->id++;
-+                      head = p;
-+              }
-+      } else {
-+              dev->id = req->dev_id;
-+
-+              list_for_each(p, &rfcomm_dev_list) {
-+                      struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-+
-+                      if (entry->id == dev->id) {
-+                              err = -EADDRINUSE;
-+                              goto out;
-+                      }
-+
-+                      if (entry->id > dev->id - 1)
-+                              break;
-+
-+                      head = p;
-+              }
-+      }
-+
-+      if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
-+              err = -ENFILE;
-+              goto out;
-+      }
-+
-+      sprintf(dev->name, "rfcomm%d", dev->id);
-+
-+      list_add(&dev->list, head);
-+      atomic_set(&dev->refcnt, 1);
-+
-+      bacpy(&dev->src, &req->src);
-+      bacpy(&dev->dst, &req->dst);
-+      dev->channel = req->channel;
-+
-+      dev->flags = req->flags & 
-+              ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
-+
-+      init_waitqueue_head(&dev->wait);
-+      tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
-+
-+      rfcomm_dlc_lock(dlc);
-+      dlc->data_ready   = rfcomm_dev_data_ready;
-+      dlc->state_change = rfcomm_dev_state_change;
-+      dlc->modem_status = rfcomm_dev_modem_status;
-+
-+      dlc->owner = dev;
-+      dev->dlc   = dlc;
-+      rfcomm_dlc_unlock(dlc);
-+
-+      MOD_INC_USE_COUNT;
-+      
-+out:
-+      write_unlock_bh(&rfcomm_dev_lock);
-+
-+      if (err) {
-+              kfree(dev);
-+              return err;
-+      } else
-+              return dev->id;
-+}
-+
-+static void rfcomm_dev_del(struct rfcomm_dev *dev)
-+{
-+      BT_DBG("dev %p", dev);
-+
-+      write_lock_bh(&rfcomm_dev_lock);
-+      list_del_init(&dev->list);
-+      write_unlock_bh(&rfcomm_dev_lock);
-+
-+      rfcomm_dev_put(dev);
-+}
-+
-+/* ---- Send buffer ---- */
-+
-+static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
-+{
-+      /* We can't let it be zero, because we don't get a callback 
-+         when tx_credits becomes nonzero, hence we'd never wake up */
-+      return dlc->mtu * (dlc->tx_credits?:1);
-+}
-+
-+static void rfcomm_wfree(struct sk_buff *skb)
-+{
-+      struct rfcomm_dev *dev = (void *) skb->sk;
-+      atomic_sub(skb->truesize, &dev->wmem_alloc);
-+      if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-+              tasklet_schedule(&dev->wakeup_task);
-+      rfcomm_dev_put(dev);
-+}
-+
-+static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
-+{
-+      rfcomm_dev_hold(dev);
-+      atomic_add(skb->truesize, &dev->wmem_alloc);
-+      skb->sk = (void *) dev;
-+      skb->destructor = rfcomm_wfree;
-+}
-+
-+static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
-+{
-+      if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
-+              struct sk_buff *skb = alloc_skb(size, priority);
-+              if (skb) {
-+                      rfcomm_set_owner_w(skb, dev);
-+                      return skb;
-+              }
-+      }
-+      return NULL;
-+}
-+
-+/* ---- Device IOCTLs ---- */
-+
-+#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
-+
-+static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
-+{
-+      struct rfcomm_dev_req req;
-+      struct rfcomm_dlc *dlc;
-+      int id;
-+
-+      if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+              return -EFAULT;
-+
-+      BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
-+
-+      if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
-+              return -EPERM;
-+
-+      if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+              /* Socket must be connected */
-+              if (sk->state != BT_CONNECTED)
-+                      return -EBADFD;
-+
-+              dlc = rfcomm_pi(sk)->dlc;
-+              rfcomm_dlc_hold(dlc);
-+      } else {
-+              dlc = rfcomm_dlc_alloc(GFP_KERNEL);
-+              if (!dlc)
-+                      return -ENOMEM;
-+      }
-+
-+      id = rfcomm_dev_add(&req, dlc);
-+      if (id < 0) {
-+              rfcomm_dlc_put(dlc);
-+              return id;
-+      }
-+
-+      if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
-+              /* DLC is now used by device.
-+               * Socket must be disconnected */
-+              sk->state = BT_CLOSED;
-+      }
-+
-+      return id;
-+}
-+
-+static int rfcomm_release_dev(unsigned long arg)
-+{
-+      struct rfcomm_dev_req req;
-+      struct rfcomm_dev *dev;
-+
-+      if (copy_from_user(&req, (void *) arg, sizeof(req)))
-+              return -EFAULT;
-+
-+      BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
-+
-+      if (!capable(CAP_NET_ADMIN))
-+              return -EPERM;
-+
-+      if (!(dev = rfcomm_dev_get(req.dev_id)))
-+              return -ENODEV;
-+
-+      if (req.flags & (1 << RFCOMM_HANGUP_NOW))
-+              rfcomm_dlc_close(dev->dlc, 0);
-+
-+      rfcomm_dev_del(dev);
-+      rfcomm_dev_put(dev);
-+      return 0;
-+}
-+
-+static int rfcomm_get_dev_list(unsigned long arg)
-+{
-+      struct rfcomm_dev_list_req *dl;
-+      struct rfcomm_dev_info *di;
-+      struct list_head *p;
-+      int n = 0, size;
-+      u16 dev_num;
-+
-+      BT_DBG("");
-+
-+      if (get_user(dev_num, (u16 *) arg))
-+              return -EFAULT;
-+
-+      if (!dev_num)
-+              return -EINVAL;
-+
-+      size = sizeof(*dl) + dev_num * sizeof(*di);
-+
-+      if (verify_area(VERIFY_WRITE, (void *)arg, size))
-+              return -EFAULT;
-+
-+      if (!(dl = kmalloc(size, GFP_KERNEL)))
-+              return -ENOMEM;
-+
-+      di = dl->dev_info;
-+
-+      read_lock_bh(&rfcomm_dev_lock);
-+
-+      list_for_each(p, &rfcomm_dev_list) {
-+              struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
-+              (di + n)->id      = dev->id;
-+              (di + n)->flags   = dev->flags;
-+              (di + n)->state   = dev->dlc->state;
-+              (di + n)->channel = dev->channel;
-+              bacpy(&(di + n)->src, &dev->src);
-+              bacpy(&(di + n)->dst, &dev->dst);
-+              if (++n >= dev_num)
-+                      break;
-+      }
-+
-+      read_unlock_bh(&rfcomm_dev_lock);
-+
-+      dl->dev_num = n;
-+      size = sizeof(*dl) + n * sizeof(*di);
-+
-+      copy_to_user((void *) arg, dl, size);
-+      kfree(dl);
-+      return 0;
-+}
-+
-+static int rfcomm_get_dev_info(unsigned long arg)
-+{
-+      struct rfcomm_dev *dev;
-+      struct rfcomm_dev_info di;
-+      int err = 0;
-+
-+      BT_DBG("");
-+
-+      if (copy_from_user(&di, (void *)arg, sizeof(di)))
-+              return -EFAULT;
-+
-+      if (!(dev = rfcomm_dev_get(di.id)))
-+              return -ENODEV;
-+
-+      di.flags   = dev->flags;
-+      di.channel = dev->channel;
-+      di.state   = dev->dlc->state;
-+      bacpy(&di.src, &dev->src);
-+      bacpy(&di.dst, &dev->dst);
-+
-+      if (copy_to_user((void *)arg, &di, sizeof(di)))
-+              err = -EFAULT;
-+
-+      rfcomm_dev_put(dev);
-+      return err;
-+}
-+
-+int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
-+{
-+      BT_DBG("cmd %d arg %ld", cmd, arg);
-+
-+      switch (cmd) {
-+      case RFCOMMCREATEDEV:
-+              return rfcomm_create_dev(sk, arg);
-+
-+      case RFCOMMRELEASEDEV:
-+              return rfcomm_release_dev(arg);
-+
-+      case RFCOMMGETDEVLIST:
-+              return rfcomm_get_dev_list(arg);
-+
-+      case RFCOMMGETDEVINFO:
-+              return rfcomm_get_dev_info(arg);
-+      }
-+
-+      return -EINVAL;
-+}
-+
-+/* ---- DLC callbacks ---- */
-+static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
-+{
-+      struct rfcomm_dev *dev = dlc->owner;
-+      struct tty_struct *tty;
-+       
-+      if (!dev || !(tty = dev->tty)) {
-+              kfree_skb(skb);
-+              return;
-+      }
-+
-+      BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
-+
-+      if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-+              register int i;
-+              for (i = 0; i < skb->len; i++) {
-+                      if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-+                              tty_flip_buffer_push(tty);
-+
-+                      tty_insert_flip_char(tty, skb->data[i], 0);
-+              }
-+              tty_flip_buffer_push(tty);
-+      } else
-+              tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
-+
-+      kfree_skb(skb);
-+}
-+
-+static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
-+{
-+      struct rfcomm_dev *dev = dlc->owner;
-+      if (!dev)
-+              return;
-+      
-+      BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
-+
-+      dev->err = err;
-+      wake_up_interruptible(&dev->wait);
-+
-+      if (dlc->state == BT_CLOSED) {
-+              if (!dev->tty) {
-+                      if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
-+                              rfcomm_dev_hold(dev);
-+                              rfcomm_dev_del(dev);
-+
-+                              /* We have to drop DLC lock here, otherwise
-+                               * rfcomm_dev_put() will dead lock if it's the last refference */
-+                              rfcomm_dlc_unlock(dlc);
-+                              rfcomm_dev_put(dev);
-+                              rfcomm_dlc_lock(dlc);
-+                      }
-+              } else 
-+                      tty_hangup(dev->tty);
-+      }
-+}
-+
-+static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
-+{
-+      struct rfcomm_dev *dev = dlc->owner;
-+      if (!dev)
-+              return;
-+      
-+      BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
-+
-+      dev->modem_status = 
-+              ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
-+              ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
-+              ((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
-+              ((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
-+}
-+
-+/* ---- TTY functions ---- */
-+static void rfcomm_tty_wakeup(unsigned long arg)
-+{
-+      struct rfcomm_dev *dev = (void *) arg;
-+      struct tty_struct *tty = dev->tty;
-+      if (!tty)
-+              return;
-+
-+      BT_DBG("dev %p tty %p", dev, tty);
-+
-+      if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+                (tty->ldisc.write_wakeup)(tty);
-+
-+      wake_up_interruptible(&tty->write_wait);
-+#ifdef SERIAL_HAVE_POLL_WAIT
-+      wake_up_interruptible(&tty->poll_wait);
-+#endif
-+}
-+
-+static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct rfcomm_dev *dev;
-+      struct rfcomm_dlc *dlc;
-+      int err, id;
-+
-+      id = MINOR(tty->device) - tty->driver.minor_start;
-+
-+      BT_DBG("tty %p id %d", tty, id);
-+
-+      dev = rfcomm_dev_get(id);
-+      if (!dev)
-+              return -ENODEV;
-+
-+      BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
-+
-+      if (dev->opened++ != 0)
-+              return 0;
-+
-+      dlc = dev->dlc;
-+
-+      /* Attach TTY and open DLC */
-+
-+      rfcomm_dlc_lock(dlc);
-+      tty->driver_data = dev;
-+      dev->tty = tty;
-+      rfcomm_dlc_unlock(dlc);
-+      set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+
-+      err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
-+      if (err < 0)
-+              return err;
-+
-+      /* Wait for DLC to connect */
-+      add_wait_queue(&dev->wait, &wait);
-+      while (1) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+
-+              if (dlc->state == BT_CLOSED) {
-+                      err = -dev->err;
-+                      break;
-+              }
-+
-+              if (dlc->state == BT_CONNECTED)
-+                      break;
-+
-+              if (signal_pending(current)) {
-+                      err = -EINTR;
-+                      break;
-+              }
-+
-+              schedule();
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(&dev->wait, &wait);
-+
-+      return err;
-+}
-+
-+static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      if (!dev)
-+              return;
-+
-+      BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
-+
-+      if (--dev->opened == 0) {
-+              /* Close DLC and dettach TTY */
-+              rfcomm_dlc_close(dev->dlc, 0);
-+
-+              clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-+              tasklet_kill(&dev->wakeup_task);
-+
-+              rfcomm_dlc_lock(dev->dlc);
-+              tty->driver_data = NULL;
-+              dev->tty = NULL;
-+              rfcomm_dlc_unlock(dev->dlc);
-+      }
-+
-+      rfcomm_dev_put(dev);
-+}
-+
-+static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      struct rfcomm_dlc *dlc = dev->dlc;
-+      struct sk_buff *skb;
-+      int err = 0, sent = 0, size;
-+
-+      BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
-+
-+      while (count) {
-+              size = min_t(uint, count, dlc->mtu);
-+
-+              if (from_user)
-+                      skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
-+              else
-+                      skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
-+              
-+              if (!skb)
-+                      break;
-+
-+              skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+              if (from_user)
-+                      copy_from_user(skb_put(skb, size), buf + sent, size);
-+              else
-+                      memcpy(skb_put(skb, size), buf + sent, size);
-+
-+              if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
-+                      kfree_skb(skb);
-+                      break;
-+              }
-+
-+              sent  += size;
-+              count -= size;
-+      }
-+
-+      return sent ? sent : err;
-+}
-+
-+static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      struct rfcomm_dlc *dlc = dev->dlc;
-+      struct sk_buff *skb;
-+
-+      BT_DBG("tty %p char %x", tty, ch);
-+
-+      skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
-+
-+      if (!skb)
-+              return;
-+
-+      skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
-+
-+      *(char *)skb_put(skb, 1) = ch;
-+
-+      if ((rfcomm_dlc_send(dlc, skb)) < 0)
-+              kfree_skb(skb); 
-+}
-+
-+static int rfcomm_tty_write_room(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      int room;
-+      
-+      BT_DBG("tty %p", tty);
-+
-+      room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
-+      if (room < 0)
-+              room = 0;
-+
-+      return room;
-+}
-+
-+static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
-+{
-+      u8 v24_sig, mask;
-+
-+      BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
-+
-+      if (cmd == TIOCMSET)
-+              v24_sig = 0;
-+      else
-+              rfcomm_dlc_get_modem_status(dlc, &v24_sig);
-+
-+      mask =  ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
-+              ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
-+              ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
-+              ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
-+              ((status & TIOCM_RI)  ? RFCOMM_V24_IC  : 0) |
-+              ((status & TIOCM_CD)  ? RFCOMM_V24_DV  : 0);
-+
-+      if (cmd == TIOCMBIC)
-+              v24_sig &= ~mask;
-+      else
-+              v24_sig |= mask;
-+
-+      rfcomm_dlc_set_modem_status(dlc, v24_sig);
-+      return 0;
-+}
-+
-+static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      struct rfcomm_dlc *dlc = dev->dlc;
-+      uint status;
-+      int err;
-+
-+      BT_DBG("tty %p cmd 0x%02x", tty, cmd);
-+
-+      switch (cmd) {
-+      case TCGETS:
-+              BT_DBG("TCGETS is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TCSETS:
-+              BT_DBG("TCSETS is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TIOCMGET:
-+              BT_DBG("TIOCMGET");
-+
-+              return put_user(dev->modem_status, (unsigned int *)arg);
-+
-+      case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-+      case TIOCMBIS: /* Turns on the lines as specified by the mask */
-+      case TIOCMBIC: /* Turns off the lines as specified by the mask */
-+              if ((err = get_user(status, (unsigned int *)arg)))
-+                      return err;
-+              return rfcomm_tty_set_modem_status(cmd, dlc, status);
-+
-+      case TIOCMIWAIT:
-+              BT_DBG("TIOCMIWAIT");
-+              break;
-+
-+      case TIOCGICOUNT:
-+              BT_DBG("TIOCGICOUNT");
-+              break;
-+
-+      case TIOCGSERIAL:
-+              BT_ERR("TIOCGSERIAL is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TIOCSSERIAL:
-+              BT_ERR("TIOCSSERIAL is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TIOCSERGSTRUCT:
-+              BT_ERR("TIOCSERGSTRUCT is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TIOCSERGETLSR:
-+              BT_ERR("TIOCSERGETLSR is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      case TIOCSERCONFIG:
-+              BT_ERR("TIOCSERCONFIG is not supported");
-+              return -ENOIOCTLCMD;
-+
-+      default:
-+              return -ENOIOCTLCMD;    /* ioctls which we must ignore */
-+
-+      }
-+
-+      return -ENOIOCTLCMD;
-+}
-+
-+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-+
-+static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
-+{
-+      BT_DBG("tty %p", tty);
-+
-+      if ((tty->termios->c_cflag == old->c_cflag) &&
-+              (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
-+              return;
-+
-+      /* handle turning off CRTSCTS */
-+      if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
-+              BT_DBG("turning off CRTSCTS");
-+      }
-+}
-+
-+static void rfcomm_tty_throttle(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+      BT_DBG("tty %p dev %p", tty, dev);
-+      
-+      rfcomm_dlc_throttle(dev->dlc);
-+}
-+
-+static void rfcomm_tty_unthrottle(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+
-+      BT_DBG("tty %p dev %p", tty, dev);
-+      
-+      rfcomm_dlc_unthrottle(dev->dlc);
-+}
-+
-+static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      struct rfcomm_dlc *dlc = dev->dlc;
-+
-+      BT_DBG("tty %p dev %p", tty, dev);
-+
-+      if (skb_queue_len(&dlc->tx_queue))
-+              return dlc->mtu;
-+
-+      return 0;
-+}
-+
-+static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      if (!dev)
-+              return;
-+
-+      BT_DBG("tty %p dev %p", tty, dev);
-+
-+      skb_queue_purge(&dev->dlc->tx_queue);
-+
-+      if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
-+              tty->ldisc.write_wakeup(tty);
-+}
-+
-+static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
-+{
-+      BT_DBG("tty %p ch %c", tty, ch);
-+}
-+
-+static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
-+{
-+      BT_DBG("tty %p timeout %d", tty, timeout);
-+}
-+
-+static void rfcomm_tty_hangup(struct tty_struct *tty)
-+{
-+      struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
-+      if (!dev)
-+              return;
-+
-+      BT_DBG("tty %p dev %p", tty, dev);
-+
-+      rfcomm_tty_flush_buffer(tty);
-+
-+      if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
-+              rfcomm_dev_del(dev);
-+}
-+
-+static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
-+{
-+      return 0;
-+}
-+
-+/* ---- TTY structure ---- */
-+static int    rfcomm_tty_refcount;       /* If we manage several devices */
-+
-+static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
-+static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
-+
-+static struct tty_driver rfcomm_tty_driver = {
-+      magic:                  TTY_DRIVER_MAGIC,
-+      driver_name:            "rfcomm",
-+#ifdef CONFIG_DEVFS_FS
-+      name:                   "bluetooth/rfcomm/%d",
-+#else
-+      name:                   "rfcomm",
-+#endif
-+      major:                  RFCOMM_TTY_MAJOR,
-+      minor_start:            RFCOMM_TTY_MINOR,
-+      num:                    RFCOMM_TTY_PORTS,
-+      type:                   TTY_DRIVER_TYPE_SERIAL,
-+      subtype:                SERIAL_TYPE_NORMAL,
-+      flags:                  TTY_DRIVER_REAL_RAW,
-+
-+      refcount:               &rfcomm_tty_refcount,
-+      table:                  rfcomm_tty_table,
-+      termios:                rfcomm_tty_termios,
-+      termios_locked:         rfcomm_tty_termios_locked,
-+
-+      open:                   rfcomm_tty_open,
-+      close:                  rfcomm_tty_close,
-+      put_char:               rfcomm_tty_put_char,
-+      write:                  rfcomm_tty_write,
-+      write_room:             rfcomm_tty_write_room,
-+      chars_in_buffer:        rfcomm_tty_chars_in_buffer,
-+      flush_buffer:           rfcomm_tty_flush_buffer,
-+      ioctl:                  rfcomm_tty_ioctl,
-+      throttle:               rfcomm_tty_throttle,
-+      unthrottle:             rfcomm_tty_unthrottle,
-+      set_termios:            rfcomm_tty_set_termios,
-+      send_xchar:             rfcomm_tty_send_xchar,
-+      stop:                   NULL,
-+      start:                  NULL,
-+      hangup:                 rfcomm_tty_hangup,
-+      wait_until_sent:        rfcomm_tty_wait_until_sent,
-+      read_proc:              rfcomm_tty_read_proc,
-+};
-+
-+int rfcomm_init_ttys(void)
-+{
-+      int i;
-+
-+      /* Initalize our global data */
-+      for (i = 0; i < RFCOMM_TTY_PORTS; i++)
-+              rfcomm_tty_table[i] = NULL;
-+
-+      /* Register the TTY driver */
-+      rfcomm_tty_driver.init_termios = tty_std_termios;
-+      rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-+      rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
-+
-+      if (tty_register_driver(&rfcomm_tty_driver)) {
-+              BT_ERR("Can't register RFCOMM TTY driver");
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+void rfcomm_cleanup_ttys(void)
-+{
-+      tty_unregister_driver(&rfcomm_tty_driver);
-+      return;
-+}
---- /dev/null  1970-01-01 01:00:00.000000000 +0100
-+++ linux/net/bluetooth/sco.c  2004-01-25 23:37:39.000000000 +0100
-@@ -0,0 +1,1019 @@
-+/* 
-+   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 SCO sockets.
-+ *
-+ * $Id: sco.c,v 1.4 2002/07/22 20:32:54 maxk Exp $
-+ */
-+#define VERSION "0.3"
-+
-+#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/init.h>
-+#include <linux/skbuff.h>
-+#include <linux/interrupt.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <net/sock.h>
-+
-+#include <asm/system.h>
-+#include <asm/uaccess.h>
-+
-+#include <net/bluetooth/bluetooth.h>
-+#include <net/bluetooth/hci_core.h>
-+#include <net/bluetooth/sco.h>
-+
-+#ifndef SCO_DEBUG
-+#undef  BT_DBG
-+#define BT_DBG( A... )
-+#endif
-+
-+static struct proto_ops sco_sock_ops;
-+
-+static struct bluez_sock_list sco_sk_list = {
-+      lock: RW_LOCK_UNLOCKED
-+};
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
-+static void sco_chan_del(struct sock *sk, int err);
-+static inline struct sock * sco_chan_get(struct sco_conn *conn);
-+
-+static int  sco_conn_del(struct hci_conn *conn, int err);
-+
-+static void sco_sock_close(struct sock *sk);
-+static void sco_sock_kill(struct sock *sk);
-+
-+/* ----- SCO timers ------ */
-+static void sco_sock_timeout(unsigned long arg)
-+{
-+      struct sock *sk = (struct sock *) arg;
-+
-+      BT_DBG("sock %p state %d", sk, sk->state);
-+
-+      bh_lock_sock(sk);
-+      sk->err = ETIMEDOUT;
-+      sk->state_change(sk);
-+      bh_unlock_sock(sk);
-+
-+      sco_sock_kill(sk);
-+      sock_put(sk);
-+}
-+
-+static void sco_sock_set_timer(struct sock *sk, long timeout)
-+{
-+      BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
-+
-+      if (!mod_timer(&sk->timer, jiffies + timeout))
-+              sock_hold(sk);
-+}
-+
-+static void sco_sock_clear_timer(struct sock *sk)
-+{
-+      BT_DBG("sock %p state %d", sk, sk->state);
-+
-+      if (timer_pending(&sk->timer) && del_timer(&sk->timer))
-+              __sock_put(sk);
-+}
-+
-+static void sco_sock_init_timer(struct sock *sk)
-+{
-+      init_timer(&sk->timer);
-+      sk->timer.function = sco_sock_timeout;
-+      sk->timer.data = (unsigned long)sk;
-+}
-+
-+/* -------- SCO connections --------- */
-+static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
-+{
-+      struct hci_dev *hdev = hcon->hdev;
-+      struct sco_conn *conn;
-+
-+      if ((conn = hcon->sco_data))
-+              return conn;
-+
-+      if (status)
-+              return conn;
-+
-+      if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
-+              return NULL;
-+      memset(conn, 0, sizeof(struct sco_conn));
-+
-+      spin_lock_init(&conn->lock);
-+
-+      hcon->sco_data = conn;
-+      conn->hcon = hcon;
-+
-+      conn->src = &hdev->bdaddr;
-+      conn->dst = &hcon->dst;
-+      
-+      if (hdev->sco_mtu > 0)
-+              conn->mtu = hdev->sco_mtu;
-+      else
-+              conn->mtu = 60;
-+
-+      BT_DBG("hcon %p conn %p", hcon, conn);
-+
-+      MOD_INC_USE_COUNT;
-+      return conn;
-+}
-+
-+static int sco_conn_del(struct hci_conn *hcon, int err)
-+{
-+      struct sco_conn *conn;
-+      struct sock *sk;
-+
-+      if (!(conn = hcon->sco_data)) 
-+              return 0;
-+
-+      BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-+
-+      /* Kill socket */
-+      if ((sk = sco_chan_get(conn))) {
-+              bh_lock_sock(sk);
-+              sco_sock_clear_timer(sk);
-+              sco_chan_del(sk, err);
-+              bh_unlock_sock(sk);
-+              sco_sock_kill(sk);
-+      }
-+
-+      hcon->sco_data = NULL;
-+      kfree(conn);
-+
-+      MOD_DEC_USE_COUNT;
-+      return 0;
-+}
-+
-+int sco_connect(struct sock *sk)
-+{
-+      bdaddr_t *src = &bluez_pi(sk)->src;
-+      bdaddr_t *dst = &bluez_pi(sk)->dst;
-+      struct sco_conn *conn;
-+      struct hci_conn *hcon;
-+      struct hci_dev  *hdev;
-+      int err = 0;
-+
-+      BT_DBG("%s -> %s", batostr(src), batostr(dst));
-+
-+      if (!(hdev = hci_get_route(dst, src)))
-+              return -EHOSTUNREACH;
-+
-+      hci_dev_lock_bh(hdev);
-+
-+      err = -ENOMEM;
-+
-+      hcon = hci_connect(hdev, SCO_LINK, dst);
-+      if (!hcon)
-+              goto done;
-+
-+      conn = sco_conn_add(hcon, 0);
-+      if (!conn) {
-+              hci_conn_put(hcon);
-+              goto done;
-+      }
-+
-+      /* Update source addr of the socket */
-+      bacpy(src, conn->src);
-+
-+      err = sco_chan_add(conn, sk, NULL);
-+      if (err)
-+              goto done;
-+
-+      if (hcon->state == BT_CONNECTED) {
-+              sco_sock_clear_timer(sk);
-+              sk->state = BT_CONNECTED;
-+      } else {
-+              sk->state = BT_CONNECT;
-+              sco_sock_set_timer(sk, sk->sndtimeo);
-+      }
-+done:
-+      hci_dev_unlock_bh(hdev);
-+      hci_dev_put(hdev);
-+      return err;
-+}
-+
-+static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
-+{
-+      struct sco_conn *conn = sco_pi(sk)->conn;
-+      struct sk_buff *skb;
-+      int err, count;
-+
-+      /* Check outgoing MTU */
-+      if (len > conn->mtu)
-+              return -EINVAL;
-+
-+      BT_DBG("sk %p len %d", sk, len);
-+
-+      count = MIN(conn->mtu, len);
-+      if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
-+              return err;
-+
-+      if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-+              err = -EFAULT;
-+              goto fail;
-+      }
-+
-+      if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-+              goto fail;
-+
-+      return count;
-+
-+fail:
-+      kfree_skb(skb);
-+      return err;
-+}
-+
-+static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
-+{
-+      struct sock *sk = sco_chan_get(conn);
-+
-+      if (!sk)
-+              goto drop;
-+
-+      BT_DBG("sk %p len %d", sk, skb->len);
-+
-+      if (sk->state != BT_CONNECTED)
-+              goto drop;
-+
-+      if (!sock_queue_rcv_skb(sk, skb))
-+              return;
-+
-+drop:
-+      kfree_skb(skb);
-+      return;
-+}
-+
-+/* -------- Socket interface ---------- */
-+static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
-+{
-+      struct sock *sk;
-+
-+      for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+              if (!bacmp(&bluez_pi(sk)->src, ba))
-+                      break;
-+      }
-+
-+      return sk;
-+}
-+
-+/* Find socket listening on source bdaddr.
-+ * Returns closest match.
-+ */
-+static struct sock *sco_get_sock_listen(bdaddr_t *src)
-+{
-+      struct sock *sk, *sk1 = NULL;
-+
-+      read_lock(&sco_sk_list.lock);
-+
-+      for (sk = sco_sk_list.head; sk; sk = sk->next) {
-+              if (sk->state != BT_LISTEN)
-+                      continue;
-+
-+              /* Exact match. */
-+              if (!bacmp(&bluez_pi(sk)->src, src))
-+                      break;
-+
-+              /* Closest match */
-+              if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
-+                      sk1 = sk;
-+      }
-+
-+      read_unlock(&sco_sk_list.lock);
-+
-+      return sk ? sk : sk1;
-+}
-+
-+static void sco_sock_destruct(struct sock *sk)
-+{
-+      BT_DBG("sk %p", sk);
-+
-+      skb_queue_purge(&sk->receive_queue);
-+      skb_queue_purge(&sk->write_queue);
-+
-+      MOD_DEC_USE_COUNT;
-+}
-+
-+static void sco_sock_cleanup_listen(struct sock *parent)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("parent %p", parent);
-+
-+      /* Close not yet accepted channels */
-+      while ((sk = bluez_accept_dequeue(parent, NULL))) {
-+              sco_sock_close(sk);
-+              sco_sock_kill(sk);
-+      }
-+
-+      parent->state  = BT_CLOSED;
-+      parent->zapped = 1;
-+}
-+
-+/* Kill socket (only if zapped and orphan)
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_kill(struct sock *sk)
-+{
-+      if (!sk->zapped || sk->socket)
-+              return;
-+
-+      BT_DBG("sk %p state %d", sk, sk->state);
-+
-+      /* Kill poor orphan */
-+      bluez_sock_unlink(&sco_sk_list, sk);
-+      sk->dead = 1;
-+      sock_put(sk);
-+}
-+
-+/* Close socket.
-+ * Must be called on unlocked socket.
-+ */
-+static void sco_sock_close(struct sock *sk)
-+{
-+      struct sco_conn *conn;
-+
-+      sco_sock_clear_timer(sk);
-+
-+      lock_sock(sk);
-+
-+      conn = sco_pi(sk)->conn;
-+
-+      BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
-+
-+      switch (sk->state) {
-+      case BT_LISTEN:
-+              sco_sock_cleanup_listen(sk);
-+              break;
-+
-+      case BT_CONNECTED:
-+      case BT_CONFIG:
-+      case BT_CONNECT:
-+      case BT_DISCONN:
-+              sco_chan_del(sk, ECONNRESET);
-+              break;
-+
-+      default:
-+              sk->zapped = 1;
-+              break;
-+      };
-+
-+      release_sock(sk);
-+}
-+
-+static void sco_sock_init(struct sock *sk, struct sock *parent)
-+{
-+      BT_DBG("sk %p", sk);
-+
-+      if (parent) 
-+              sk->type = parent->type;
-+}
-+
-+static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
-+{
-+      struct sock *sk;
-+
-+      if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
-+              return NULL;
-+
-+      bluez_sock_init(sock, sk);
-+
-+      sk->zapped   = 0;
-+
-+      sk->destruct = sco_sock_destruct;
-+      sk->sndtimeo = SCO_CONN_TIMEOUT;
-+
-+      sk->protocol = proto;
-+      sk->state    = BT_OPEN;
-+
-+      sco_sock_init_timer(sk);
-+
-+      bluez_sock_link(&sco_sk_list, sk);
-+
-+      MOD_INC_USE_COUNT;
-+      return sk;
-+}
-+
-+static int sco_sock_create(struct socket *sock, int protocol)
-+{
-+      struct sock *sk;
-+
-+      BT_DBG("sock %p", sock);
-+
-+      sock->state = SS_UNCONNECTED;
-+
-+      if (sock->type != SOCK_SEQPACKET)
-+              return -ESOCKTNOSUPPORT;
-+
-+      sock->ops = &sco_sock_ops;
-+
-+      if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
-+              return -ENOMEM;
-+
-+      sco_sock_init(sk, NULL);
-+      return 0;
-+}
-+
-+static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
-+{
-+      struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+      struct sock *sk = sock->sk;
-+      bdaddr_t *src = &sa->sco_bdaddr;
-+      int err = 0;
-+
-+      BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
-+
-+      if (!addr || addr->sa_family != AF_BLUETOOTH)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_OPEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      write_lock_bh(&sco_sk_list.lock);
-+
-+      if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
-+              err = -EADDRINUSE;
-+      } else {
-+              /* Save source address */
-+              bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
-+              sk->state = BT_BOUND;
-+      }
-+
-+      write_unlock_bh(&sco_sk_list.lock);
-+
-+done:
-+      release_sock(sk);
-+
-+      return err;
-+}
-+
-+static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
-+{
-+      struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
-+              return -EINVAL;
-+
-+      if (sk->state != BT_OPEN && sk->state != BT_BOUND)
-+              return -EBADFD;
-+
-+      if (sk->type != SOCK_SEQPACKET)
-+              return -EINVAL;
-+
-+      lock_sock(sk);
-+
-+      /* Set destination address and psm */
-+      bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
-+
-+      if ((err = sco_connect(sk)))
-+              goto done;
-+
-+      err = bluez_sock_wait_state(sk, BT_CONNECTED,
-+                      sock_sndtimeo(sk, flags & O_NONBLOCK));
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int sco_sock_listen(struct socket *sock, int backlog)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p backlog %d", sk, backlog);
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      sk->max_ack_backlog = backlog;
-+      sk->ack_backlog = 0;
-+      sk->state = BT_LISTEN;
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      struct sock *sk = sock->sk, *ch;
-+      long timeo;
-+      int err = 0;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state != BT_LISTEN) {
-+              err = -EBADFD;
-+              goto done;
-+      }
-+
-+      timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
-+
-+      BT_DBG("sk %p timeo %ld", sk, timeo);
-+
-+      /* Wait for an incoming connection. (wake-one). */
-+      add_wait_queue_exclusive(sk->sleep, &wait);
-+      while (!(ch = bluez_accept_dequeue(sk, newsock))) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+              if (!timeo) {
-+                      err = -EAGAIN;
-+                      break;
-+              }
-+
-+              release_sock(sk);
-+              timeo = schedule_timeout(timeo);
-+              lock_sock(sk);
-+
-+              if (sk->state != BT_LISTEN) {
-+                      err = -EBADFD;
-+                      break;
-+              }
-+
-+              if (signal_pending(current)) {
-+                      err = sock_intr_errno(timeo);
-+                      break;
-+              }
-+      }
-+      set_current_state(TASK_RUNNING);
-+      remove_wait_queue(sk->sleep, &wait);
-+
-+      if (err)
-+              goto done;
-+
-+      newsock->state = SS_CONNECTED;
-+
-+      BT_DBG("new socket %p", ch);
-+
-+done:
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
-+{
-+      struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
-+      struct sock *sk = sock->sk;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      addr->sa_family = AF_BLUETOOTH;
-+      *len = sizeof(struct sockaddr_sco);
-+
-+      if (peer)
-+              bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
-+      else
-+              bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
-+
-+      return 0;
-+}
-+
-+static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (sk->err)
-+              return sock_error(sk);
-+
-+      if (msg->msg_flags & MSG_OOB)
-+              return -EOPNOTSUPP;
-+
-+      lock_sock(sk);
-+
-+      if (sk->state == BT_CONNECTED)
-+              err = sco_send_frame(sk, msg, len);
-+      else
-+              err = -ENOTCONN;
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sk %p", sk);
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      };
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
-+{
-+      struct sock *sk = sock->sk;
-+      struct sco_options opts;
-+      struct sco_conninfo cinfo;
-+      int len, err = 0; 
-+
-+      BT_DBG("sk %p", sk);
-+
-+      if (get_user(len, optlen))
-+              return -EFAULT;
-+
-+      lock_sock(sk);
-+
-+      switch (optname) {
-+      case SCO_OPTIONS:
-+              if (sk->state != BT_CONNECTED) {
-+                      err = -ENOTCONN;
-+                      break;
-+              }
-+              
-+              opts.mtu = sco_pi(sk)->conn->mtu;
-+
-+              BT_DBG("mtu %d", opts.mtu);
-+
-+              len = MIN(len, sizeof(opts));
-+              if (copy_to_user(optval, (char *)&opts, len))
-+                      err = -EFAULT;
-+
-+              break;
-+
-+      case SCO_CONNINFO:
-+              if (sk->state != BT_CONNECTED) {
-+                      err = -ENOTCONN;
-+                      break;
-+              }
-+
-+              cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
-+
-+              len = MIN(len, sizeof(cinfo));
-+              if (copy_to_user(optval, (char *)&cinfo, len))
-+                      err = -EFAULT;
-+
-+              break;
-+
-+      default:
-+              err = -ENOPROTOOPT;
-+              break;
-+      };
-+
-+      release_sock(sk);
-+      return err;
-+}
-+
-+static int sco_sock_release(struct socket *sock)
-+{
-+      struct sock *sk = sock->sk;
-+      int err = 0;
-+
-+      BT_DBG("sock %p, sk %p", sock, sk);
-+
-+      if (!sk)
-+              return 0;
-+
-+      sco_sock_close(sk);
-+      if (sk->linger) {
-+              lock_sock(sk);
-+              err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
-+              release_sock(sk);
-+      }
-+
-+      sock_orphan(sk);
-+      sco_sock_kill(sk);
-+      return err;
-+}
-+
-+static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+      BT_DBG("conn %p", conn);
-+
-+      sco_pi(sk)->conn = conn;
-+      conn->sk = sk;
-+
-+      if (parent)
-+              bluez_accept_enqueue(parent, sk);
-+}
-+
-+static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
-+{
-+      int err = 0;
-+
-+      sco_conn_lock(conn);
-+      if (conn->sk) {
-+              err = -EBUSY;
-+      } else {
-+              __sco_chan_add(conn, sk, parent);
-+      }
-+      sco_conn_unlock(conn);
-+      return err;
-+}
-+
-+static inline struct sock * sco_chan_get(struct sco_conn *conn)
-+{
-+      struct sock *sk = NULL;
-+      sco_conn_lock(conn);
-+      sk = conn->sk;
-+      sco_conn_unlock(conn);
-+      return sk;
-+}
-+
-+/* Delete channel. 
-+ * Must be called on the locked socket. */
-+static void sco_chan_del(struct sock *sk, int err)
-+{
-+      struct sco_conn *conn;
-+
-+      conn = sco_pi(sk)->conn;
-+
-+      BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
-+
-+      if (conn) { 
-+              sco_conn_lock(conn);
-+              conn->sk = NULL;
-+              sco_pi(sk)->conn = NULL;
-+              sco_conn_unlock(conn);
-+              hci_conn_put(conn->hcon);
-+      }
-+
-+      sk->state = BT_CLOSED;
-+      sk->err   = err;
-+      sk->state_change(sk);
-+
-+      sk->zapped = 1;
-+}
-+
-+static void sco_conn_ready(struct sco_conn *conn)
-+{
-+      struct sock *parent, *sk;
-+
-+      BT_DBG("conn %p", conn);
-+
-+      sco_conn_lock(conn);
-+
-+      if ((sk = conn->sk)) {
-+              sco_sock_clear_timer(sk);
-+              bh_lock_sock(sk);
-+              sk->state = BT_CONNECTED;
-+              sk->state_change(sk);
-+              bh_unlock_sock(sk);
-+      } else {
-+              parent = sco_get_sock_listen(conn->src);
-+              if (!parent)
-+                      goto done;
-+
-+              bh_lock_sock(parent);
-+
-+              sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
-+              if (!sk) {
-+                      bh_unlock_sock(parent);
-+                      goto done;
-+              }
-+
-+              sco_sock_init(sk, parent);
-+
-+              bacpy(&bluez_pi(sk)->src, conn->src);
-+              bacpy(&bluez_pi(sk)->dst, conn->dst);
-+
-+              hci_conn_hold(conn->hcon);
-+              __sco_chan_add(conn, sk, parent);
-+
-+              sk->state = BT_CONNECTED;
-+
-+              /* Wake up parent */
-+              parent->data_ready(parent, 1);
-+      
-+              bh_unlock_sock(parent);
-+      }
-+
-+done:
-+      sco_conn_unlock(conn);
-+}
-+
-+/* ----- SCO interface with lower layer (HCI) ----- */
-+int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
-+{
-+      BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
-+
-+      /* Always accept connection */
-+      return HCI_LM_ACCEPT;
-+}
-+
-+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)
-+              return 0;
-+
-+      if (!status) {
-+              struct sco_conn *conn;
-+
-+              conn = sco_conn_add(hcon, status);
-+              if (conn)
-+                      sco_conn_ready(conn);
-+      } else 
-+              sco_conn_del(hcon, bterr(status));
-+      
-+      return 0;
-+}
-+
-+int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
-+{
-+      BT_DBG("hcon %p reason %d", hcon, reason);
-+
-+      if (hcon->type != SCO_LINK)
-+              return 0;
-+
-+      sco_conn_del(hcon, bterr(reason));
-+      return 0;
-+}
-+
-+int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
-+{
-+      struct sco_conn *conn = hcon->sco_data;
-+
-+      if (!conn)
-+              goto drop;
-+
-+      BT_DBG("conn %p len %d", conn, skb->len);
-+
-+      if (skb->len) {
-+              sco_recv_frame(conn, skb);
-+              return 0;
-+      }
-+
-+drop:
-+      kfree_skb(skb); 
-+      return 0;
-+}
-+
-+/* ----- Proc fs support ------ */
-+static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
-+{
-+      struct sco_pinfo *pi;
-+      struct sock *sk;
-+      char *ptr = buf;
-+
-+      write_lock_bh(&list->lock);
-+
-+      for (sk = list->head; sk; sk = sk->next) {
-+              pi = sco_pi(sk);
-+              ptr += sprintf(ptr, "%s %s %d\n",
-+                              batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
-+                              sk->state); 
-+      }
-+
-+      write_unlock_bh(&list->lock);
-+
-+      ptr += sprintf(ptr, "\n");
-+
-+      return ptr - buf;
-+}
-+
-+static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
-+{
-+      char *ptr = buf;
-+      int len;
-+
-+      BT_DBG("count %d, offset %ld", count, offset);
-+
-+      ptr += sco_sock_dump(ptr, &sco_sk_list);
-+      len  = ptr - buf;
-+
-+      if (len <= count + offset)
-+              *eof = 1;
-+
-+      *start = buf + offset;
-+      len -= offset;
-+
-+      if (len > count)
-+              len = count;
-+      if (len < 0)
-+              len = 0;
-+
-+      return len;
-+}
-+
-+static struct proto_ops sco_sock_ops = {
-+      family:         PF_BLUETOOTH,
-+      release:        sco_sock_release,
-+      bind:           sco_sock_bind,
-+      connect:        sco_sock_connect,
-+      listen:         sco_sock_listen,
-+      accept:         sco_sock_accept,
-+      getname:        sco_sock_getname,
-+      sendmsg:        sco_sock_sendmsg,
-+      recvmsg:        bluez_sock_recvmsg,
-+      poll:           bluez_sock_poll,
-+      socketpair:     sock_no_socketpair,
-+      ioctl:          sock_no_ioctl,
-+      shutdown:       sock_no_shutdown,
-+      setsockopt:     sco_sock_setsockopt,
-+      getsockopt:     sco_sock_getsockopt,
-+      mmap:           sock_no_mmap
-+};
-+
-+static struct net_proto_family sco_sock_family_ops = {
-+      family:         PF_BLUETOOTH,
-+      create:         sco_sock_create
-+};
-+
-+static struct hci_proto sco_hci_proto = {
-+      name:           "SCO",
-+      id:             HCI_PROTO_SCO,
-+      connect_ind:    sco_connect_ind,
-+      connect_cfm:    sco_connect_cfm,
-+      disconn_ind:    sco_disconn_ind,
-+      recv_scodata:   sco_recv_scodata,
-+};
-+
-+int __init sco_init(void)
-+{
-+      int err;
-+
-+      if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
-+              BT_ERR("Can't register SCO socket layer");
-+              return err;
-+      }
-+
-+      if ((err = hci_register_proto(&sco_hci_proto))) {
-+              BT_ERR("Can't register SCO protocol");
-+              return err;
-+      }
-+
-+      create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
-+
-+      BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
-+      BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
-+      return 0;
-+}
-+
-+void sco_cleanup(void)
-+{
-+      int err;
-+
-+      remove_proc_entry("bluetooth/sco", NULL);
-+
-+      /* Unregister socket, protocol and notifier */
-+      if ((err = bluez_sock_unregister(BTPROTO_SCO)))
-+              BT_ERR("Can't unregister SCO socket layer %d", err);
-+
-+      if ((err = hci_unregister_proto(&sco_hci_proto)))
-+              BT_ERR("Can't unregister SCO protocol %d", err);
-+}
-+
-+module_init(sco_init);
-+module_exit(sco_cleanup);
-+
-+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-+MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
-+MODULE_LICENSE("GPL");
---- linux/net/bluetooth/syms.c~bluetooth-2.4.18-mh11   2001-09-07 18:28:38.000000000 +0200
-+++ linux/net/bluetooth/syms.c 2004-01-25 23:37:39.000000000 +0100
-@@ -25,7 +25,7 @@
- /*
-  * BlueZ symbols.
-  *
-- * $Id: syms.c,v 1.1 2001/07/12 19:31:24 maxk Exp $
-+ * $Id: syms.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
-  */
- #include <linux/config.h>
-@@ -39,25 +39,28 @@
- #include <linux/socket.h>
- #include <net/bluetooth/bluetooth.h>
--#include <net/bluetooth/bluez.h>
- #include <net/bluetooth/hci_core.h>
- /* HCI Core */
- EXPORT_SYMBOL(hci_register_dev);
- EXPORT_SYMBOL(hci_unregister_dev);
-+EXPORT_SYMBOL(hci_suspend_dev);
-+EXPORT_SYMBOL(hci_resume_dev);
-+
- EXPORT_SYMBOL(hci_register_proto);
- EXPORT_SYMBOL(hci_unregister_proto);
--EXPORT_SYMBOL(hci_register_notifier);
--EXPORT_SYMBOL(hci_unregister_notifier);
-+EXPORT_SYMBOL(hci_get_route);
- EXPORT_SYMBOL(hci_connect);
--EXPORT_SYMBOL(hci_disconnect);
- EXPORT_SYMBOL(hci_dev_get);
-+EXPORT_SYMBOL(hci_conn_auth);
-+EXPORT_SYMBOL(hci_conn_encrypt);
- EXPORT_SYMBOL(hci_recv_frame);
- EXPORT_SYMBOL(hci_send_acl);
- EXPORT_SYMBOL(hci_send_sco);
--EXPORT_SYMBOL(hci_send_raw);
-+EXPORT_SYMBOL(hci_send_cmd);
-+EXPORT_SYMBOL(hci_si_event);
- /* BlueZ lib */
- EXPORT_SYMBOL(bluez_dump);
-@@ -68,5 +71,11 @@
- /* BlueZ sockets */
- EXPORT_SYMBOL(bluez_sock_register);
- EXPORT_SYMBOL(bluez_sock_unregister);
-+EXPORT_SYMBOL(bluez_sock_init);
- EXPORT_SYMBOL(bluez_sock_link);
- EXPORT_SYMBOL(bluez_sock_unlink);
-+EXPORT_SYMBOL(bluez_sock_recvmsg);
-+EXPORT_SYMBOL(bluez_sock_poll);
-+EXPORT_SYMBOL(bluez_accept_enqueue);
-+EXPORT_SYMBOL(bluez_accept_dequeue);
-+EXPORT_SYMBOL(bluez_sock_wait_state);
index b1dc3d7..59cd6e8 100644 (file)
@@ -5,7 +5,7 @@ SECTION = "kernel"
 PV = "2.4.20-rmk2-embedix"
 LICENSE = "GPL"
 KV = "2.4.20"
-PR = "r8"
+PR = "r9"
 
 SRC_URI = "http://developer.ezaurus.com/sl_j/source/c1000/20050228/linux-c1000-20050228-rom1_01.tar.bz2 \
            file://P01-C3000-clockup_050221.patch;pnum=2;patch=1 \
@@ -41,7 +41,7 @@ SRC_URI = "http://developer.ezaurus.com/sl_j/source/c1000/20050228/linux-c1000-2
            file://1764-1.patch;patch=1 \
            file://armdeffix.patch;patch=1 \
            file://add-oz-release-string.patch;patch=1 \
-          file://saner-spitz-keymap.patch;patch=1 \
+           file://saner-spitz-keymap.patch;patch=1 \
            file://defconfig-${MACHINE} "
 
 S = "${WORKDIR}/linux_n1"
@@ -51,6 +51,9 @@ inherit kernel
 # Breaks compilation for now, needs to be fixed
 # SRC_URI += "file://CPAR050218.patch;patch=1"
 
+# autoload modules
+module_autoload_usb-ohci-pxa27x = "usb-ohci-pxa27x"
+
 #
 # Compensate for sucky bootloader on all Sharp Zaurus models
 #
index c4159d2..9cd6eb1 100644 (file)
@@ -7,7 +7,7 @@ KV = "2.4.18"
 RMKV = "7"
 PXAV = "3"
 SHARPV = "20031107"
-PR = "r39"
+PR = "r40"
 FILESDIR = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/openzaurus-pxa-${KV}-rmk${RMKV}-pxa${PXAV}-embedix${SHARPV}"
 
 SRC_URI = "ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-${KV}.tar.bz2 \
@@ -42,8 +42,8 @@ SRC_URI = "ftp://ftp.kernel.org/pub/linux/kernel/v2.4/linux-${KV}.tar.bz2 \
            http://www.openswan.org/download/openswan-2.2.0-kernel-2.4-klips.patch.gz;patch=1 \
            file://1764-1.patch;patch=1 \
            file://module_licence.patch;patch=1 \
-           http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/iw249_we16-6.diff;patch=1 \
-          http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/iw249_we17-13.diff;patch=1 \
+           file://iw249_we16-6.diff;patch=1 \
+           file://iw249_we17-13.diff;patch=1 \
            file://ir240_sys_max_tx-2.diff;patch=1 \
            file://ir241_qos_param-2.diff;patch=1 \
            http://us1.samba.org/samba/ftp/cifs-cvs/cifs-1.20c-2.4.tar.gz \