From fb2d31da84a0cc813f26ac55f1a4df6fdea055e1 Mon Sep 17 00:00:00 2001 From: Michael Lauer Date: Sun, 24 Jul 2005 19:30:31 +0000 Subject: openzaurus-pxa27x: autoload usb host module openzaurus-pxa: remove outdated bluetooth patch, use local WE patches --- .../bluetooth-2.4.18-mh11.patch | 31393 ------------------- ...penzaurus-pxa27x_2.4.20-rmk2-embedix20050228.bb | 7 +- ...zaurus-pxa_2.4.18-rmk7-pxa3-embedix20031107.inc | 6 +- 3 files changed, 8 insertions(+), 31398 deletions(-) delete mode 100644 packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch (limited to 'packages/linux') 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 index ff3582ab7b..0000000000 --- a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch +++ /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 - #include -+#include - - #include - #include -@@ -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 . -+ - 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 . - - 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 . - -- 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 . -+ -+ 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 . -+ -+ 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 -+ * -+ * Sample code on how to use request_firmware() from drivers. -+ * -+ * Note that register_firmware() is currently useless. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#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 -+ -+ 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 -+ * -+ * -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#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 "); -+ -+ 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 "); -+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 -+ * -+ * -+ * 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 -+ * . Portions created by David A. Hinds -+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. -+ * -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+ -+/* ======================== 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 "); -+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]