diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
| commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
| tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/bluetooth | |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/bluetooth')
| -rw-r--r-- | drivers/bluetooth/Kconfig | 168 | ||||
| -rw-r--r-- | drivers/bluetooth/Makefile | 19 | ||||
| -rw-r--r-- | drivers/bluetooth/bcm203x.c | 314 | ||||
| -rw-r--r-- | drivers/bluetooth/bfusb.c | 806 | ||||
| -rw-r--r-- | drivers/bluetooth/bluecard_cs.c | 1114 | ||||
| -rw-r--r-- | drivers/bluetooth/bpa10x.c | 657 | ||||
| -rw-r--r-- | drivers/bluetooth/bt3c_cs.c | 960 | ||||
| -rw-r--r-- | drivers/bluetooth/btuart_cs.c | 880 | ||||
| -rw-r--r-- | drivers/bluetooth/dtl1_cs.c | 832 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_bcsp.c | 749 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_bcsp.h | 70 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_h4.c | 282 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_h4.h | 44 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 593 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_uart.h | 82 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_usb.c | 1075 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_usb.h | 128 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_vhci.c | 364 | ||||
| -rw-r--r-- | drivers/bluetooth/hci_vhci.h | 50 |
19 files changed, 9187 insertions, 0 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig new file mode 100644 index 000000000000..543f93e0f23f --- /dev/null +++ b/drivers/bluetooth/Kconfig | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | |||
| 2 | menu "Bluetooth device drivers" | ||
| 3 | depends on BT | ||
| 4 | |||
| 5 | config BT_HCIUSB | ||
| 6 | tristate "HCI USB driver" | ||
| 7 | depends on USB | ||
| 8 | help | ||
| 9 | Bluetooth HCI USB driver. | ||
| 10 | This driver is required if you want to use Bluetooth devices with | ||
| 11 | USB interface. | ||
| 12 | |||
| 13 | Say Y here to compile support for Bluetooth USB devices into the | ||
| 14 | kernel or say M to compile it as module (hci_usb). | ||
| 15 | |||
| 16 | config BT_HCIUSB_SCO | ||
| 17 | bool "SCO (voice) support" | ||
| 18 | depends on BT_HCIUSB | ||
| 19 | help | ||
| 20 | This option enables the SCO support in the HCI USB driver. You need this | ||
| 21 | to transmit voice data with your Bluetooth USB device. | ||
| 22 | |||
| 23 | Say Y here to compile support for SCO over HCI USB. | ||
| 24 | |||
| 25 | config BT_HCIUART | ||
| 26 | tristate "HCI UART driver" | ||
| 27 | help | ||
| 28 | Bluetooth HCI UART driver. | ||
| 29 | This driver is required if you want to use Bluetooth devices with | ||
| 30 | serial port interface. You will also need this driver if you have | ||
| 31 | UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card | ||
| 32 | adapter and BrainBoxes Bluetooth PC Card. | ||
| 33 | |||
| 34 | Say Y here to compile support for Bluetooth UART devices into the | ||
| 35 | kernel or say M to compile it as module (hci_uart). | ||
| 36 | |||
| 37 | config BT_HCIUART_H4 | ||
| 38 | bool "UART (H4) protocol support" | ||
| 39 | depends on BT_HCIUART | ||
| 40 | help | ||
| 41 | UART (H4) is serial protocol for communication between Bluetooth | ||
| 42 | device and host. This protocol is required for most Bluetooth devices | ||
| 43 | with UART interface, including PCMCIA and CF cards. | ||
| 44 | |||
| 45 | Say Y here to compile support for HCI UART (H4) protocol. | ||
| 46 | |||
| 47 | config BT_HCIUART_BCSP | ||
| 48 | bool "BCSP protocol support" | ||
| 49 | depends on BT_HCIUART | ||
| 50 | help | ||
| 51 | BCSP (BlueCore Serial Protocol) is serial protocol for communication | ||
| 52 | between Bluetooth device and host. This protocol is required for non | ||
| 53 | USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and | ||
| 54 | CF cards. | ||
| 55 | |||
| 56 | Say Y here to compile support for HCI BCSP protocol. | ||
| 57 | |||
| 58 | config BT_HCIUART_BCSP_TXCRC | ||
| 59 | bool "Transmit CRC with every BCSP packet" | ||
| 60 | depends on BT_HCIUART_BCSP | ||
| 61 | help | ||
| 62 | If you say Y here, a 16-bit CRC checksum will be transmitted along with | ||
| 63 | every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. | ||
| 64 | This increases reliability, but slightly reduces efficiency. | ||
| 65 | |||
| 66 | config BT_HCIBCM203X | ||
| 67 | tristate "HCI BCM203x USB driver" | ||
| 68 | depends on USB | ||
| 69 | select FW_LOADER | ||
| 70 | help | ||
| 71 | Bluetooth HCI BCM203x USB driver. | ||
| 72 | This driver provides the firmware loading mechanism for the Broadcom | ||
| 73 | Blutonium based devices. | ||
| 74 | |||
| 75 | Say Y here to compile support for HCI BCM203x devices into the | ||
| 76 | kernel or say M to compile it as module (bcm203x). | ||
| 77 | |||
| 78 | config BT_HCIBPA10X | ||
| 79 | tristate "HCI BPA10x USB driver" | ||
| 80 | depends on USB | ||
| 81 | help | ||
| 82 | Bluetooth HCI BPA10x USB driver. | ||
| 83 | This driver provides support for the Digianswer BPA 100/105 Bluetooth | ||
| 84 | sniffer devices. | ||
| 85 | |||
| 86 | Say Y here to compile support for HCI BPA10x devices into the | ||
| 87 | kernel or say M to compile it as module (bpa10x). | ||
| 88 | |||
| 89 | config BT_HCIBFUSB | ||
| 90 | tristate "HCI BlueFRITZ! USB driver" | ||
| 91 | depends on USB | ||
| 92 | select FW_LOADER | ||
| 93 | help | ||
| 94 | Bluetooth HCI BlueFRITZ! USB driver. | ||
| 95 | This driver provides support for Bluetooth USB devices with AVM | ||
| 96 | interface: | ||
| 97 | AVM BlueFRITZ! USB | ||
| 98 | |||
| 99 | Say Y here to compile support for HCI BFUSB devices into the | ||
| 100 | kernel or say M to compile it as module (bfusb). | ||
| 101 | |||
| 102 | config BT_HCIDTL1 | ||
| 103 | tristate "HCI DTL1 (PC Card) driver" | ||
| 104 | depends on PCMCIA | ||
| 105 | help | ||
| 106 | Bluetooth HCI DTL1 (PC Card) driver. | ||
| 107 | This driver provides support for Bluetooth PCMCIA devices with | ||
| 108 | Nokia DTL1 interface: | ||
| 109 | Nokia Bluetooth Card | ||
| 110 | Socket Bluetooth CF Card | ||
| 111 | |||
| 112 | Say Y here to compile support for HCI DTL1 devices into the | ||
| 113 | kernel or say M to compile it as module (dtl1_cs). | ||
| 114 | |||
| 115 | config BT_HCIBT3C | ||
| 116 | tristate "HCI BT3C (PC Card) driver" | ||
| 117 | depends on PCMCIA | ||
| 118 | select FW_LOADER | ||
| 119 | help | ||
| 120 | Bluetooth HCI BT3C (PC Card) driver. | ||
| 121 | This driver provides support for Bluetooth PCMCIA devices with | ||
| 122 | 3Com BT3C interface: | ||
| 123 | 3Com Bluetooth Card (3CRWB6096) | ||
| 124 | HP Bluetooth Card | ||
| 125 | |||
| 126 | Say Y here to compile support for HCI BT3C devices into the | ||
| 127 | kernel or say M to compile it as module (bt3c_cs). | ||
| 128 | |||
| 129 | config BT_HCIBLUECARD | ||
| 130 | tristate "HCI BlueCard (PC Card) driver" | ||
| 131 | depends on PCMCIA | ||
| 132 | help | ||
| 133 | Bluetooth HCI BlueCard (PC Card) driver. | ||
| 134 | This driver provides support for Bluetooth PCMCIA devices with | ||
| 135 | Anycom BlueCard interface: | ||
| 136 | Anycom Bluetooth PC Card | ||
| 137 | Anycom Bluetooth CF Card | ||
| 138 | |||
| 139 | Say Y here to compile support for HCI BlueCard devices into the | ||
| 140 | kernel or say M to compile it as module (bluecard_cs). | ||
| 141 | |||
| 142 | config BT_HCIBTUART | ||
| 143 | tristate "HCI UART (PC Card) device driver" | ||
| 144 | depends on PCMCIA | ||
| 145 | help | ||
| 146 | Bluetooth HCI UART (PC Card) driver. | ||
| 147 | This driver provides support for Bluetooth PCMCIA devices with | ||
| 148 | an UART interface: | ||
| 149 | Xircom CreditCard Bluetooth Adapter | ||
| 150 | Xircom RealPort2 Bluetooth Adapter | ||
| 151 | Sphinx PICO Card | ||
| 152 | H-Soft blue+Card | ||
| 153 | Cyber-blue Compact Flash Card | ||
| 154 | |||
| 155 | Say Y here to compile support for HCI UART devices into the | ||
| 156 | kernel or say M to compile it as module (btuart_cs). | ||
| 157 | |||
| 158 | config BT_HCIVHCI | ||
| 159 | tristate "HCI VHCI (Virtual HCI device) driver" | ||
| 160 | help | ||
| 161 | Bluetooth Virtual HCI device driver. | ||
| 162 | This driver is required if you want to use HCI Emulation software. | ||
| 163 | |||
| 164 | Say Y here to compile support for virtual HCI devices into the | ||
| 165 | kernel or say M to compile it as module (hci_vhci). | ||
| 166 | |||
| 167 | endmenu | ||
| 168 | |||
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile new file mode 100644 index 000000000000..08c10e178e02 --- /dev/null +++ b/drivers/bluetooth/Makefile | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Linux Bluetooth HCI device drivers. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_BT_HCIUSB) += hci_usb.o | ||
| 6 | obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o | ||
| 7 | obj-$(CONFIG_BT_HCIUART) += hci_uart.o | ||
| 8 | obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o | ||
| 9 | obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o | ||
| 10 | obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o | ||
| 11 | obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o | ||
| 12 | obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o | ||
| 13 | obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o | ||
| 14 | obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o | ||
| 15 | |||
| 16 | hci_uart-y := hci_ldisc.o | ||
| 17 | hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o | ||
| 18 | hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o | ||
| 19 | hci_uart-objs := $(hci_uart-y) | ||
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c new file mode 100644 index 000000000000..5fd3e4cb7525 --- /dev/null +++ b/drivers/bluetooth/bcm203x.c | |||
| @@ -0,0 +1,314 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Broadcom Blutonium firmware driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/config.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | |||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/types.h> | ||
| 32 | #include <linux/errno.h> | ||
| 33 | #include <linux/timer.h> | ||
| 34 | |||
| 35 | #include <linux/device.h> | ||
| 36 | #include <linux/firmware.h> | ||
| 37 | |||
| 38 | #include <linux/usb.h> | ||
| 39 | |||
| 40 | #include <net/bluetooth/bluetooth.h> | ||
| 41 | |||
| 42 | #ifndef CONFIG_BT_HCIBCM203X_DEBUG | ||
| 43 | #undef BT_DBG | ||
| 44 | #define BT_DBG(D...) | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #define VERSION "1.0" | ||
| 48 | |||
| 49 | static int ignore = 0; | ||
| 50 | |||
| 51 | static struct usb_device_id bcm203x_table[] = { | ||
| 52 | /* Broadcom Blutonium (BCM2033) */ | ||
| 53 | { USB_DEVICE(0x0a5c, 0x2033) }, | ||
| 54 | |||
| 55 | { } /* Terminating entry */ | ||
| 56 | }; | ||
| 57 | |||
| 58 | MODULE_DEVICE_TABLE(usb, bcm203x_table); | ||
| 59 | |||
| 60 | #define BCM203X_ERROR 0 | ||
| 61 | #define BCM203X_RESET 1 | ||
| 62 | #define BCM203X_LOAD_MINIDRV 2 | ||
| 63 | #define BCM203X_SELECT_MEMORY 3 | ||
| 64 | #define BCM203X_CHECK_MEMORY 4 | ||
| 65 | #define BCM203X_LOAD_FIRMWARE 5 | ||
| 66 | #define BCM203X_CHECK_FIRMWARE 6 | ||
| 67 | |||
| 68 | #define BCM203X_IN_EP 0x81 | ||
| 69 | #define BCM203X_OUT_EP 0x02 | ||
| 70 | |||
| 71 | struct bcm203x_data { | ||
| 72 | struct usb_device *udev; | ||
| 73 | |||
| 74 | unsigned long state; | ||
| 75 | |||
| 76 | struct timer_list timer; | ||
| 77 | |||
| 78 | struct urb *urb; | ||
| 79 | unsigned char *buffer; | ||
| 80 | |||
| 81 | unsigned char *fw_data; | ||
| 82 | unsigned int fw_size; | ||
| 83 | unsigned int fw_sent; | ||
| 84 | }; | ||
| 85 | |||
| 86 | static void bcm203x_complete(struct urb *urb, struct pt_regs *regs) | ||
| 87 | { | ||
| 88 | struct bcm203x_data *data = urb->context; | ||
| 89 | struct usb_device *udev = urb->dev; | ||
| 90 | int len; | ||
| 91 | |||
| 92 | BT_DBG("udev %p urb %p", udev, urb); | ||
| 93 | |||
| 94 | if (urb->status) { | ||
| 95 | BT_ERR("URB failed with status %d", urb->status); | ||
| 96 | data->state = BCM203X_ERROR; | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | switch (data->state) { | ||
| 101 | case BCM203X_LOAD_MINIDRV: | ||
| 102 | memcpy(data->buffer, "#", 1); | ||
| 103 | |||
| 104 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), | ||
| 105 | data->buffer, 1, bcm203x_complete, data); | ||
| 106 | |||
| 107 | data->state = BCM203X_SELECT_MEMORY; | ||
| 108 | |||
| 109 | mod_timer(&data->timer, jiffies + (HZ / 10)); | ||
| 110 | break; | ||
| 111 | |||
| 112 | case BCM203X_SELECT_MEMORY: | ||
| 113 | usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), | ||
| 114 | data->buffer, 32, bcm203x_complete, data, 1); | ||
| 115 | |||
| 116 | data->state = BCM203X_CHECK_MEMORY; | ||
| 117 | |||
| 118 | if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) | ||
| 119 | BT_ERR("Can't submit URB"); | ||
| 120 | break; | ||
| 121 | |||
| 122 | case BCM203X_CHECK_MEMORY: | ||
| 123 | if (data->buffer[0] != '#') { | ||
| 124 | BT_ERR("Memory select failed"); | ||
| 125 | data->state = BCM203X_ERROR; | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | |||
| 129 | data->state = BCM203X_LOAD_FIRMWARE; | ||
| 130 | |||
| 131 | case BCM203X_LOAD_FIRMWARE: | ||
| 132 | if (data->fw_sent == data->fw_size) { | ||
| 133 | usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), | ||
| 134 | data->buffer, 32, bcm203x_complete, data, 1); | ||
| 135 | |||
| 136 | data->state = BCM203X_CHECK_FIRMWARE; | ||
| 137 | } else { | ||
| 138 | len = min_t(uint, data->fw_size - data->fw_sent, 4096); | ||
| 139 | |||
| 140 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), | ||
| 141 | data->fw_data + data->fw_sent, len, bcm203x_complete, data); | ||
| 142 | |||
| 143 | data->fw_sent += len; | ||
| 144 | } | ||
| 145 | |||
| 146 | if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) | ||
| 147 | BT_ERR("Can't submit URB"); | ||
| 148 | break; | ||
| 149 | |||
| 150 | case BCM203X_CHECK_FIRMWARE: | ||
| 151 | if (data->buffer[0] != '.') { | ||
| 152 | BT_ERR("Firmware loading failed"); | ||
| 153 | data->state = BCM203X_ERROR; | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | |||
| 157 | data->state = BCM203X_RESET; | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | static void bcm203x_timer(unsigned long user_data) | ||
| 163 | { | ||
| 164 | struct bcm203x_data *data = (struct bcm203x_data *) user_data; | ||
| 165 | |||
| 166 | if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) | ||
| 167 | BT_ERR("Can't submit URB"); | ||
| 168 | } | ||
| 169 | |||
| 170 | static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 171 | { | ||
| 172 | const struct firmware *firmware; | ||
| 173 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 174 | struct bcm203x_data *data; | ||
| 175 | int size; | ||
| 176 | |||
| 177 | BT_DBG("intf %p id %p", intf, id); | ||
| 178 | |||
| 179 | if (ignore || (intf->cur_altsetting->desc.bInterfaceNumber != 0)) | ||
| 180 | return -ENODEV; | ||
| 181 | |||
| 182 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
| 183 | if (!data) { | ||
| 184 | BT_ERR("Can't allocate memory for data structure"); | ||
| 185 | return -ENOMEM; | ||
| 186 | } | ||
| 187 | |||
| 188 | memset(data, 0, sizeof(*data)); | ||
| 189 | |||
| 190 | data->udev = udev; | ||
| 191 | data->state = BCM203X_LOAD_MINIDRV; | ||
| 192 | |||
| 193 | data->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 194 | if (!data->urb) { | ||
| 195 | BT_ERR("Can't allocate URB"); | ||
| 196 | kfree(data); | ||
| 197 | return -ENOMEM; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { | ||
| 201 | BT_ERR("Mini driver request failed"); | ||
| 202 | usb_free_urb(data->urb); | ||
| 203 | kfree(data); | ||
| 204 | return -EIO; | ||
| 205 | } | ||
| 206 | |||
| 207 | BT_DBG("minidrv data %p size %d", firmware->data, firmware->size); | ||
| 208 | |||
| 209 | size = max_t(uint, firmware->size, 4096); | ||
| 210 | |||
| 211 | data->buffer = kmalloc(size, GFP_KERNEL); | ||
| 212 | if (!data->buffer) { | ||
| 213 | BT_ERR("Can't allocate memory for mini driver"); | ||
| 214 | release_firmware(firmware); | ||
| 215 | usb_free_urb(data->urb); | ||
| 216 | kfree(data); | ||
| 217 | return -ENOMEM; | ||
| 218 | } | ||
| 219 | |||
| 220 | memcpy(data->buffer, firmware->data, firmware->size); | ||
| 221 | |||
| 222 | usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), | ||
| 223 | data->buffer, firmware->size, bcm203x_complete, data); | ||
| 224 | |||
| 225 | release_firmware(firmware); | ||
| 226 | |||
| 227 | if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { | ||
| 228 | BT_ERR("Firmware request failed"); | ||
| 229 | usb_free_urb(data->urb); | ||
| 230 | kfree(data->buffer); | ||
| 231 | kfree(data); | ||
| 232 | return -EIO; | ||
| 233 | } | ||
| 234 | |||
| 235 | BT_DBG("firmware data %p size %d", firmware->data, firmware->size); | ||
| 236 | |||
| 237 | data->fw_data = kmalloc(firmware->size, GFP_KERNEL); | ||
| 238 | if (!data->fw_data) { | ||
| 239 | BT_ERR("Can't allocate memory for firmware image"); | ||
| 240 | usb_free_urb(data->urb); | ||
| 241 | kfree(data->buffer); | ||
| 242 | kfree(data); | ||
| 243 | return -ENOMEM; | ||
| 244 | } | ||
| 245 | |||
| 246 | memcpy(data->fw_data, firmware->data, firmware->size); | ||
| 247 | data->fw_size = firmware->size; | ||
| 248 | data->fw_sent = 0; | ||
| 249 | |||
| 250 | release_firmware(firmware); | ||
| 251 | |||
| 252 | init_timer(&data->timer); | ||
| 253 | data->timer.function = bcm203x_timer; | ||
| 254 | data->timer.data = (unsigned long) data; | ||
| 255 | |||
| 256 | usb_set_intfdata(intf, data); | ||
| 257 | |||
| 258 | mod_timer(&data->timer, jiffies + HZ); | ||
| 259 | |||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | |||
| 263 | static void bcm203x_disconnect(struct usb_interface *intf) | ||
| 264 | { | ||
| 265 | struct bcm203x_data *data = usb_get_intfdata(intf); | ||
| 266 | |||
| 267 | BT_DBG("intf %p", intf); | ||
| 268 | |||
| 269 | usb_kill_urb(data->urb); | ||
| 270 | |||
| 271 | usb_set_intfdata(intf, NULL); | ||
| 272 | |||
| 273 | usb_free_urb(data->urb); | ||
| 274 | kfree(data->fw_data); | ||
| 275 | kfree(data->buffer); | ||
| 276 | kfree(data); | ||
| 277 | } | ||
| 278 | |||
| 279 | static struct usb_driver bcm203x_driver = { | ||
| 280 | .owner = THIS_MODULE, | ||
| 281 | .name = "bcm203x", | ||
| 282 | .probe = bcm203x_probe, | ||
| 283 | .disconnect = bcm203x_disconnect, | ||
| 284 | .id_table = bcm203x_table, | ||
| 285 | }; | ||
| 286 | |||
| 287 | static int __init bcm203x_init(void) | ||
| 288 | { | ||
| 289 | int err; | ||
| 290 | |||
| 291 | BT_INFO("Broadcom Blutonium firmware driver ver %s", VERSION); | ||
| 292 | |||
| 293 | err = usb_register(&bcm203x_driver); | ||
| 294 | if (err < 0) | ||
| 295 | BT_ERR("Failed to register USB driver"); | ||
| 296 | |||
| 297 | return err; | ||
| 298 | } | ||
| 299 | |||
| 300 | static void __exit bcm203x_exit(void) | ||
| 301 | { | ||
| 302 | usb_deregister(&bcm203x_driver); | ||
| 303 | } | ||
| 304 | |||
| 305 | module_init(bcm203x_init); | ||
| 306 | module_exit(bcm203x_exit); | ||
| 307 | |||
| 308 | module_param(ignore, bool, 0644); | ||
| 309 | MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); | ||
| 310 | |||
| 311 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 312 | MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); | ||
| 313 | MODULE_VERSION(VERSION); | ||
| 314 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c new file mode 100644 index 000000000000..c42d7e6ac1c5 --- /dev/null +++ b/drivers/bluetooth/bfusb.c | |||
| @@ -0,0 +1,806 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * AVM BlueFRITZ! USB driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/errno.h> | ||
| 33 | #include <linux/skbuff.h> | ||
| 34 | |||
| 35 | #include <linux/device.h> | ||
| 36 | #include <linux/firmware.h> | ||
| 37 | |||
| 38 | #include <linux/usb.h> | ||
| 39 | |||
| 40 | #include <net/bluetooth/bluetooth.h> | ||
| 41 | #include <net/bluetooth/hci_core.h> | ||
| 42 | |||
| 43 | #ifndef CONFIG_BT_HCIBFUSB_DEBUG | ||
| 44 | #undef BT_DBG | ||
| 45 | #define BT_DBG(D...) | ||
| 46 | #endif | ||
| 47 | |||
| 48 | #define VERSION "1.1" | ||
| 49 | |||
| 50 | static int ignore = 0; | ||
| 51 | |||
| 52 | static struct usb_driver bfusb_driver; | ||
| 53 | |||
| 54 | static struct usb_device_id bfusb_table[] = { | ||
| 55 | /* AVM BlueFRITZ! USB */ | ||
| 56 | { USB_DEVICE(0x057c, 0x2200) }, | ||
| 57 | |||
| 58 | { } /* Terminating entry */ | ||
| 59 | }; | ||
| 60 | |||
| 61 | MODULE_DEVICE_TABLE(usb, bfusb_table); | ||
| 62 | |||
| 63 | |||
| 64 | #define BFUSB_MAX_BLOCK_SIZE 256 | ||
| 65 | |||
| 66 | #define BFUSB_BLOCK_TIMEOUT 3000 | ||
| 67 | |||
| 68 | #define BFUSB_TX_PROCESS 1 | ||
| 69 | #define BFUSB_TX_WAKEUP 2 | ||
| 70 | |||
| 71 | #define BFUSB_MAX_BULK_TX 2 | ||
| 72 | #define BFUSB_MAX_BULK_RX 2 | ||
| 73 | |||
| 74 | struct bfusb { | ||
| 75 | struct hci_dev *hdev; | ||
| 76 | |||
| 77 | unsigned long state; | ||
| 78 | |||
| 79 | struct usb_device *udev; | ||
| 80 | |||
| 81 | unsigned int bulk_in_ep; | ||
| 82 | unsigned int bulk_out_ep; | ||
| 83 | unsigned int bulk_pkt_size; | ||
| 84 | |||
| 85 | rwlock_t lock; | ||
| 86 | |||
| 87 | struct sk_buff_head transmit_q; | ||
| 88 | |||
| 89 | struct sk_buff *reassembly; | ||
| 90 | |||
| 91 | atomic_t pending_tx; | ||
| 92 | struct sk_buff_head pending_q; | ||
| 93 | struct sk_buff_head completed_q; | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct bfusb_scb { | ||
| 97 | struct urb *urb; | ||
| 98 | }; | ||
| 99 | |||
| 100 | static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs); | ||
| 101 | static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs); | ||
| 102 | |||
| 103 | static struct urb *bfusb_get_completed(struct bfusb *bfusb) | ||
| 104 | { | ||
| 105 | struct sk_buff *skb; | ||
| 106 | struct urb *urb = NULL; | ||
| 107 | |||
| 108 | BT_DBG("bfusb %p", bfusb); | ||
| 109 | |||
| 110 | skb = skb_dequeue(&bfusb->completed_q); | ||
| 111 | if (skb) { | ||
| 112 | urb = ((struct bfusb_scb *) skb->cb)->urb; | ||
| 113 | kfree_skb(skb); | ||
| 114 | } | ||
| 115 | |||
| 116 | return urb; | ||
| 117 | } | ||
| 118 | |||
| 119 | static void bfusb_unlink_urbs(struct bfusb *bfusb) | ||
| 120 | { | ||
| 121 | struct sk_buff *skb; | ||
| 122 | struct urb *urb; | ||
| 123 | |||
| 124 | BT_DBG("bfusb %p", bfusb); | ||
| 125 | |||
| 126 | while ((skb = skb_dequeue(&bfusb->pending_q))) { | ||
| 127 | urb = ((struct bfusb_scb *) skb->cb)->urb; | ||
| 128 | usb_kill_urb(urb); | ||
| 129 | skb_queue_tail(&bfusb->completed_q, skb); | ||
| 130 | } | ||
| 131 | |||
| 132 | while ((urb = bfusb_get_completed(bfusb))) | ||
| 133 | usb_free_urb(urb); | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb) | ||
| 138 | { | ||
| 139 | struct bfusb_scb *scb = (void *) skb->cb; | ||
| 140 | struct urb *urb = bfusb_get_completed(bfusb); | ||
| 141 | int err, pipe; | ||
| 142 | |||
| 143 | BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len); | ||
| 144 | |||
| 145 | if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) | ||
| 146 | return -ENOMEM; | ||
| 147 | |||
| 148 | pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); | ||
| 149 | |||
| 150 | usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len, | ||
| 151 | bfusb_tx_complete, skb); | ||
| 152 | |||
| 153 | scb->urb = urb; | ||
| 154 | |||
| 155 | skb_queue_tail(&bfusb->pending_q, skb); | ||
| 156 | |||
| 157 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 158 | if (err) { | ||
| 159 | BT_ERR("%s bulk tx submit failed urb %p err %d", | ||
| 160 | bfusb->hdev->name, urb, err); | ||
| 161 | skb_unlink(skb); | ||
| 162 | usb_free_urb(urb); | ||
| 163 | } else | ||
| 164 | atomic_inc(&bfusb->pending_tx); | ||
| 165 | |||
| 166 | return err; | ||
| 167 | } | ||
| 168 | |||
| 169 | static void bfusb_tx_wakeup(struct bfusb *bfusb) | ||
| 170 | { | ||
| 171 | struct sk_buff *skb; | ||
| 172 | |||
| 173 | BT_DBG("bfusb %p", bfusb); | ||
| 174 | |||
| 175 | if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) { | ||
| 176 | set_bit(BFUSB_TX_WAKEUP, &bfusb->state); | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | |||
| 180 | do { | ||
| 181 | clear_bit(BFUSB_TX_WAKEUP, &bfusb->state); | ||
| 182 | |||
| 183 | while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) && | ||
| 184 | (skb = skb_dequeue(&bfusb->transmit_q))) { | ||
| 185 | if (bfusb_send_bulk(bfusb, skb) < 0) { | ||
| 186 | skb_queue_head(&bfusb->transmit_q, skb); | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state)); | ||
| 192 | |||
| 193 | clear_bit(BFUSB_TX_PROCESS, &bfusb->state); | ||
| 194 | } | ||
| 195 | |||
| 196 | static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs) | ||
| 197 | { | ||
| 198 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
| 199 | struct bfusb *bfusb = (struct bfusb *) skb->dev; | ||
| 200 | |||
| 201 | BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); | ||
| 202 | |||
| 203 | atomic_dec(&bfusb->pending_tx); | ||
| 204 | |||
| 205 | if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags)) | ||
| 206 | return; | ||
| 207 | |||
| 208 | if (!urb->status) | ||
| 209 | bfusb->hdev->stat.byte_tx += skb->len; | ||
| 210 | else | ||
| 211 | bfusb->hdev->stat.err_tx++; | ||
| 212 | |||
| 213 | read_lock(&bfusb->lock); | ||
| 214 | |||
| 215 | skb_unlink(skb); | ||
| 216 | skb_queue_tail(&bfusb->completed_q, skb); | ||
| 217 | |||
| 218 | bfusb_tx_wakeup(bfusb); | ||
| 219 | |||
| 220 | read_unlock(&bfusb->lock); | ||
| 221 | } | ||
| 222 | |||
| 223 | |||
| 224 | static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb) | ||
| 225 | { | ||
| 226 | struct bfusb_scb *scb; | ||
| 227 | struct sk_buff *skb; | ||
| 228 | int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; | ||
| 229 | |||
| 230 | BT_DBG("bfusb %p urb %p", bfusb, urb); | ||
| 231 | |||
| 232 | if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) | ||
| 233 | return -ENOMEM; | ||
| 234 | |||
| 235 | if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) { | ||
| 236 | usb_free_urb(urb); | ||
| 237 | return -ENOMEM; | ||
| 238 | } | ||
| 239 | |||
| 240 | skb->dev = (void *) bfusb; | ||
| 241 | |||
| 242 | scb = (struct bfusb_scb *) skb->cb; | ||
| 243 | scb->urb = urb; | ||
| 244 | |||
| 245 | pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep); | ||
| 246 | |||
| 247 | usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size, | ||
| 248 | bfusb_rx_complete, skb); | ||
| 249 | |||
| 250 | skb_queue_tail(&bfusb->pending_q, skb); | ||
| 251 | |||
| 252 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 253 | if (err) { | ||
| 254 | BT_ERR("%s bulk rx submit failed urb %p err %d", | ||
| 255 | bfusb->hdev->name, urb, err); | ||
| 256 | skb_unlink(skb); | ||
| 257 | kfree_skb(skb); | ||
| 258 | usb_free_urb(urb); | ||
| 259 | } | ||
| 260 | |||
| 261 | return err; | ||
| 262 | } | ||
| 263 | |||
| 264 | static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len) | ||
| 265 | { | ||
| 266 | BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len); | ||
| 267 | |||
| 268 | if (hdr & 0x10) { | ||
| 269 | BT_ERR("%s error in block", bfusb->hdev->name); | ||
| 270 | if (bfusb->reassembly) | ||
| 271 | kfree_skb(bfusb->reassembly); | ||
| 272 | bfusb->reassembly = NULL; | ||
| 273 | return -EIO; | ||
| 274 | } | ||
| 275 | |||
| 276 | if (hdr & 0x04) { | ||
| 277 | struct sk_buff *skb; | ||
| 278 | unsigned char pkt_type; | ||
| 279 | int pkt_len = 0; | ||
| 280 | |||
| 281 | if (bfusb->reassembly) { | ||
| 282 | BT_ERR("%s unexpected start block", bfusb->hdev->name); | ||
| 283 | kfree_skb(bfusb->reassembly); | ||
| 284 | bfusb->reassembly = NULL; | ||
| 285 | } | ||
| 286 | |||
| 287 | if (len < 1) { | ||
| 288 | BT_ERR("%s no packet type found", bfusb->hdev->name); | ||
| 289 | return -EPROTO; | ||
| 290 | } | ||
| 291 | |||
| 292 | pkt_type = *data++; len--; | ||
| 293 | |||
| 294 | switch (pkt_type) { | ||
| 295 | case HCI_EVENT_PKT: | ||
| 296 | if (len >= HCI_EVENT_HDR_SIZE) { | ||
| 297 | struct hci_event_hdr *hdr = (struct hci_event_hdr *) data; | ||
| 298 | pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; | ||
| 299 | } else { | ||
| 300 | BT_ERR("%s event block is too short", bfusb->hdev->name); | ||
| 301 | return -EILSEQ; | ||
| 302 | } | ||
| 303 | break; | ||
| 304 | |||
| 305 | case HCI_ACLDATA_PKT: | ||
| 306 | if (len >= HCI_ACL_HDR_SIZE) { | ||
| 307 | struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data; | ||
| 308 | pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); | ||
| 309 | } else { | ||
| 310 | BT_ERR("%s data block is too short", bfusb->hdev->name); | ||
| 311 | return -EILSEQ; | ||
| 312 | } | ||
| 313 | break; | ||
| 314 | |||
| 315 | case HCI_SCODATA_PKT: | ||
| 316 | if (len >= HCI_SCO_HDR_SIZE) { | ||
| 317 | struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data; | ||
| 318 | pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; | ||
| 319 | } else { | ||
| 320 | BT_ERR("%s audio block is too short", bfusb->hdev->name); | ||
| 321 | return -EILSEQ; | ||
| 322 | } | ||
| 323 | break; | ||
| 324 | } | ||
| 325 | |||
| 326 | skb = bt_skb_alloc(pkt_len, GFP_ATOMIC); | ||
| 327 | if (!skb) { | ||
| 328 | BT_ERR("%s no memory for the packet", bfusb->hdev->name); | ||
| 329 | return -ENOMEM; | ||
| 330 | } | ||
| 331 | |||
| 332 | skb->dev = (void *) bfusb->hdev; | ||
| 333 | skb->pkt_type = pkt_type; | ||
| 334 | |||
| 335 | bfusb->reassembly = skb; | ||
| 336 | } else { | ||
| 337 | if (!bfusb->reassembly) { | ||
| 338 | BT_ERR("%s unexpected continuation block", bfusb->hdev->name); | ||
| 339 | return -EIO; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | if (len > 0) | ||
| 344 | memcpy(skb_put(bfusb->reassembly, len), data, len); | ||
| 345 | |||
| 346 | if (hdr & 0x08) { | ||
| 347 | hci_recv_frame(bfusb->reassembly); | ||
| 348 | bfusb->reassembly = NULL; | ||
| 349 | } | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs) | ||
| 355 | { | ||
| 356 | struct sk_buff *skb = (struct sk_buff *) urb->context; | ||
| 357 | struct bfusb *bfusb = (struct bfusb *) skb->dev; | ||
| 358 | unsigned char *buf = urb->transfer_buffer; | ||
| 359 | int count = urb->actual_length; | ||
| 360 | int err, hdr, len; | ||
| 361 | |||
| 362 | BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); | ||
| 363 | |||
| 364 | read_lock(&bfusb->lock); | ||
| 365 | |||
| 366 | if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags)) | ||
| 367 | goto unlock; | ||
| 368 | |||
| 369 | if (urb->status || !count) | ||
| 370 | goto resubmit; | ||
| 371 | |||
| 372 | bfusb->hdev->stat.byte_rx += count; | ||
| 373 | |||
| 374 | skb_put(skb, count); | ||
| 375 | |||
| 376 | while (count) { | ||
| 377 | hdr = buf[0] | (buf[1] << 8); | ||
| 378 | |||
| 379 | if (hdr & 0x4000) { | ||
| 380 | len = 0; | ||
| 381 | count -= 2; | ||
| 382 | buf += 2; | ||
| 383 | } else { | ||
| 384 | len = (buf[2] == 0) ? 256 : buf[2]; | ||
| 385 | count -= 3; | ||
| 386 | buf += 3; | ||
| 387 | } | ||
| 388 | |||
| 389 | if (count < len) { | ||
| 390 | BT_ERR("%s block extends over URB buffer ranges", | ||
| 391 | bfusb->hdev->name); | ||
| 392 | } | ||
| 393 | |||
| 394 | if ((hdr & 0xe1) == 0xc1) | ||
| 395 | bfusb_recv_block(bfusb, hdr, buf, len); | ||
| 396 | |||
| 397 | count -= len; | ||
| 398 | buf += len; | ||
| 399 | } | ||
| 400 | |||
| 401 | skb_unlink(skb); | ||
| 402 | kfree_skb(skb); | ||
| 403 | |||
| 404 | bfusb_rx_submit(bfusb, urb); | ||
| 405 | |||
| 406 | read_unlock(&bfusb->lock); | ||
| 407 | |||
| 408 | return; | ||
| 409 | |||
| 410 | resubmit: | ||
| 411 | urb->dev = bfusb->udev; | ||
| 412 | |||
| 413 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 414 | if (err) { | ||
| 415 | BT_ERR("%s bulk resubmit failed urb %p err %d", | ||
| 416 | bfusb->hdev->name, urb, err); | ||
| 417 | } | ||
| 418 | |||
| 419 | unlock: | ||
| 420 | read_unlock(&bfusb->lock); | ||
| 421 | } | ||
| 422 | |||
| 423 | |||
| 424 | static int bfusb_open(struct hci_dev *hdev) | ||
| 425 | { | ||
| 426 | struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; | ||
| 427 | unsigned long flags; | ||
| 428 | int i, err; | ||
| 429 | |||
| 430 | BT_DBG("hdev %p bfusb %p", hdev, bfusb); | ||
| 431 | |||
| 432 | if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) | ||
| 433 | return 0; | ||
| 434 | |||
| 435 | write_lock_irqsave(&bfusb->lock, flags); | ||
| 436 | |||
| 437 | err = bfusb_rx_submit(bfusb, NULL); | ||
| 438 | if (!err) { | ||
| 439 | for (i = 1; i < BFUSB_MAX_BULK_RX; i++) | ||
| 440 | bfusb_rx_submit(bfusb, NULL); | ||
| 441 | } else { | ||
| 442 | clear_bit(HCI_RUNNING, &hdev->flags); | ||
| 443 | } | ||
| 444 | |||
| 445 | write_unlock_irqrestore(&bfusb->lock, flags); | ||
| 446 | |||
| 447 | return err; | ||
| 448 | } | ||
| 449 | |||
| 450 | static int bfusb_flush(struct hci_dev *hdev) | ||
| 451 | { | ||
| 452 | struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; | ||
| 453 | |||
| 454 | BT_DBG("hdev %p bfusb %p", hdev, bfusb); | ||
| 455 | |||
| 456 | skb_queue_purge(&bfusb->transmit_q); | ||
| 457 | |||
| 458 | return 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | static int bfusb_close(struct hci_dev *hdev) | ||
| 462 | { | ||
| 463 | struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; | ||
| 464 | unsigned long flags; | ||
| 465 | |||
| 466 | BT_DBG("hdev %p bfusb %p", hdev, bfusb); | ||
| 467 | |||
| 468 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | ||
| 469 | return 0; | ||
| 470 | |||
| 471 | write_lock_irqsave(&bfusb->lock, flags); | ||
| 472 | write_unlock_irqrestore(&bfusb->lock, flags); | ||
| 473 | |||
| 474 | bfusb_unlink_urbs(bfusb); | ||
| 475 | bfusb_flush(hdev); | ||
| 476 | |||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | static int bfusb_send_frame(struct sk_buff *skb) | ||
| 481 | { | ||
| 482 | struct hci_dev *hdev = (struct hci_dev *) skb->dev; | ||
| 483 | struct bfusb *bfusb; | ||
| 484 | struct sk_buff *nskb; | ||
| 485 | unsigned char buf[3]; | ||
| 486 | int sent = 0, size, count; | ||
| 487 | |||
| 488 | BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len); | ||
| 489 | |||
| 490 | if (!hdev) { | ||
| 491 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
| 492 | return -ENODEV; | ||
| 493 | } | ||
| 494 | |||
| 495 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 496 | return -EBUSY; | ||
| 497 | |||
| 498 | bfusb = (struct bfusb *) hdev->driver_data; | ||
| 499 | |||
| 500 | switch (skb->pkt_type) { | ||
| 501 | case HCI_COMMAND_PKT: | ||
| 502 | hdev->stat.cmd_tx++; | ||
| 503 | break; | ||
| 504 | case HCI_ACLDATA_PKT: | ||
| 505 | hdev->stat.acl_tx++; | ||
| 506 | break; | ||
| 507 | case HCI_SCODATA_PKT: | ||
| 508 | hdev->stat.sco_tx++; | ||
| 509 | break; | ||
| 510 | }; | ||
| 511 | |||
| 512 | /* Prepend skb with frame type */ | ||
| 513 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
| 514 | |||
| 515 | count = skb->len; | ||
| 516 | |||
| 517 | /* Max HCI frame size seems to be 1511 + 1 */ | ||
| 518 | if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) { | ||
| 519 | BT_ERR("Can't allocate memory for new packet"); | ||
| 520 | return -ENOMEM; | ||
| 521 | } | ||
| 522 | |||
| 523 | nskb->dev = (void *) bfusb; | ||
| 524 | |||
| 525 | while (count) { | ||
| 526 | size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); | ||
| 527 | |||
| 528 | buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); | ||
| 529 | buf[1] = 0x00; | ||
| 530 | buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; | ||
| 531 | |||
| 532 | memcpy(skb_put(nskb, 3), buf, 3); | ||
| 533 | memcpy(skb_put(nskb, size), skb->data + sent, size); | ||
| 534 | |||
| 535 | sent += size; | ||
| 536 | count -= size; | ||
| 537 | } | ||
| 538 | |||
| 539 | /* Don't send frame with multiple size of bulk max packet */ | ||
| 540 | if ((nskb->len % bfusb->bulk_pkt_size) == 0) { | ||
| 541 | buf[0] = 0xdd; | ||
| 542 | buf[1] = 0x00; | ||
| 543 | memcpy(skb_put(nskb, 2), buf, 2); | ||
| 544 | } | ||
| 545 | |||
| 546 | read_lock(&bfusb->lock); | ||
| 547 | |||
| 548 | skb_queue_tail(&bfusb->transmit_q, nskb); | ||
| 549 | bfusb_tx_wakeup(bfusb); | ||
| 550 | |||
| 551 | read_unlock(&bfusb->lock); | ||
| 552 | |||
| 553 | kfree_skb(skb); | ||
| 554 | |||
| 555 | return 0; | ||
| 556 | } | ||
| 557 | |||
| 558 | static void bfusb_destruct(struct hci_dev *hdev) | ||
| 559 | { | ||
| 560 | struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; | ||
| 561 | |||
| 562 | BT_DBG("hdev %p bfusb %p", hdev, bfusb); | ||
| 563 | |||
| 564 | kfree(bfusb); | ||
| 565 | } | ||
| 566 | |||
| 567 | static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
| 568 | { | ||
| 569 | return -ENOIOCTLCMD; | ||
| 570 | } | ||
| 571 | |||
| 572 | |||
| 573 | static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count) | ||
| 574 | { | ||
| 575 | unsigned char *buf; | ||
| 576 | int err, pipe, len, size, sent = 0; | ||
| 577 | |||
| 578 | BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev); | ||
| 579 | |||
| 580 | BT_INFO("BlueFRITZ! USB loading firmware"); | ||
| 581 | |||
| 582 | pipe = usb_sndctrlpipe(bfusb->udev, 0); | ||
| 583 | |||
| 584 | if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, | ||
| 585 | 0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) { | ||
| 586 | BT_ERR("Can't change to loading configuration"); | ||
| 587 | return -EBUSY; | ||
| 588 | } | ||
| 589 | |||
| 590 | bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0; | ||
| 591 | |||
| 592 | buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); | ||
| 593 | if (!buf) { | ||
| 594 | BT_ERR("Can't allocate memory chunk for firmware"); | ||
| 595 | return -ENOMEM; | ||
| 596 | } | ||
| 597 | |||
| 598 | pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); | ||
| 599 | |||
| 600 | while (count) { | ||
| 601 | size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3); | ||
| 602 | |||
| 603 | memcpy(buf, firmware + sent, size); | ||
| 604 | |||
| 605 | err = usb_bulk_msg(bfusb->udev, pipe, buf, size, | ||
| 606 | &len, BFUSB_BLOCK_TIMEOUT); | ||
| 607 | |||
| 608 | if (err || (len != size)) { | ||
| 609 | BT_ERR("Error in firmware loading"); | ||
| 610 | goto error; | ||
| 611 | } | ||
| 612 | |||
| 613 | sent += size; | ||
| 614 | count -= size; | ||
| 615 | } | ||
| 616 | |||
| 617 | if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0, | ||
| 618 | &len, BFUSB_BLOCK_TIMEOUT)) < 0) { | ||
| 619 | BT_ERR("Error in null packet request"); | ||
| 620 | goto error; | ||
| 621 | } | ||
| 622 | |||
| 623 | pipe = usb_sndctrlpipe(bfusb->udev, 0); | ||
| 624 | |||
| 625 | if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, | ||
| 626 | 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { | ||
| 627 | BT_ERR("Can't change to running configuration"); | ||
| 628 | goto error; | ||
| 629 | } | ||
| 630 | |||
| 631 | bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0; | ||
| 632 | |||
| 633 | BT_INFO("BlueFRITZ! USB device ready"); | ||
| 634 | |||
| 635 | kfree(buf); | ||
| 636 | return 0; | ||
| 637 | |||
| 638 | error: | ||
| 639 | kfree(buf); | ||
| 640 | |||
| 641 | pipe = usb_sndctrlpipe(bfusb->udev, 0); | ||
| 642 | |||
| 643 | usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, | ||
| 644 | 0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
| 645 | |||
| 646 | return err; | ||
| 647 | } | ||
| 648 | |||
| 649 | static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 650 | { | ||
| 651 | const struct firmware *firmware; | ||
| 652 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 653 | struct usb_host_endpoint *bulk_out_ep; | ||
| 654 | struct usb_host_endpoint *bulk_in_ep; | ||
| 655 | struct hci_dev *hdev; | ||
| 656 | struct bfusb *bfusb; | ||
| 657 | |||
| 658 | BT_DBG("intf %p id %p", intf, id); | ||
| 659 | |||
| 660 | if (ignore) | ||
| 661 | return -ENODEV; | ||
| 662 | |||
| 663 | /* Check number of endpoints */ | ||
| 664 | if (intf->cur_altsetting->desc.bNumEndpoints < 2) | ||
| 665 | return -EIO; | ||
| 666 | |||
| 667 | bulk_out_ep = &intf->cur_altsetting->endpoint[0]; | ||
| 668 | bulk_in_ep = &intf->cur_altsetting->endpoint[1]; | ||
| 669 | |||
| 670 | if (!bulk_out_ep || !bulk_in_ep) { | ||
| 671 | BT_ERR("Bulk endpoints not found"); | ||
| 672 | goto done; | ||
| 673 | } | ||
| 674 | |||
| 675 | /* Initialize control structure and load firmware */ | ||
| 676 | if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) { | ||
| 677 | BT_ERR("Can't allocate memory for control structure"); | ||
| 678 | goto done; | ||
| 679 | } | ||
| 680 | |||
| 681 | memset(bfusb, 0, sizeof(struct bfusb)); | ||
| 682 | |||
| 683 | bfusb->udev = udev; | ||
| 684 | bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress; | ||
| 685 | bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress; | ||
| 686 | bfusb->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize); | ||
| 687 | |||
| 688 | rwlock_init(&bfusb->lock); | ||
| 689 | |||
| 690 | bfusb->reassembly = NULL; | ||
| 691 | |||
| 692 | skb_queue_head_init(&bfusb->transmit_q); | ||
| 693 | skb_queue_head_init(&bfusb->pending_q); | ||
| 694 | skb_queue_head_init(&bfusb->completed_q); | ||
| 695 | |||
| 696 | if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) { | ||
| 697 | BT_ERR("Firmware request failed"); | ||
| 698 | goto error; | ||
| 699 | } | ||
| 700 | |||
| 701 | BT_DBG("firmware data %p size %d", firmware->data, firmware->size); | ||
| 702 | |||
| 703 | if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) { | ||
| 704 | BT_ERR("Firmware loading failed"); | ||
| 705 | goto release; | ||
| 706 | } | ||
| 707 | |||
| 708 | release_firmware(firmware); | ||
| 709 | |||
| 710 | /* Initialize and register HCI device */ | ||
| 711 | hdev = hci_alloc_dev(); | ||
| 712 | if (!hdev) { | ||
| 713 | BT_ERR("Can't allocate HCI device"); | ||
| 714 | goto error; | ||
| 715 | } | ||
| 716 | |||
| 717 | bfusb->hdev = hdev; | ||
| 718 | |||
| 719 | hdev->type = HCI_USB; | ||
| 720 | hdev->driver_data = bfusb; | ||
| 721 | SET_HCIDEV_DEV(hdev, &intf->dev); | ||
| 722 | |||
| 723 | hdev->open = bfusb_open; | ||
| 724 | hdev->close = bfusb_close; | ||
| 725 | hdev->flush = bfusb_flush; | ||
| 726 | hdev->send = bfusb_send_frame; | ||
| 727 | hdev->destruct = bfusb_destruct; | ||
| 728 | hdev->ioctl = bfusb_ioctl; | ||
| 729 | |||
| 730 | hdev->owner = THIS_MODULE; | ||
| 731 | |||
| 732 | if (hci_register_dev(hdev) < 0) { | ||
| 733 | BT_ERR("Can't register HCI device"); | ||
| 734 | hci_free_dev(hdev); | ||
| 735 | goto error; | ||
| 736 | } | ||
| 737 | |||
| 738 | usb_set_intfdata(intf, bfusb); | ||
| 739 | |||
| 740 | return 0; | ||
| 741 | |||
| 742 | release: | ||
| 743 | release_firmware(firmware); | ||
| 744 | |||
| 745 | error: | ||
| 746 | kfree(bfusb); | ||
| 747 | |||
| 748 | done: | ||
| 749 | return -EIO; | ||
| 750 | } | ||
| 751 | |||
| 752 | static void bfusb_disconnect(struct usb_interface *intf) | ||
| 753 | { | ||
| 754 | struct bfusb *bfusb = usb_get_intfdata(intf); | ||
| 755 | struct hci_dev *hdev = bfusb->hdev; | ||
| 756 | |||
| 757 | BT_DBG("intf %p", intf); | ||
| 758 | |||
| 759 | if (!hdev) | ||
| 760 | return; | ||
| 761 | |||
| 762 | usb_set_intfdata(intf, NULL); | ||
| 763 | |||
| 764 | bfusb_close(hdev); | ||
| 765 | |||
| 766 | if (hci_unregister_dev(hdev) < 0) | ||
| 767 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 768 | |||
| 769 | hci_free_dev(hdev); | ||
| 770 | } | ||
| 771 | |||
| 772 | static struct usb_driver bfusb_driver = { | ||
| 773 | .owner = THIS_MODULE, | ||
| 774 | .name = "bfusb", | ||
| 775 | .probe = bfusb_probe, | ||
| 776 | .disconnect = bfusb_disconnect, | ||
| 777 | .id_table = bfusb_table, | ||
| 778 | }; | ||
| 779 | |||
| 780 | static int __init bfusb_init(void) | ||
| 781 | { | ||
| 782 | int err; | ||
| 783 | |||
| 784 | BT_INFO("BlueFRITZ! USB driver ver %s", VERSION); | ||
| 785 | |||
| 786 | if ((err = usb_register(&bfusb_driver)) < 0) | ||
| 787 | BT_ERR("Failed to register BlueFRITZ! USB driver"); | ||
| 788 | |||
| 789 | return err; | ||
| 790 | } | ||
| 791 | |||
| 792 | static void __exit bfusb_exit(void) | ||
| 793 | { | ||
| 794 | usb_deregister(&bfusb_driver); | ||
| 795 | } | ||
| 796 | |||
| 797 | module_init(bfusb_init); | ||
| 798 | module_exit(bfusb_exit); | ||
| 799 | |||
| 800 | module_param(ignore, bool, 0644); | ||
| 801 | MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); | ||
| 802 | |||
| 803 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 804 | MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); | ||
| 805 | MODULE_VERSION(VERSION); | ||
| 806 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c new file mode 100644 index 000000000000..e481cc411b5d --- /dev/null +++ b/drivers/bluetooth/bluecard_cs.c | |||
| @@ -0,0 +1,1114 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation; | ||
| 11 | * | ||
| 12 | * Software distributed under the License is distributed on an "AS | ||
| 13 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
| 14 | * implied. See the License for the specific language governing | ||
| 15 | * rights and limitations under the License. | ||
| 16 | * | ||
| 17 | * The initial developer of the original code is David A. Hinds | ||
| 18 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
| 19 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/config.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/types.h> | ||
| 30 | #include <linux/sched.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/timer.h> | ||
| 33 | #include <linux/errno.h> | ||
| 34 | #include <linux/ptrace.h> | ||
| 35 | #include <linux/ioport.h> | ||
| 36 | #include <linux/spinlock.h> | ||
| 37 | #include <linux/moduleparam.h> | ||
| 38 | #include <linux/wait.h> | ||
| 39 | |||
| 40 | #include <linux/skbuff.h> | ||
| 41 | #include <asm/io.h> | ||
| 42 | |||
| 43 | #include <pcmcia/version.h> | ||
| 44 | #include <pcmcia/cs_types.h> | ||
| 45 | #include <pcmcia/cs.h> | ||
| 46 | #include <pcmcia/cistpl.h> | ||
| 47 | #include <pcmcia/ciscode.h> | ||
| 48 | #include <pcmcia/ds.h> | ||
| 49 | #include <pcmcia/cisreg.h> | ||
| 50 | |||
| 51 | #include <net/bluetooth/bluetooth.h> | ||
| 52 | #include <net/bluetooth/hci_core.h> | ||
| 53 | |||
| 54 | |||
| 55 | |||
| 56 | /* ======================== Module parameters ======================== */ | ||
| 57 | |||
| 58 | |||
| 59 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 60 | MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)"); | ||
| 61 | MODULE_LICENSE("GPL"); | ||
| 62 | |||
| 63 | |||
| 64 | |||
| 65 | /* ======================== Local structures ======================== */ | ||
| 66 | |||
| 67 | |||
| 68 | typedef struct bluecard_info_t { | ||
| 69 | dev_link_t link; | ||
| 70 | dev_node_t node; | ||
| 71 | |||
| 72 | struct hci_dev *hdev; | ||
| 73 | |||
| 74 | spinlock_t lock; /* For serializing operations */ | ||
| 75 | struct timer_list timer; /* For LED control */ | ||
| 76 | |||
| 77 | struct sk_buff_head txq; | ||
| 78 | unsigned long tx_state; | ||
| 79 | |||
| 80 | unsigned long rx_state; | ||
| 81 | unsigned long rx_count; | ||
| 82 | struct sk_buff *rx_skb; | ||
| 83 | |||
| 84 | unsigned char ctrl_reg; | ||
| 85 | unsigned long hw_state; /* Status of the hardware and LED control */ | ||
| 86 | } bluecard_info_t; | ||
| 87 | |||
| 88 | |||
| 89 | static void bluecard_config(dev_link_t *link); | ||
| 90 | static void bluecard_release(dev_link_t *link); | ||
| 91 | static int bluecard_event(event_t event, int priority, event_callback_args_t *args); | ||
| 92 | |||
| 93 | static dev_info_t dev_info = "bluecard_cs"; | ||
| 94 | |||
| 95 | static dev_link_t *bluecard_attach(void); | ||
| 96 | static void bluecard_detach(dev_link_t *); | ||
| 97 | |||
| 98 | static dev_link_t *dev_list = NULL; | ||
| 99 | |||
| 100 | |||
| 101 | /* Default baud rate: 57600, 115200, 230400 or 460800 */ | ||
| 102 | #define DEFAULT_BAUD_RATE 230400 | ||
| 103 | |||
| 104 | |||
| 105 | /* Hardware states */ | ||
| 106 | #define CARD_READY 1 | ||
| 107 | #define CARD_HAS_PCCARD_ID 4 | ||
| 108 | #define CARD_HAS_POWER_LED 5 | ||
| 109 | #define CARD_HAS_ACTIVITY_LED 6 | ||
| 110 | |||
| 111 | /* Transmit states */ | ||
| 112 | #define XMIT_SENDING 1 | ||
| 113 | #define XMIT_WAKEUP 2 | ||
| 114 | #define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ | ||
| 115 | #define XMIT_BUF_ONE_READY 6 | ||
| 116 | #define XMIT_BUF_TWO_READY 7 | ||
| 117 | #define XMIT_SENDING_READY 8 | ||
| 118 | |||
| 119 | /* Receiver states */ | ||
| 120 | #define RECV_WAIT_PACKET_TYPE 0 | ||
| 121 | #define RECV_WAIT_EVENT_HEADER 1 | ||
| 122 | #define RECV_WAIT_ACL_HEADER 2 | ||
| 123 | #define RECV_WAIT_SCO_HEADER 3 | ||
| 124 | #define RECV_WAIT_DATA 4 | ||
| 125 | |||
| 126 | /* Special packet types */ | ||
| 127 | #define PKT_BAUD_RATE_57600 0x80 | ||
| 128 | #define PKT_BAUD_RATE_115200 0x81 | ||
| 129 | #define PKT_BAUD_RATE_230400 0x82 | ||
| 130 | #define PKT_BAUD_RATE_460800 0x83 | ||
| 131 | |||
| 132 | |||
| 133 | /* These are the register offsets */ | ||
| 134 | #define REG_COMMAND 0x20 | ||
| 135 | #define REG_INTERRUPT 0x21 | ||
| 136 | #define REG_CONTROL 0x22 | ||
| 137 | #define REG_RX_CONTROL 0x24 | ||
| 138 | #define REG_CARD_RESET 0x30 | ||
| 139 | #define REG_LED_CTRL 0x30 | ||
| 140 | |||
| 141 | /* REG_COMMAND */ | ||
| 142 | #define REG_COMMAND_TX_BUF_ONE 0x01 | ||
| 143 | #define REG_COMMAND_TX_BUF_TWO 0x02 | ||
| 144 | #define REG_COMMAND_RX_BUF_ONE 0x04 | ||
| 145 | #define REG_COMMAND_RX_BUF_TWO 0x08 | ||
| 146 | #define REG_COMMAND_RX_WIN_ONE 0x00 | ||
| 147 | #define REG_COMMAND_RX_WIN_TWO 0x10 | ||
| 148 | |||
| 149 | /* REG_CONTROL */ | ||
| 150 | #define REG_CONTROL_BAUD_RATE_57600 0x00 | ||
| 151 | #define REG_CONTROL_BAUD_RATE_115200 0x01 | ||
| 152 | #define REG_CONTROL_BAUD_RATE_230400 0x02 | ||
| 153 | #define REG_CONTROL_BAUD_RATE_460800 0x03 | ||
| 154 | #define REG_CONTROL_RTS 0x04 | ||
| 155 | #define REG_CONTROL_BT_ON 0x08 | ||
| 156 | #define REG_CONTROL_BT_RESET 0x10 | ||
| 157 | #define REG_CONTROL_BT_RES_PU 0x20 | ||
| 158 | #define REG_CONTROL_INTERRUPT 0x40 | ||
| 159 | #define REG_CONTROL_CARD_RESET 0x80 | ||
| 160 | |||
| 161 | /* REG_RX_CONTROL */ | ||
| 162 | #define RTS_LEVEL_SHIFT_BITS 0x02 | ||
| 163 | |||
| 164 | |||
| 165 | |||
| 166 | /* ======================== LED handling routines ======================== */ | ||
| 167 | |||
| 168 | |||
| 169 | static void bluecard_activity_led_timeout(u_long arg) | ||
| 170 | { | ||
| 171 | bluecard_info_t *info = (bluecard_info_t *)arg; | ||
| 172 | unsigned int iobase = info->link.io.BasePort1; | ||
| 173 | |||
| 174 | if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) | ||
| 175 | return; | ||
| 176 | |||
| 177 | if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { | ||
| 178 | /* Disable activity LED */ | ||
| 179 | outb(0x08 | 0x20, iobase + 0x30); | ||
| 180 | } else { | ||
| 181 | /* Disable power LED */ | ||
| 182 | outb(0x00, iobase + 0x30); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | |||
| 187 | static void bluecard_enable_activity_led(bluecard_info_t *info) | ||
| 188 | { | ||
| 189 | unsigned int iobase = info->link.io.BasePort1; | ||
| 190 | |||
| 191 | if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) | ||
| 192 | return; | ||
| 193 | |||
| 194 | if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { | ||
| 195 | /* Enable activity LED */ | ||
| 196 | outb(0x10 | 0x40, iobase + 0x30); | ||
| 197 | |||
| 198 | /* Stop the LED after HZ/4 */ | ||
| 199 | mod_timer(&(info->timer), jiffies + HZ / 4); | ||
| 200 | } else { | ||
| 201 | /* Enable power LED */ | ||
| 202 | outb(0x08 | 0x20, iobase + 0x30); | ||
| 203 | |||
| 204 | /* Stop the LED after HZ/2 */ | ||
| 205 | mod_timer(&(info->timer), jiffies + HZ / 2); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | |||
| 210 | |||
| 211 | /* ======================== Interrupt handling ======================== */ | ||
| 212 | |||
| 213 | |||
| 214 | static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len) | ||
| 215 | { | ||
| 216 | int i, actual; | ||
| 217 | |||
| 218 | actual = (len > 15) ? 15 : len; | ||
| 219 | |||
| 220 | outb_p(actual, iobase + offset); | ||
| 221 | |||
| 222 | for (i = 0; i < actual; i++) | ||
| 223 | outb_p(buf[i], iobase + offset + i + 1); | ||
| 224 | |||
| 225 | return actual; | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | static void bluecard_write_wakeup(bluecard_info_t *info) | ||
| 230 | { | ||
| 231 | if (!info) { | ||
| 232 | BT_ERR("Unknown device"); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) | ||
| 237 | return; | ||
| 238 | |||
| 239 | if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { | ||
| 240 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | |||
| 244 | do { | ||
| 245 | register unsigned int iobase = info->link.io.BasePort1; | ||
| 246 | register unsigned int offset; | ||
| 247 | register unsigned char command; | ||
| 248 | register unsigned long ready_bit; | ||
| 249 | register struct sk_buff *skb; | ||
| 250 | register int len; | ||
| 251 | |||
| 252 | clear_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 253 | |||
| 254 | if (!(info->link.state & DEV_PRESENT)) | ||
| 255 | return; | ||
| 256 | |||
| 257 | if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { | ||
| 258 | if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) | ||
| 259 | break; | ||
| 260 | offset = 0x10; | ||
| 261 | command = REG_COMMAND_TX_BUF_TWO; | ||
| 262 | ready_bit = XMIT_BUF_TWO_READY; | ||
| 263 | } else { | ||
| 264 | if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) | ||
| 265 | break; | ||
| 266 | offset = 0x00; | ||
| 267 | command = REG_COMMAND_TX_BUF_ONE; | ||
| 268 | ready_bit = XMIT_BUF_ONE_READY; | ||
| 269 | } | ||
| 270 | |||
| 271 | if (!(skb = skb_dequeue(&(info->txq)))) | ||
| 272 | break; | ||
| 273 | |||
| 274 | if (skb->pkt_type & 0x80) { | ||
| 275 | /* Disable RTS */ | ||
| 276 | info->ctrl_reg |= REG_CONTROL_RTS; | ||
| 277 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 278 | } | ||
| 279 | |||
| 280 | /* Activate LED */ | ||
| 281 | bluecard_enable_activity_led(info); | ||
| 282 | |||
| 283 | /* Send frame */ | ||
| 284 | len = bluecard_write(iobase, offset, skb->data, skb->len); | ||
| 285 | |||
| 286 | /* Tell the FPGA to send the data */ | ||
| 287 | outb_p(command, iobase + REG_COMMAND); | ||
| 288 | |||
| 289 | /* Mark the buffer as dirty */ | ||
| 290 | clear_bit(ready_bit, &(info->tx_state)); | ||
| 291 | |||
| 292 | if (skb->pkt_type & 0x80) { | ||
| 293 | DECLARE_WAIT_QUEUE_HEAD(wq); | ||
| 294 | DEFINE_WAIT(wait); | ||
| 295 | |||
| 296 | unsigned char baud_reg; | ||
| 297 | |||
| 298 | switch (skb->pkt_type) { | ||
| 299 | case PKT_BAUD_RATE_460800: | ||
| 300 | baud_reg = REG_CONTROL_BAUD_RATE_460800; | ||
| 301 | break; | ||
| 302 | case PKT_BAUD_RATE_230400: | ||
| 303 | baud_reg = REG_CONTROL_BAUD_RATE_230400; | ||
| 304 | break; | ||
| 305 | case PKT_BAUD_RATE_115200: | ||
| 306 | baud_reg = REG_CONTROL_BAUD_RATE_115200; | ||
| 307 | break; | ||
| 308 | case PKT_BAUD_RATE_57600: | ||
| 309 | /* Fall through... */ | ||
| 310 | default: | ||
| 311 | baud_reg = REG_CONTROL_BAUD_RATE_57600; | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* Wait until the command reaches the baseband */ | ||
| 316 | prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); | ||
| 317 | schedule_timeout(HZ/10); | ||
| 318 | finish_wait(&wq, &wait); | ||
| 319 | |||
| 320 | /* Set baud on baseband */ | ||
| 321 | info->ctrl_reg &= ~0x03; | ||
| 322 | info->ctrl_reg |= baud_reg; | ||
| 323 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 324 | |||
| 325 | /* Enable RTS */ | ||
| 326 | info->ctrl_reg &= ~REG_CONTROL_RTS; | ||
| 327 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 328 | |||
| 329 | /* Wait before the next HCI packet can be send */ | ||
| 330 | prepare_to_wait(&wq, &wait, TASK_INTERRUPTIBLE); | ||
| 331 | schedule_timeout(HZ); | ||
| 332 | finish_wait(&wq, &wait); | ||
| 333 | } | ||
| 334 | |||
| 335 | if (len == skb->len) { | ||
| 336 | kfree_skb(skb); | ||
| 337 | } else { | ||
| 338 | skb_pull(skb, len); | ||
| 339 | skb_queue_head(&(info->txq), skb); | ||
| 340 | } | ||
| 341 | |||
| 342 | info->hdev->stat.byte_tx += len; | ||
| 343 | |||
| 344 | /* Change buffer */ | ||
| 345 | change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); | ||
| 346 | |||
| 347 | } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); | ||
| 348 | |||
| 349 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
| 350 | } | ||
| 351 | |||
| 352 | |||
| 353 | static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size) | ||
| 354 | { | ||
| 355 | int i, n, len; | ||
| 356 | |||
| 357 | outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); | ||
| 358 | |||
| 359 | len = inb(iobase + offset); | ||
| 360 | n = 0; | ||
| 361 | i = 1; | ||
| 362 | |||
| 363 | while (n < len) { | ||
| 364 | |||
| 365 | if (i == 16) { | ||
| 366 | outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); | ||
| 367 | i = 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | buf[n] = inb(iobase + offset + i); | ||
| 371 | |||
| 372 | n++; | ||
| 373 | i++; | ||
| 374 | |||
| 375 | } | ||
| 376 | |||
| 377 | return len; | ||
| 378 | } | ||
| 379 | |||
| 380 | |||
| 381 | static void bluecard_receive(bluecard_info_t *info, unsigned int offset) | ||
| 382 | { | ||
| 383 | unsigned int iobase; | ||
| 384 | unsigned char buf[31]; | ||
| 385 | int i, len; | ||
| 386 | |||
| 387 | if (!info) { | ||
| 388 | BT_ERR("Unknown device"); | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | |||
| 392 | iobase = info->link.io.BasePort1; | ||
| 393 | |||
| 394 | if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) | ||
| 395 | bluecard_enable_activity_led(info); | ||
| 396 | |||
| 397 | len = bluecard_read(iobase, offset, buf, sizeof(buf)); | ||
| 398 | |||
| 399 | for (i = 0; i < len; i++) { | ||
| 400 | |||
| 401 | /* Allocate packet */ | ||
| 402 | if (info->rx_skb == NULL) { | ||
| 403 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 404 | info->rx_count = 0; | ||
| 405 | if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
| 406 | BT_ERR("Can't allocate mem for new packet"); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | if (info->rx_state == RECV_WAIT_PACKET_TYPE) { | ||
| 412 | |||
| 413 | info->rx_skb->dev = (void *) info->hdev; | ||
| 414 | info->rx_skb->pkt_type = buf[i]; | ||
| 415 | |||
| 416 | switch (info->rx_skb->pkt_type) { | ||
| 417 | |||
| 418 | case 0x00: | ||
| 419 | /* init packet */ | ||
| 420 | if (offset != 0x00) { | ||
| 421 | set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); | ||
| 422 | set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); | ||
| 423 | set_bit(XMIT_SENDING_READY, &(info->tx_state)); | ||
| 424 | bluecard_write_wakeup(info); | ||
| 425 | } | ||
| 426 | |||
| 427 | kfree_skb(info->rx_skb); | ||
| 428 | info->rx_skb = NULL; | ||
| 429 | break; | ||
| 430 | |||
| 431 | case HCI_EVENT_PKT: | ||
| 432 | info->rx_state = RECV_WAIT_EVENT_HEADER; | ||
| 433 | info->rx_count = HCI_EVENT_HDR_SIZE; | ||
| 434 | break; | ||
| 435 | |||
| 436 | case HCI_ACLDATA_PKT: | ||
| 437 | info->rx_state = RECV_WAIT_ACL_HEADER; | ||
| 438 | info->rx_count = HCI_ACL_HDR_SIZE; | ||
| 439 | break; | ||
| 440 | |||
| 441 | case HCI_SCODATA_PKT: | ||
| 442 | info->rx_state = RECV_WAIT_SCO_HEADER; | ||
| 443 | info->rx_count = HCI_SCO_HDR_SIZE; | ||
| 444 | break; | ||
| 445 | |||
| 446 | default: | ||
| 447 | /* unknown packet */ | ||
| 448 | BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type); | ||
| 449 | info->hdev->stat.err_rx++; | ||
| 450 | |||
| 451 | kfree_skb(info->rx_skb); | ||
| 452 | info->rx_skb = NULL; | ||
| 453 | break; | ||
| 454 | |||
| 455 | } | ||
| 456 | |||
| 457 | } else { | ||
| 458 | |||
| 459 | *skb_put(info->rx_skb, 1) = buf[i]; | ||
| 460 | info->rx_count--; | ||
| 461 | |||
| 462 | if (info->rx_count == 0) { | ||
| 463 | |||
| 464 | int dlen; | ||
| 465 | struct hci_event_hdr *eh; | ||
| 466 | struct hci_acl_hdr *ah; | ||
| 467 | struct hci_sco_hdr *sh; | ||
| 468 | |||
| 469 | switch (info->rx_state) { | ||
| 470 | |||
| 471 | case RECV_WAIT_EVENT_HEADER: | ||
| 472 | eh = (struct hci_event_hdr *)(info->rx_skb->data); | ||
| 473 | info->rx_state = RECV_WAIT_DATA; | ||
| 474 | info->rx_count = eh->plen; | ||
| 475 | break; | ||
| 476 | |||
| 477 | case RECV_WAIT_ACL_HEADER: | ||
| 478 | ah = (struct hci_acl_hdr *)(info->rx_skb->data); | ||
| 479 | dlen = __le16_to_cpu(ah->dlen); | ||
| 480 | info->rx_state = RECV_WAIT_DATA; | ||
| 481 | info->rx_count = dlen; | ||
| 482 | break; | ||
| 483 | |||
| 484 | case RECV_WAIT_SCO_HEADER: | ||
| 485 | sh = (struct hci_sco_hdr *)(info->rx_skb->data); | ||
| 486 | info->rx_state = RECV_WAIT_DATA; | ||
| 487 | info->rx_count = sh->dlen; | ||
| 488 | break; | ||
| 489 | |||
| 490 | case RECV_WAIT_DATA: | ||
| 491 | hci_recv_frame(info->rx_skb); | ||
| 492 | info->rx_skb = NULL; | ||
| 493 | break; | ||
| 494 | |||
| 495 | } | ||
| 496 | |||
| 497 | } | ||
| 498 | |||
| 499 | } | ||
| 500 | |||
| 501 | |||
| 502 | } | ||
| 503 | |||
| 504 | info->hdev->stat.byte_rx += len; | ||
| 505 | } | ||
| 506 | |||
| 507 | |||
| 508 | static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) | ||
| 509 | { | ||
| 510 | bluecard_info_t *info = dev_inst; | ||
| 511 | unsigned int iobase; | ||
| 512 | unsigned char reg; | ||
| 513 | |||
| 514 | if (!info || !info->hdev) { | ||
| 515 | BT_ERR("Call of irq %d for unknown device", irq); | ||
| 516 | return IRQ_NONE; | ||
| 517 | } | ||
| 518 | |||
| 519 | if (!test_bit(CARD_READY, &(info->hw_state))) | ||
| 520 | return IRQ_HANDLED; | ||
| 521 | |||
| 522 | iobase = info->link.io.BasePort1; | ||
| 523 | |||
| 524 | spin_lock(&(info->lock)); | ||
| 525 | |||
| 526 | /* Disable interrupt */ | ||
| 527 | info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; | ||
| 528 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 529 | |||
| 530 | reg = inb(iobase + REG_INTERRUPT); | ||
| 531 | |||
| 532 | if ((reg != 0x00) && (reg != 0xff)) { | ||
| 533 | |||
| 534 | if (reg & 0x04) { | ||
| 535 | bluecard_receive(info, 0x00); | ||
| 536 | outb(0x04, iobase + REG_INTERRUPT); | ||
| 537 | outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); | ||
| 538 | } | ||
| 539 | |||
| 540 | if (reg & 0x08) { | ||
| 541 | bluecard_receive(info, 0x10); | ||
| 542 | outb(0x08, iobase + REG_INTERRUPT); | ||
| 543 | outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); | ||
| 544 | } | ||
| 545 | |||
| 546 | if (reg & 0x01) { | ||
| 547 | set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); | ||
| 548 | outb(0x01, iobase + REG_INTERRUPT); | ||
| 549 | bluecard_write_wakeup(info); | ||
| 550 | } | ||
| 551 | |||
| 552 | if (reg & 0x02) { | ||
| 553 | set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); | ||
| 554 | outb(0x02, iobase + REG_INTERRUPT); | ||
| 555 | bluecard_write_wakeup(info); | ||
| 556 | } | ||
| 557 | |||
| 558 | } | ||
| 559 | |||
| 560 | /* Enable interrupt */ | ||
| 561 | info->ctrl_reg |= REG_CONTROL_INTERRUPT; | ||
| 562 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 563 | |||
| 564 | spin_unlock(&(info->lock)); | ||
| 565 | |||
| 566 | return IRQ_HANDLED; | ||
| 567 | } | ||
| 568 | |||
| 569 | |||
| 570 | |||
| 571 | /* ======================== Device specific HCI commands ======================== */ | ||
| 572 | |||
| 573 | |||
| 574 | static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) | ||
| 575 | { | ||
| 576 | bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); | ||
| 577 | struct sk_buff *skb; | ||
| 578 | |||
| 579 | /* Ericsson baud rate command */ | ||
| 580 | unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; | ||
| 581 | |||
| 582 | if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
| 583 | BT_ERR("Can't allocate mem for new packet"); | ||
| 584 | return -1; | ||
| 585 | } | ||
| 586 | |||
| 587 | switch (baud) { | ||
| 588 | case 460800: | ||
| 589 | cmd[4] = 0x00; | ||
| 590 | skb->pkt_type = PKT_BAUD_RATE_460800; | ||
| 591 | break; | ||
| 592 | case 230400: | ||
| 593 | cmd[4] = 0x01; | ||
| 594 | skb->pkt_type = PKT_BAUD_RATE_230400; | ||
| 595 | break; | ||
| 596 | case 115200: | ||
| 597 | cmd[4] = 0x02; | ||
| 598 | skb->pkt_type = PKT_BAUD_RATE_115200; | ||
| 599 | break; | ||
| 600 | case 57600: | ||
| 601 | /* Fall through... */ | ||
| 602 | default: | ||
| 603 | cmd[4] = 0x03; | ||
| 604 | skb->pkt_type = PKT_BAUD_RATE_57600; | ||
| 605 | break; | ||
| 606 | } | ||
| 607 | |||
| 608 | memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); | ||
| 609 | |||
| 610 | skb_queue_tail(&(info->txq), skb); | ||
| 611 | |||
| 612 | bluecard_write_wakeup(info); | ||
| 613 | |||
| 614 | return 0; | ||
| 615 | } | ||
| 616 | |||
| 617 | |||
| 618 | |||
| 619 | /* ======================== HCI interface ======================== */ | ||
| 620 | |||
| 621 | |||
| 622 | static int bluecard_hci_flush(struct hci_dev *hdev) | ||
| 623 | { | ||
| 624 | bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); | ||
| 625 | |||
| 626 | /* Drop TX queue */ | ||
| 627 | skb_queue_purge(&(info->txq)); | ||
| 628 | |||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 632 | |||
| 633 | static int bluecard_hci_open(struct hci_dev *hdev) | ||
| 634 | { | ||
| 635 | bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); | ||
| 636 | unsigned int iobase = info->link.io.BasePort1; | ||
| 637 | |||
| 638 | if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) | ||
| 639 | bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); | ||
| 640 | |||
| 641 | if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) | ||
| 642 | return 0; | ||
| 643 | |||
| 644 | if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { | ||
| 645 | /* Enable LED */ | ||
| 646 | outb(0x08 | 0x20, iobase + 0x30); | ||
| 647 | } | ||
| 648 | |||
| 649 | return 0; | ||
| 650 | } | ||
| 651 | |||
| 652 | |||
| 653 | static int bluecard_hci_close(struct hci_dev *hdev) | ||
| 654 | { | ||
| 655 | bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); | ||
| 656 | unsigned int iobase = info->link.io.BasePort1; | ||
| 657 | |||
| 658 | if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) | ||
| 659 | return 0; | ||
| 660 | |||
| 661 | bluecard_hci_flush(hdev); | ||
| 662 | |||
| 663 | if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { | ||
| 664 | /* Disable LED */ | ||
| 665 | outb(0x00, iobase + 0x30); | ||
| 666 | } | ||
| 667 | |||
| 668 | return 0; | ||
| 669 | } | ||
| 670 | |||
| 671 | |||
| 672 | static int bluecard_hci_send_frame(struct sk_buff *skb) | ||
| 673 | { | ||
| 674 | bluecard_info_t *info; | ||
| 675 | struct hci_dev *hdev = (struct hci_dev *)(skb->dev); | ||
| 676 | |||
| 677 | if (!hdev) { | ||
| 678 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
| 679 | return -ENODEV; | ||
| 680 | } | ||
| 681 | |||
| 682 | info = (bluecard_info_t *)(hdev->driver_data); | ||
| 683 | |||
| 684 | switch (skb->pkt_type) { | ||
| 685 | case HCI_COMMAND_PKT: | ||
| 686 | hdev->stat.cmd_tx++; | ||
| 687 | break; | ||
| 688 | case HCI_ACLDATA_PKT: | ||
| 689 | hdev->stat.acl_tx++; | ||
| 690 | break; | ||
| 691 | case HCI_SCODATA_PKT: | ||
| 692 | hdev->stat.sco_tx++; | ||
| 693 | break; | ||
| 694 | }; | ||
| 695 | |||
| 696 | /* Prepend skb with frame type */ | ||
| 697 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
| 698 | skb_queue_tail(&(info->txq), skb); | ||
| 699 | |||
| 700 | bluecard_write_wakeup(info); | ||
| 701 | |||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | |||
| 706 | static void bluecard_hci_destruct(struct hci_dev *hdev) | ||
| 707 | { | ||
| 708 | } | ||
| 709 | |||
| 710 | |||
| 711 | static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
| 712 | { | ||
| 713 | return -ENOIOCTLCMD; | ||
| 714 | } | ||
| 715 | |||
| 716 | |||
| 717 | |||
| 718 | /* ======================== Card services HCI interaction ======================== */ | ||
| 719 | |||
| 720 | |||
| 721 | static int bluecard_open(bluecard_info_t *info) | ||
| 722 | { | ||
| 723 | unsigned int iobase = info->link.io.BasePort1; | ||
| 724 | struct hci_dev *hdev; | ||
| 725 | unsigned char id; | ||
| 726 | |||
| 727 | spin_lock_init(&(info->lock)); | ||
| 728 | |||
| 729 | init_timer(&(info->timer)); | ||
| 730 | info->timer.function = &bluecard_activity_led_timeout; | ||
| 731 | info->timer.data = (u_long)info; | ||
| 732 | |||
| 733 | skb_queue_head_init(&(info->txq)); | ||
| 734 | |||
| 735 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 736 | info->rx_count = 0; | ||
| 737 | info->rx_skb = NULL; | ||
| 738 | |||
| 739 | /* Initialize HCI device */ | ||
| 740 | hdev = hci_alloc_dev(); | ||
| 741 | if (!hdev) { | ||
| 742 | BT_ERR("Can't allocate HCI device"); | ||
| 743 | return -ENOMEM; | ||
| 744 | } | ||
| 745 | |||
| 746 | info->hdev = hdev; | ||
| 747 | |||
| 748 | hdev->type = HCI_PCCARD; | ||
| 749 | hdev->driver_data = info; | ||
| 750 | |||
| 751 | hdev->open = bluecard_hci_open; | ||
| 752 | hdev->close = bluecard_hci_close; | ||
| 753 | hdev->flush = bluecard_hci_flush; | ||
| 754 | hdev->send = bluecard_hci_send_frame; | ||
| 755 | hdev->destruct = bluecard_hci_destruct; | ||
| 756 | hdev->ioctl = bluecard_hci_ioctl; | ||
| 757 | |||
| 758 | hdev->owner = THIS_MODULE; | ||
| 759 | |||
| 760 | id = inb(iobase + 0x30); | ||
| 761 | |||
| 762 | if ((id & 0x0f) == 0x02) | ||
| 763 | set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); | ||
| 764 | |||
| 765 | if (id & 0x10) | ||
| 766 | set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); | ||
| 767 | |||
| 768 | if (id & 0x20) | ||
| 769 | set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); | ||
| 770 | |||
| 771 | /* Reset card */ | ||
| 772 | info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; | ||
| 773 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 774 | |||
| 775 | /* Turn FPGA off */ | ||
| 776 | outb(0x80, iobase + 0x30); | ||
| 777 | |||
| 778 | /* Wait some time */ | ||
| 779 | msleep(10); | ||
| 780 | |||
| 781 | /* Turn FPGA on */ | ||
| 782 | outb(0x00, iobase + 0x30); | ||
| 783 | |||
| 784 | /* Activate card */ | ||
| 785 | info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; | ||
| 786 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 787 | |||
| 788 | /* Enable interrupt */ | ||
| 789 | outb(0xff, iobase + REG_INTERRUPT); | ||
| 790 | info->ctrl_reg |= REG_CONTROL_INTERRUPT; | ||
| 791 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 792 | |||
| 793 | if ((id & 0x0f) == 0x03) { | ||
| 794 | /* Disable RTS */ | ||
| 795 | info->ctrl_reg |= REG_CONTROL_RTS; | ||
| 796 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 797 | |||
| 798 | /* Set baud rate */ | ||
| 799 | info->ctrl_reg |= 0x03; | ||
| 800 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 801 | |||
| 802 | /* Enable RTS */ | ||
| 803 | info->ctrl_reg &= ~REG_CONTROL_RTS; | ||
| 804 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 805 | |||
| 806 | set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); | ||
| 807 | set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); | ||
| 808 | set_bit(XMIT_SENDING_READY, &(info->tx_state)); | ||
| 809 | } | ||
| 810 | |||
| 811 | /* Start the RX buffers */ | ||
| 812 | outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); | ||
| 813 | outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); | ||
| 814 | |||
| 815 | /* Signal that the hardware is ready */ | ||
| 816 | set_bit(CARD_READY, &(info->hw_state)); | ||
| 817 | |||
| 818 | /* Drop TX queue */ | ||
| 819 | skb_queue_purge(&(info->txq)); | ||
| 820 | |||
| 821 | /* Control the point at which RTS is enabled */ | ||
| 822 | outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); | ||
| 823 | |||
| 824 | /* Timeout before it is safe to send the first HCI packet */ | ||
| 825 | msleep(1250); | ||
| 826 | |||
| 827 | /* Register HCI device */ | ||
| 828 | if (hci_register_dev(hdev) < 0) { | ||
| 829 | BT_ERR("Can't register HCI device"); | ||
| 830 | info->hdev = NULL; | ||
| 831 | hci_free_dev(hdev); | ||
| 832 | return -ENODEV; | ||
| 833 | } | ||
| 834 | |||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | |||
| 838 | |||
| 839 | static int bluecard_close(bluecard_info_t *info) | ||
| 840 | { | ||
| 841 | unsigned int iobase = info->link.io.BasePort1; | ||
| 842 | struct hci_dev *hdev = info->hdev; | ||
| 843 | |||
| 844 | if (!hdev) | ||
| 845 | return -ENODEV; | ||
| 846 | |||
| 847 | bluecard_hci_close(hdev); | ||
| 848 | |||
| 849 | clear_bit(CARD_READY, &(info->hw_state)); | ||
| 850 | |||
| 851 | /* Reset card */ | ||
| 852 | info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; | ||
| 853 | outb(info->ctrl_reg, iobase + REG_CONTROL); | ||
| 854 | |||
| 855 | /* Turn FPGA off */ | ||
| 856 | outb(0x80, iobase + 0x30); | ||
| 857 | |||
| 858 | if (hci_unregister_dev(hdev) < 0) | ||
| 859 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 860 | |||
| 861 | hci_free_dev(hdev); | ||
| 862 | |||
| 863 | return 0; | ||
| 864 | } | ||
| 865 | |||
| 866 | static dev_link_t *bluecard_attach(void) | ||
| 867 | { | ||
| 868 | bluecard_info_t *info; | ||
| 869 | client_reg_t client_reg; | ||
| 870 | dev_link_t *link; | ||
| 871 | int ret; | ||
| 872 | |||
| 873 | /* Create new info device */ | ||
| 874 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
| 875 | if (!info) | ||
| 876 | return NULL; | ||
| 877 | memset(info, 0, sizeof(*info)); | ||
| 878 | |||
| 879 | link = &info->link; | ||
| 880 | link->priv = info; | ||
| 881 | |||
| 882 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
| 883 | link->io.NumPorts1 = 8; | ||
| 884 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
| 885 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
| 886 | |||
| 887 | link->irq.Handler = bluecard_interrupt; | ||
| 888 | link->irq.Instance = info; | ||
| 889 | |||
| 890 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
| 891 | link->conf.Vcc = 50; | ||
| 892 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
| 893 | |||
| 894 | /* Register with Card Services */ | ||
| 895 | link->next = dev_list; | ||
| 896 | dev_list = link; | ||
| 897 | client_reg.dev_info = &dev_info; | ||
| 898 | client_reg.EventMask = | ||
| 899 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
| 900 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
| 901 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
| 902 | client_reg.event_handler = &bluecard_event; | ||
| 903 | client_reg.Version = 0x0210; | ||
| 904 | client_reg.event_callback_args.client_data = link; | ||
| 905 | |||
| 906 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
| 907 | if (ret != CS_SUCCESS) { | ||
| 908 | cs_error(link->handle, RegisterClient, ret); | ||
| 909 | bluecard_detach(link); | ||
| 910 | return NULL; | ||
| 911 | } | ||
| 912 | |||
| 913 | return link; | ||
| 914 | } | ||
| 915 | |||
| 916 | |||
| 917 | static void bluecard_detach(dev_link_t *link) | ||
| 918 | { | ||
| 919 | bluecard_info_t *info = link->priv; | ||
| 920 | dev_link_t **linkp; | ||
| 921 | int ret; | ||
| 922 | |||
| 923 | /* Locate device structure */ | ||
| 924 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
| 925 | if (*linkp == link) | ||
| 926 | break; | ||
| 927 | |||
| 928 | if (*linkp == NULL) | ||
| 929 | return; | ||
| 930 | |||
| 931 | if (link->state & DEV_CONFIG) | ||
| 932 | bluecard_release(link); | ||
| 933 | |||
| 934 | if (link->handle) { | ||
| 935 | ret = pcmcia_deregister_client(link->handle); | ||
| 936 | if (ret != CS_SUCCESS) | ||
| 937 | cs_error(link->handle, DeregisterClient, ret); | ||
| 938 | } | ||
| 939 | |||
| 940 | /* Unlink device structure, free bits */ | ||
| 941 | *linkp = link->next; | ||
| 942 | |||
| 943 | kfree(info); | ||
| 944 | } | ||
| 945 | |||
| 946 | |||
| 947 | static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 948 | { | ||
| 949 | int i; | ||
| 950 | |||
| 951 | i = pcmcia_get_first_tuple(handle, tuple); | ||
| 952 | if (i != CS_SUCCESS) | ||
| 953 | return CS_NO_MORE_ITEMS; | ||
| 954 | |||
| 955 | i = pcmcia_get_tuple_data(handle, tuple); | ||
| 956 | if (i != CS_SUCCESS) | ||
| 957 | return i; | ||
| 958 | |||
| 959 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
| 960 | } | ||
| 961 | |||
| 962 | static void bluecard_config(dev_link_t *link) | ||
| 963 | { | ||
| 964 | client_handle_t handle = link->handle; | ||
| 965 | bluecard_info_t *info = link->priv; | ||
| 966 | tuple_t tuple; | ||
| 967 | u_short buf[256]; | ||
| 968 | cisparse_t parse; | ||
| 969 | config_info_t config; | ||
| 970 | int i, n, last_ret, last_fn; | ||
| 971 | |||
| 972 | tuple.TupleData = (cisdata_t *)buf; | ||
| 973 | tuple.TupleOffset = 0; | ||
| 974 | tuple.TupleDataMax = 255; | ||
| 975 | tuple.Attributes = 0; | ||
| 976 | |||
| 977 | /* Get configuration register information */ | ||
| 978 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
| 979 | last_ret = first_tuple(handle, &tuple, &parse); | ||
| 980 | if (last_ret != CS_SUCCESS) { | ||
| 981 | last_fn = ParseTuple; | ||
| 982 | goto cs_failed; | ||
| 983 | } | ||
| 984 | link->conf.ConfigBase = parse.config.base; | ||
| 985 | link->conf.Present = parse.config.rmask[0]; | ||
| 986 | |||
| 987 | /* Configure card */ | ||
| 988 | link->state |= DEV_CONFIG; | ||
| 989 | i = pcmcia_get_configuration_info(handle, &config); | ||
| 990 | link->conf.Vcc = config.Vcc; | ||
| 991 | |||
| 992 | link->conf.ConfigIndex = 0x20; | ||
| 993 | link->io.NumPorts1 = 64; | ||
| 994 | link->io.IOAddrLines = 6; | ||
| 995 | |||
| 996 | for (n = 0; n < 0x400; n += 0x40) { | ||
| 997 | link->io.BasePort1 = n ^ 0x300; | ||
| 998 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 999 | if (i == CS_SUCCESS) | ||
| 1000 | break; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | if (i != CS_SUCCESS) { | ||
| 1004 | cs_error(link->handle, RequestIO, i); | ||
| 1005 | goto failed; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
| 1009 | if (i != CS_SUCCESS) { | ||
| 1010 | cs_error(link->handle, RequestIRQ, i); | ||
| 1011 | link->irq.AssignedIRQ = 0; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
| 1015 | if (i != CS_SUCCESS) { | ||
| 1016 | cs_error(link->handle, RequestConfiguration, i); | ||
| 1017 | goto failed; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | if (bluecard_open(info) != 0) | ||
| 1021 | goto failed; | ||
| 1022 | |||
| 1023 | strcpy(info->node.dev_name, info->hdev->name); | ||
| 1024 | link->dev = &info->node; | ||
| 1025 | link->state &= ~DEV_CONFIG_PENDING; | ||
| 1026 | |||
| 1027 | return; | ||
| 1028 | |||
| 1029 | cs_failed: | ||
| 1030 | cs_error(link->handle, last_fn, last_ret); | ||
| 1031 | |||
| 1032 | failed: | ||
| 1033 | bluecard_release(link); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | |||
| 1037 | static void bluecard_release(dev_link_t *link) | ||
| 1038 | { | ||
| 1039 | bluecard_info_t *info = link->priv; | ||
| 1040 | |||
| 1041 | if (link->state & DEV_PRESENT) | ||
| 1042 | bluecard_close(info); | ||
| 1043 | |||
| 1044 | del_timer(&(info->timer)); | ||
| 1045 | |||
| 1046 | link->dev = NULL; | ||
| 1047 | |||
| 1048 | pcmcia_release_configuration(link->handle); | ||
| 1049 | pcmcia_release_io(link->handle, &link->io); | ||
| 1050 | pcmcia_release_irq(link->handle, &link->irq); | ||
| 1051 | |||
| 1052 | link->state &= ~DEV_CONFIG; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | |||
| 1056 | static int bluecard_event(event_t event, int priority, event_callback_args_t *args) | ||
| 1057 | { | ||
| 1058 | dev_link_t *link = args->client_data; | ||
| 1059 | bluecard_info_t *info = link->priv; | ||
| 1060 | |||
| 1061 | switch (event) { | ||
| 1062 | case CS_EVENT_CARD_REMOVAL: | ||
| 1063 | link->state &= ~DEV_PRESENT; | ||
| 1064 | if (link->state & DEV_CONFIG) { | ||
| 1065 | bluecard_close(info); | ||
| 1066 | bluecard_release(link); | ||
| 1067 | } | ||
| 1068 | break; | ||
| 1069 | case CS_EVENT_CARD_INSERTION: | ||
| 1070 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
| 1071 | bluecard_config(link); | ||
| 1072 | break; | ||
| 1073 | case CS_EVENT_PM_SUSPEND: | ||
| 1074 | link->state |= DEV_SUSPEND; | ||
| 1075 | /* Fall through... */ | ||
| 1076 | case CS_EVENT_RESET_PHYSICAL: | ||
| 1077 | if (link->state & DEV_CONFIG) | ||
| 1078 | pcmcia_release_configuration(link->handle); | ||
| 1079 | break; | ||
| 1080 | case CS_EVENT_PM_RESUME: | ||
| 1081 | link->state &= ~DEV_SUSPEND; | ||
| 1082 | /* Fall through... */ | ||
| 1083 | case CS_EVENT_CARD_RESET: | ||
| 1084 | if (DEV_OK(link)) | ||
| 1085 | pcmcia_request_configuration(link->handle, &link->conf); | ||
| 1086 | break; | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | return 0; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | static struct pcmcia_driver bluecard_driver = { | ||
| 1093 | .owner = THIS_MODULE, | ||
| 1094 | .drv = { | ||
| 1095 | .name = "bluecard_cs", | ||
| 1096 | }, | ||
| 1097 | .attach = bluecard_attach, | ||
| 1098 | .detach = bluecard_detach, | ||
| 1099 | }; | ||
| 1100 | |||
| 1101 | static int __init init_bluecard_cs(void) | ||
| 1102 | { | ||
| 1103 | return pcmcia_register_driver(&bluecard_driver); | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | |||
| 1107 | static void __exit exit_bluecard_cs(void) | ||
| 1108 | { | ||
| 1109 | pcmcia_unregister_driver(&bluecard_driver); | ||
| 1110 | BUG_ON(dev_list != NULL); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | module_init(init_bluecard_cs); | ||
| 1114 | module_exit(exit_bluecard_cs); | ||
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c new file mode 100644 index 000000000000..2771c861f185 --- /dev/null +++ b/drivers/bluetooth/bpa10x.c | |||
| @@ -0,0 +1,657 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Digianswer Bluetooth USB driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/errno.h> | ||
| 32 | |||
| 33 | #include <linux/usb.h> | ||
| 34 | |||
| 35 | #include <net/bluetooth/bluetooth.h> | ||
| 36 | #include <net/bluetooth/hci_core.h> | ||
| 37 | |||
| 38 | #ifndef CONFIG_BT_HCIBPA10X_DEBUG | ||
| 39 | #undef BT_DBG | ||
| 40 | #define BT_DBG(D...) | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #define VERSION "0.8" | ||
| 44 | |||
| 45 | static int ignore = 0; | ||
| 46 | |||
| 47 | static struct usb_device_id bpa10x_table[] = { | ||
| 48 | /* Tektronix BPA 100/105 (Digianswer) */ | ||
| 49 | { USB_DEVICE(0x08fd, 0x0002) }, | ||
| 50 | |||
| 51 | { } /* Terminating entry */ | ||
| 52 | }; | ||
| 53 | |||
| 54 | MODULE_DEVICE_TABLE(usb, bpa10x_table); | ||
| 55 | |||
| 56 | #define BPA10X_CMD_EP 0x00 | ||
| 57 | #define BPA10X_EVT_EP 0x81 | ||
| 58 | #define BPA10X_TX_EP 0x02 | ||
| 59 | #define BPA10X_RX_EP 0x82 | ||
| 60 | |||
| 61 | #define BPA10X_CMD_BUF_SIZE 252 | ||
| 62 | #define BPA10X_EVT_BUF_SIZE 16 | ||
| 63 | #define BPA10X_TX_BUF_SIZE 384 | ||
| 64 | #define BPA10X_RX_BUF_SIZE 384 | ||
| 65 | |||
| 66 | struct bpa10x_data { | ||
| 67 | struct hci_dev *hdev; | ||
| 68 | struct usb_device *udev; | ||
| 69 | |||
| 70 | rwlock_t lock; | ||
| 71 | |||
| 72 | struct sk_buff_head cmd_queue; | ||
| 73 | struct urb *cmd_urb; | ||
| 74 | struct urb *evt_urb; | ||
| 75 | struct sk_buff *evt_skb; | ||
| 76 | unsigned int evt_len; | ||
| 77 | |||
| 78 | struct sk_buff_head tx_queue; | ||
| 79 | struct urb *tx_urb; | ||
| 80 | struct urb *rx_urb; | ||
| 81 | }; | ||
| 82 | |||
| 83 | #define HCI_VENDOR_HDR_SIZE 5 | ||
| 84 | |||
| 85 | struct hci_vendor_hdr { | ||
| 86 | __u8 type; | ||
| 87 | __u16 snum; | ||
| 88 | __u16 dlen; | ||
| 89 | } __attribute__ ((packed)); | ||
| 90 | |||
| 91 | static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count) | ||
| 92 | { | ||
| 93 | struct hci_acl_hdr *ah; | ||
| 94 | struct hci_sco_hdr *sh; | ||
| 95 | struct hci_vendor_hdr *vh; | ||
| 96 | struct sk_buff *skb; | ||
| 97 | int len; | ||
| 98 | |||
| 99 | while (count) { | ||
| 100 | switch (*buf++) { | ||
| 101 | case HCI_ACLDATA_PKT: | ||
| 102 | ah = (struct hci_acl_hdr *) buf; | ||
| 103 | len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen); | ||
| 104 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
| 105 | if (skb) { | ||
| 106 | memcpy(skb_put(skb, len), buf, len); | ||
| 107 | skb->dev = (void *) data->hdev; | ||
| 108 | skb->pkt_type = HCI_ACLDATA_PKT; | ||
| 109 | hci_recv_frame(skb); | ||
| 110 | } | ||
| 111 | break; | ||
| 112 | |||
| 113 | case HCI_SCODATA_PKT: | ||
| 114 | sh = (struct hci_sco_hdr *) buf; | ||
| 115 | len = HCI_SCO_HDR_SIZE + sh->dlen; | ||
| 116 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
| 117 | if (skb) { | ||
| 118 | memcpy(skb_put(skb, len), buf, len); | ||
| 119 | skb->dev = (void *) data->hdev; | ||
| 120 | skb->pkt_type = HCI_SCODATA_PKT; | ||
| 121 | hci_recv_frame(skb); | ||
| 122 | } | ||
| 123 | break; | ||
| 124 | |||
| 125 | case HCI_VENDOR_PKT: | ||
| 126 | vh = (struct hci_vendor_hdr *) buf; | ||
| 127 | len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen); | ||
| 128 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
| 129 | if (skb) { | ||
| 130 | memcpy(skb_put(skb, len), buf, len); | ||
| 131 | skb->dev = (void *) data->hdev; | ||
| 132 | skb->pkt_type = HCI_VENDOR_PKT; | ||
| 133 | hci_recv_frame(skb); | ||
| 134 | } | ||
| 135 | break; | ||
| 136 | |||
| 137 | default: | ||
| 138 | len = count - 1; | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | |||
| 142 | buf += len; | ||
| 143 | count -= (len + 1); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size) | ||
| 148 | { | ||
| 149 | BT_DBG("data %p buf %p size %d", data, buf, size); | ||
| 150 | |||
| 151 | if (data->evt_skb) { | ||
| 152 | struct sk_buff *skb = data->evt_skb; | ||
| 153 | |||
| 154 | memcpy(skb_put(skb, size), buf, size); | ||
| 155 | |||
| 156 | if (skb->len == data->evt_len) { | ||
| 157 | data->evt_skb = NULL; | ||
| 158 | data->evt_len = 0; | ||
| 159 | hci_recv_frame(skb); | ||
| 160 | } | ||
| 161 | } else { | ||
| 162 | struct sk_buff *skb; | ||
| 163 | struct hci_event_hdr *hdr; | ||
| 164 | unsigned char pkt_type; | ||
| 165 | int pkt_len = 0; | ||
| 166 | |||
| 167 | if (size < HCI_EVENT_HDR_SIZE + 1) { | ||
| 168 | BT_ERR("%s event packet block with size %d is too short", | ||
| 169 | data->hdev->name, size); | ||
| 170 | return -EILSEQ; | ||
| 171 | } | ||
| 172 | |||
| 173 | pkt_type = *buf++; | ||
| 174 | size--; | ||
| 175 | |||
| 176 | if (pkt_type != HCI_EVENT_PKT) { | ||
| 177 | BT_ERR("%s unexpected event packet start byte 0x%02x", | ||
| 178 | data->hdev->name, pkt_type); | ||
| 179 | return -EPROTO; | ||
| 180 | } | ||
| 181 | |||
| 182 | hdr = (struct hci_event_hdr *) buf; | ||
| 183 | pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; | ||
| 184 | |||
| 185 | skb = bt_skb_alloc(pkt_len, GFP_ATOMIC); | ||
| 186 | if (!skb) { | ||
| 187 | BT_ERR("%s no memory for new event packet", | ||
| 188 | data->hdev->name); | ||
| 189 | return -ENOMEM; | ||
| 190 | } | ||
| 191 | |||
| 192 | skb->dev = (void *) data->hdev; | ||
| 193 | skb->pkt_type = pkt_type; | ||
| 194 | |||
| 195 | memcpy(skb_put(skb, size), buf, size); | ||
| 196 | |||
| 197 | if (pkt_len == size) { | ||
| 198 | hci_recv_frame(skb); | ||
| 199 | } else { | ||
| 200 | data->evt_skb = skb; | ||
| 201 | data->evt_len = pkt_len; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | static void bpa10x_wakeup(struct bpa10x_data *data) | ||
| 209 | { | ||
| 210 | struct urb *urb; | ||
| 211 | struct sk_buff *skb; | ||
| 212 | int err; | ||
| 213 | |||
| 214 | BT_DBG("data %p", data); | ||
| 215 | |||
| 216 | urb = data->cmd_urb; | ||
| 217 | if (urb->status == -EINPROGRESS) | ||
| 218 | skb = NULL; | ||
| 219 | else | ||
| 220 | skb = skb_dequeue(&data->cmd_queue); | ||
| 221 | |||
| 222 | if (skb) { | ||
| 223 | struct usb_ctrlrequest *cr; | ||
| 224 | |||
| 225 | if (skb->len > BPA10X_CMD_BUF_SIZE) { | ||
| 226 | BT_ERR("%s command packet with size %d is too big", | ||
| 227 | data->hdev->name, skb->len); | ||
| 228 | kfree_skb(skb); | ||
| 229 | return; | ||
| 230 | } | ||
| 231 | |||
| 232 | cr = (struct usb_ctrlrequest *) urb->setup_packet; | ||
| 233 | cr->wLength = __cpu_to_le16(skb->len); | ||
| 234 | |||
| 235 | memcpy(urb->transfer_buffer, skb->data, skb->len); | ||
| 236 | urb->transfer_buffer_length = skb->len; | ||
| 237 | |||
| 238 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 239 | if (err < 0 && err != -ENODEV) { | ||
| 240 | BT_ERR("%s submit failed for command urb %p with error %d", | ||
| 241 | data->hdev->name, urb, err); | ||
| 242 | skb_queue_head(&data->cmd_queue, skb); | ||
| 243 | } else | ||
| 244 | kfree_skb(skb); | ||
| 245 | } | ||
| 246 | |||
| 247 | urb = data->tx_urb; | ||
| 248 | if (urb->status == -EINPROGRESS) | ||
| 249 | skb = NULL; | ||
| 250 | else | ||
| 251 | skb = skb_dequeue(&data->tx_queue); | ||
| 252 | |||
| 253 | if (skb) { | ||
| 254 | memcpy(urb->transfer_buffer, skb->data, skb->len); | ||
| 255 | urb->transfer_buffer_length = skb->len; | ||
| 256 | |||
| 257 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 258 | if (err < 0 && err != -ENODEV) { | ||
| 259 | BT_ERR("%s submit failed for command urb %p with error %d", | ||
| 260 | data->hdev->name, urb, err); | ||
| 261 | skb_queue_head(&data->tx_queue, skb); | ||
| 262 | } else | ||
| 263 | kfree_skb(skb); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | static void bpa10x_complete(struct urb *urb, struct pt_regs *regs) | ||
| 268 | { | ||
| 269 | struct bpa10x_data *data = urb->context; | ||
| 270 | unsigned char *buf = urb->transfer_buffer; | ||
| 271 | int err, count = urb->actual_length; | ||
| 272 | |||
| 273 | BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count); | ||
| 274 | |||
| 275 | read_lock(&data->lock); | ||
| 276 | |||
| 277 | if (!test_bit(HCI_RUNNING, &data->hdev->flags)) | ||
| 278 | goto unlock; | ||
| 279 | |||
| 280 | if (urb->status < 0 || !count) | ||
| 281 | goto resubmit; | ||
| 282 | |||
| 283 | if (usb_pipein(urb->pipe)) { | ||
| 284 | data->hdev->stat.byte_rx += count; | ||
| 285 | |||
| 286 | if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) | ||
| 287 | bpa10x_recv_event(data, buf, count); | ||
| 288 | |||
| 289 | if (usb_pipetype(urb->pipe) == PIPE_BULK) | ||
| 290 | bpa10x_recv_bulk(data, buf, count); | ||
| 291 | } else { | ||
| 292 | data->hdev->stat.byte_tx += count; | ||
| 293 | |||
| 294 | bpa10x_wakeup(data); | ||
| 295 | } | ||
| 296 | |||
| 297 | resubmit: | ||
| 298 | if (usb_pipein(urb->pipe)) { | ||
| 299 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 300 | if (err < 0 && err != -ENODEV) { | ||
| 301 | BT_ERR("%s urb %p type %d resubmit status %d", | ||
| 302 | data->hdev->name, urb, usb_pipetype(urb->pipe), err); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | unlock: | ||
| 307 | read_unlock(&data->lock); | ||
| 308 | } | ||
| 309 | |||
| 310 | static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe, size_t size, int flags, void *data) | ||
| 311 | { | ||
| 312 | struct urb *urb; | ||
| 313 | struct usb_ctrlrequest *cr; | ||
| 314 | unsigned char *buf; | ||
| 315 | |||
| 316 | BT_DBG("udev %p data %p", udev, data); | ||
| 317 | |||
| 318 | urb = usb_alloc_urb(0, flags); | ||
| 319 | if (!urb) | ||
| 320 | return NULL; | ||
| 321 | |||
| 322 | buf = kmalloc(size, flags); | ||
| 323 | if (!buf) { | ||
| 324 | usb_free_urb(urb); | ||
| 325 | return NULL; | ||
| 326 | } | ||
| 327 | |||
| 328 | switch (usb_pipetype(pipe)) { | ||
| 329 | case PIPE_CONTROL: | ||
| 330 | cr = kmalloc(sizeof(*cr), flags); | ||
| 331 | if (!cr) { | ||
| 332 | kfree(buf); | ||
| 333 | usb_free_urb(urb); | ||
| 334 | return NULL; | ||
| 335 | } | ||
| 336 | |||
| 337 | cr->bRequestType = USB_TYPE_VENDOR; | ||
| 338 | cr->bRequest = 0; | ||
| 339 | cr->wIndex = 0; | ||
| 340 | cr->wValue = 0; | ||
| 341 | cr->wLength = __cpu_to_le16(0); | ||
| 342 | |||
| 343 | usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data); | ||
| 344 | break; | ||
| 345 | |||
| 346 | case PIPE_INTERRUPT: | ||
| 347 | usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1); | ||
| 348 | break; | ||
| 349 | |||
| 350 | case PIPE_BULK: | ||
| 351 | usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data); | ||
| 352 | break; | ||
| 353 | |||
| 354 | default: | ||
| 355 | kfree(buf); | ||
| 356 | usb_free_urb(urb); | ||
| 357 | return NULL; | ||
| 358 | } | ||
| 359 | |||
| 360 | return urb; | ||
| 361 | } | ||
| 362 | |||
| 363 | static inline void bpa10x_free_urb(struct urb *urb) | ||
| 364 | { | ||
| 365 | BT_DBG("urb %p", urb); | ||
| 366 | |||
| 367 | if (!urb) | ||
| 368 | return; | ||
| 369 | |||
| 370 | if (urb->setup_packet) | ||
| 371 | kfree(urb->setup_packet); | ||
| 372 | |||
| 373 | if (urb->transfer_buffer) | ||
| 374 | kfree(urb->transfer_buffer); | ||
| 375 | |||
| 376 | usb_free_urb(urb); | ||
| 377 | } | ||
| 378 | |||
| 379 | static int bpa10x_open(struct hci_dev *hdev) | ||
| 380 | { | ||
| 381 | struct bpa10x_data *data = hdev->driver_data; | ||
| 382 | struct usb_device *udev = data->udev; | ||
| 383 | unsigned long flags; | ||
| 384 | int err; | ||
| 385 | |||
| 386 | BT_DBG("hdev %p data %p", hdev, data); | ||
| 387 | |||
| 388 | if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) | ||
| 389 | return 0; | ||
| 390 | |||
| 391 | data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP), | ||
| 392 | BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data); | ||
| 393 | if (!data->cmd_urb) { | ||
| 394 | err = -ENOMEM; | ||
| 395 | goto done; | ||
| 396 | } | ||
| 397 | |||
| 398 | data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP), | ||
| 399 | BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data); | ||
| 400 | if (!data->evt_urb) { | ||
| 401 | bpa10x_free_urb(data->cmd_urb); | ||
| 402 | err = -ENOMEM; | ||
| 403 | goto done; | ||
| 404 | } | ||
| 405 | |||
| 406 | data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP), | ||
| 407 | BPA10X_RX_BUF_SIZE, GFP_KERNEL, data); | ||
| 408 | if (!data->rx_urb) { | ||
| 409 | bpa10x_free_urb(data->evt_urb); | ||
| 410 | bpa10x_free_urb(data->cmd_urb); | ||
| 411 | err = -ENOMEM; | ||
| 412 | goto done; | ||
| 413 | } | ||
| 414 | |||
| 415 | data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP), | ||
| 416 | BPA10X_TX_BUF_SIZE, GFP_KERNEL, data); | ||
| 417 | if (!data->rx_urb) { | ||
| 418 | bpa10x_free_urb(data->rx_urb); | ||
| 419 | bpa10x_free_urb(data->evt_urb); | ||
| 420 | bpa10x_free_urb(data->cmd_urb); | ||
| 421 | err = -ENOMEM; | ||
| 422 | goto done; | ||
| 423 | } | ||
| 424 | |||
| 425 | write_lock_irqsave(&data->lock, flags); | ||
| 426 | |||
| 427 | err = usb_submit_urb(data->evt_urb, GFP_ATOMIC); | ||
| 428 | if (err < 0) { | ||
| 429 | BT_ERR("%s submit failed for event urb %p with error %d", | ||
| 430 | data->hdev->name, data->evt_urb, err); | ||
| 431 | } else { | ||
| 432 | err = usb_submit_urb(data->rx_urb, GFP_ATOMIC); | ||
| 433 | if (err < 0) { | ||
| 434 | BT_ERR("%s submit failed for rx urb %p with error %d", | ||
| 435 | data->hdev->name, data->evt_urb, err); | ||
| 436 | usb_kill_urb(data->evt_urb); | ||
| 437 | } | ||
| 438 | } | ||
| 439 | |||
| 440 | write_unlock_irqrestore(&data->lock, flags); | ||
| 441 | |||
| 442 | done: | ||
| 443 | if (err < 0) | ||
| 444 | clear_bit(HCI_RUNNING, &hdev->flags); | ||
| 445 | |||
| 446 | return err; | ||
| 447 | } | ||
| 448 | |||
| 449 | static int bpa10x_close(struct hci_dev *hdev) | ||
| 450 | { | ||
| 451 | struct bpa10x_data *data = hdev->driver_data; | ||
| 452 | unsigned long flags; | ||
| 453 | |||
| 454 | BT_DBG("hdev %p data %p", hdev, data); | ||
| 455 | |||
| 456 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | ||
| 457 | return 0; | ||
| 458 | |||
| 459 | write_lock_irqsave(&data->lock, flags); | ||
| 460 | |||
| 461 | skb_queue_purge(&data->cmd_queue); | ||
| 462 | usb_kill_urb(data->cmd_urb); | ||
| 463 | usb_kill_urb(data->evt_urb); | ||
| 464 | usb_kill_urb(data->rx_urb); | ||
| 465 | usb_kill_urb(data->tx_urb); | ||
| 466 | |||
| 467 | write_unlock_irqrestore(&data->lock, flags); | ||
| 468 | |||
| 469 | bpa10x_free_urb(data->cmd_urb); | ||
| 470 | bpa10x_free_urb(data->evt_urb); | ||
| 471 | bpa10x_free_urb(data->rx_urb); | ||
| 472 | bpa10x_free_urb(data->tx_urb); | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | |||
| 477 | static int bpa10x_flush(struct hci_dev *hdev) | ||
| 478 | { | ||
| 479 | struct bpa10x_data *data = hdev->driver_data; | ||
| 480 | |||
| 481 | BT_DBG("hdev %p data %p", hdev, data); | ||
| 482 | |||
| 483 | skb_queue_purge(&data->cmd_queue); | ||
| 484 | |||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | static int bpa10x_send_frame(struct sk_buff *skb) | ||
| 489 | { | ||
| 490 | struct hci_dev *hdev = (struct hci_dev *) skb->dev; | ||
| 491 | struct bpa10x_data *data; | ||
| 492 | |||
| 493 | BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len); | ||
| 494 | |||
| 495 | if (!hdev) { | ||
| 496 | BT_ERR("Frame for unknown HCI device"); | ||
| 497 | return -ENODEV; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 501 | return -EBUSY; | ||
| 502 | |||
| 503 | data = hdev->driver_data; | ||
| 504 | |||
| 505 | /* Prepend skb with frame type */ | ||
| 506 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
| 507 | |||
| 508 | switch (skb->pkt_type) { | ||
| 509 | case HCI_COMMAND_PKT: | ||
| 510 | hdev->stat.cmd_tx++; | ||
| 511 | skb_queue_tail(&data->cmd_queue, skb); | ||
| 512 | break; | ||
| 513 | |||
| 514 | case HCI_ACLDATA_PKT: | ||
| 515 | hdev->stat.acl_tx++; | ||
| 516 | skb_queue_tail(&data->tx_queue, skb); | ||
| 517 | break; | ||
| 518 | |||
| 519 | case HCI_SCODATA_PKT: | ||
| 520 | hdev->stat.sco_tx++; | ||
| 521 | skb_queue_tail(&data->tx_queue, skb); | ||
| 522 | break; | ||
| 523 | }; | ||
| 524 | |||
| 525 | read_lock(&data->lock); | ||
| 526 | |||
| 527 | bpa10x_wakeup(data); | ||
| 528 | |||
| 529 | read_unlock(&data->lock); | ||
| 530 | |||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | static void bpa10x_destruct(struct hci_dev *hdev) | ||
| 535 | { | ||
| 536 | struct bpa10x_data *data = hdev->driver_data; | ||
| 537 | |||
| 538 | BT_DBG("hdev %p data %p", hdev, data); | ||
| 539 | |||
| 540 | kfree(data); | ||
| 541 | } | ||
| 542 | |||
| 543 | static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 544 | { | ||
| 545 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 546 | struct hci_dev *hdev; | ||
| 547 | struct bpa10x_data *data; | ||
| 548 | int err; | ||
| 549 | |||
| 550 | BT_DBG("intf %p id %p", intf, id); | ||
| 551 | |||
| 552 | if (ignore) | ||
| 553 | return -ENODEV; | ||
| 554 | |||
| 555 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
| 556 | if (!data) { | ||
| 557 | BT_ERR("Can't allocate data structure"); | ||
| 558 | return -ENOMEM; | ||
| 559 | } | ||
| 560 | |||
| 561 | memset(data, 0, sizeof(*data)); | ||
| 562 | |||
| 563 | data->udev = udev; | ||
| 564 | |||
| 565 | rwlock_init(&data->lock); | ||
| 566 | |||
| 567 | skb_queue_head_init(&data->cmd_queue); | ||
| 568 | skb_queue_head_init(&data->tx_queue); | ||
| 569 | |||
| 570 | hdev = hci_alloc_dev(); | ||
| 571 | if (!hdev) { | ||
| 572 | BT_ERR("Can't allocate HCI device"); | ||
| 573 | kfree(data); | ||
| 574 | return -ENOMEM; | ||
| 575 | } | ||
| 576 | |||
| 577 | data->hdev = hdev; | ||
| 578 | |||
| 579 | hdev->type = HCI_USB; | ||
| 580 | hdev->driver_data = data; | ||
| 581 | SET_HCIDEV_DEV(hdev, &intf->dev); | ||
| 582 | |||
| 583 | hdev->open = bpa10x_open; | ||
| 584 | hdev->close = bpa10x_close; | ||
| 585 | hdev->flush = bpa10x_flush; | ||
| 586 | hdev->send = bpa10x_send_frame; | ||
| 587 | hdev->destruct = bpa10x_destruct; | ||
| 588 | |||
| 589 | hdev->owner = THIS_MODULE; | ||
| 590 | |||
| 591 | err = hci_register_dev(hdev); | ||
| 592 | if (err < 0) { | ||
| 593 | BT_ERR("Can't register HCI device"); | ||
| 594 | kfree(data); | ||
| 595 | hci_free_dev(hdev); | ||
| 596 | return err; | ||
| 597 | } | ||
| 598 | |||
| 599 | usb_set_intfdata(intf, data); | ||
| 600 | |||
| 601 | return 0; | ||
| 602 | } | ||
| 603 | |||
| 604 | static void bpa10x_disconnect(struct usb_interface *intf) | ||
| 605 | { | ||
| 606 | struct bpa10x_data *data = usb_get_intfdata(intf); | ||
| 607 | struct hci_dev *hdev = data->hdev; | ||
| 608 | |||
| 609 | BT_DBG("intf %p", intf); | ||
| 610 | |||
| 611 | if (!hdev) | ||
| 612 | return; | ||
| 613 | |||
| 614 | usb_set_intfdata(intf, NULL); | ||
| 615 | |||
| 616 | if (hci_unregister_dev(hdev) < 0) | ||
| 617 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 618 | |||
| 619 | hci_free_dev(hdev); | ||
| 620 | } | ||
| 621 | |||
| 622 | static struct usb_driver bpa10x_driver = { | ||
| 623 | .owner = THIS_MODULE, | ||
| 624 | .name = "bpa10x", | ||
| 625 | .probe = bpa10x_probe, | ||
| 626 | .disconnect = bpa10x_disconnect, | ||
| 627 | .id_table = bpa10x_table, | ||
| 628 | }; | ||
| 629 | |||
| 630 | static int __init bpa10x_init(void) | ||
| 631 | { | ||
| 632 | int err; | ||
| 633 | |||
| 634 | BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION); | ||
| 635 | |||
| 636 | err = usb_register(&bpa10x_driver); | ||
| 637 | if (err < 0) | ||
| 638 | BT_ERR("Failed to register USB driver"); | ||
| 639 | |||
| 640 | return err; | ||
| 641 | } | ||
| 642 | |||
| 643 | static void __exit bpa10x_exit(void) | ||
| 644 | { | ||
| 645 | usb_deregister(&bpa10x_driver); | ||
| 646 | } | ||
| 647 | |||
| 648 | module_init(bpa10x_init); | ||
| 649 | module_exit(bpa10x_exit); | ||
| 650 | |||
| 651 | module_param(ignore, bool, 0644); | ||
| 652 | MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); | ||
| 653 | |||
| 654 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 655 | MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION); | ||
| 656 | MODULE_VERSION(VERSION); | ||
| 657 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c new file mode 100644 index 000000000000..f71e5c76963d --- /dev/null +++ b/drivers/bluetooth/bt3c_cs.c | |||
| @@ -0,0 +1,960 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Driver for the 3Com Bluetooth PCMCIA card | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * Jose Orlando Pereira <jop@di.uminho.pt> | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation; | ||
| 12 | * | ||
| 13 | * Software distributed under the License is distributed on an "AS | ||
| 14 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
| 15 | * implied. See the License for the specific language governing | ||
| 16 | * rights and limitations under the License. | ||
| 17 | * | ||
| 18 | * The initial developer of the original code is David A. Hinds | ||
| 19 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
| 20 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | |||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/init.h> | ||
| 29 | #include <linux/slab.h> | ||
| 30 | #include <linux/types.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <linux/errno.h> | ||
| 34 | #include <linux/ptrace.h> | ||
| 35 | #include <linux/ioport.h> | ||
| 36 | #include <linux/spinlock.h> | ||
| 37 | #include <linux/moduleparam.h> | ||
| 38 | |||
| 39 | #include <linux/skbuff.h> | ||
| 40 | #include <linux/string.h> | ||
| 41 | #include <linux/serial.h> | ||
| 42 | #include <linux/serial_reg.h> | ||
| 43 | #include <linux/bitops.h> | ||
| 44 | #include <asm/system.h> | ||
| 45 | #include <asm/io.h> | ||
| 46 | |||
| 47 | #include <linux/device.h> | ||
| 48 | #include <linux/firmware.h> | ||
| 49 | |||
| 50 | #include <pcmcia/version.h> | ||
| 51 | #include <pcmcia/cs_types.h> | ||
| 52 | #include <pcmcia/cs.h> | ||
| 53 | #include <pcmcia/cistpl.h> | ||
| 54 | #include <pcmcia/ciscode.h> | ||
| 55 | #include <pcmcia/ds.h> | ||
| 56 | #include <pcmcia/cisreg.h> | ||
| 57 | |||
| 58 | #include <net/bluetooth/bluetooth.h> | ||
| 59 | #include <net/bluetooth/hci_core.h> | ||
| 60 | |||
| 61 | |||
| 62 | |||
| 63 | /* ======================== Module parameters ======================== */ | ||
| 64 | |||
| 65 | |||
| 66 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); | ||
| 67 | MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); | ||
| 68 | MODULE_LICENSE("GPL"); | ||
| 69 | |||
| 70 | |||
| 71 | |||
| 72 | /* ======================== Local structures ======================== */ | ||
| 73 | |||
| 74 | |||
| 75 | typedef struct bt3c_info_t { | ||
| 76 | dev_link_t link; | ||
| 77 | dev_node_t node; | ||
| 78 | |||
| 79 | struct hci_dev *hdev; | ||
| 80 | |||
| 81 | spinlock_t lock; /* For serializing operations */ | ||
| 82 | |||
| 83 | struct sk_buff_head txq; | ||
| 84 | unsigned long tx_state; | ||
| 85 | |||
| 86 | unsigned long rx_state; | ||
| 87 | unsigned long rx_count; | ||
| 88 | struct sk_buff *rx_skb; | ||
| 89 | } bt3c_info_t; | ||
| 90 | |||
| 91 | |||
| 92 | static void bt3c_config(dev_link_t *link); | ||
| 93 | static void bt3c_release(dev_link_t *link); | ||
| 94 | static int bt3c_event(event_t event, int priority, event_callback_args_t *args); | ||
| 95 | |||
| 96 | static dev_info_t dev_info = "bt3c_cs"; | ||
| 97 | |||
| 98 | static dev_link_t *bt3c_attach(void); | ||
| 99 | static void bt3c_detach(dev_link_t *); | ||
| 100 | |||
| 101 | static dev_link_t *dev_list = NULL; | ||
| 102 | |||
| 103 | |||
| 104 | /* Transmit states */ | ||
| 105 | #define XMIT_SENDING 1 | ||
| 106 | #define XMIT_WAKEUP 2 | ||
| 107 | #define XMIT_WAITING 8 | ||
| 108 | |||
| 109 | /* Receiver states */ | ||
| 110 | #define RECV_WAIT_PACKET_TYPE 0 | ||
| 111 | #define RECV_WAIT_EVENT_HEADER 1 | ||
| 112 | #define RECV_WAIT_ACL_HEADER 2 | ||
| 113 | #define RECV_WAIT_SCO_HEADER 3 | ||
| 114 | #define RECV_WAIT_DATA 4 | ||
| 115 | |||
| 116 | |||
| 117 | |||
| 118 | /* ======================== Special I/O functions ======================== */ | ||
| 119 | |||
| 120 | |||
| 121 | #define DATA_L 0 | ||
| 122 | #define DATA_H 1 | ||
| 123 | #define ADDR_L 2 | ||
| 124 | #define ADDR_H 3 | ||
| 125 | #define CONTROL 4 | ||
| 126 | |||
| 127 | |||
| 128 | static inline void bt3c_address(unsigned int iobase, unsigned short addr) | ||
| 129 | { | ||
| 130 | outb(addr & 0xff, iobase + ADDR_L); | ||
| 131 | outb((addr >> 8) & 0xff, iobase + ADDR_H); | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | static inline void bt3c_put(unsigned int iobase, unsigned short value) | ||
| 136 | { | ||
| 137 | outb(value & 0xff, iobase + DATA_L); | ||
| 138 | outb((value >> 8) & 0xff, iobase + DATA_H); | ||
| 139 | } | ||
| 140 | |||
| 141 | |||
| 142 | static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value) | ||
| 143 | { | ||
| 144 | bt3c_address(iobase, addr); | ||
| 145 | bt3c_put(iobase, value); | ||
| 146 | } | ||
| 147 | |||
| 148 | |||
| 149 | static inline unsigned short bt3c_get(unsigned int iobase) | ||
| 150 | { | ||
| 151 | unsigned short value = inb(iobase + DATA_L); | ||
| 152 | |||
| 153 | value |= inb(iobase + DATA_H) << 8; | ||
| 154 | |||
| 155 | return value; | ||
| 156 | } | ||
| 157 | |||
| 158 | |||
| 159 | static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr) | ||
| 160 | { | ||
| 161 | bt3c_address(iobase, addr); | ||
| 162 | |||
| 163 | return bt3c_get(iobase); | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | |||
| 168 | /* ======================== Interrupt handling ======================== */ | ||
| 169 | |||
| 170 | |||
| 171 | static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) | ||
| 172 | { | ||
| 173 | int actual = 0; | ||
| 174 | |||
| 175 | bt3c_address(iobase, 0x7080); | ||
| 176 | |||
| 177 | /* Fill FIFO with current frame */ | ||
| 178 | while (actual < len) { | ||
| 179 | /* Transmit next byte */ | ||
| 180 | bt3c_put(iobase, buf[actual]); | ||
| 181 | actual++; | ||
| 182 | } | ||
| 183 | |||
| 184 | bt3c_io_write(iobase, 0x7005, actual); | ||
| 185 | |||
| 186 | return actual; | ||
| 187 | } | ||
| 188 | |||
| 189 | |||
| 190 | static void bt3c_write_wakeup(bt3c_info_t *info) | ||
| 191 | { | ||
| 192 | if (!info) { | ||
| 193 | BT_ERR("Unknown device"); | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) | ||
| 198 | return; | ||
| 199 | |||
| 200 | do { | ||
| 201 | register unsigned int iobase = info->link.io.BasePort1; | ||
| 202 | register struct sk_buff *skb; | ||
| 203 | register int len; | ||
| 204 | |||
| 205 | if (!(info->link.state & DEV_PRESENT)) | ||
| 206 | break; | ||
| 207 | |||
| 208 | |||
| 209 | if (!(skb = skb_dequeue(&(info->txq)))) { | ||
| 210 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | |||
| 214 | /* Send frame */ | ||
| 215 | len = bt3c_write(iobase, 256, skb->data, skb->len); | ||
| 216 | |||
| 217 | if (len != skb->len) { | ||
| 218 | BT_ERR("Very strange"); | ||
| 219 | } | ||
| 220 | |||
| 221 | kfree_skb(skb); | ||
| 222 | |||
| 223 | info->hdev->stat.byte_tx += len; | ||
| 224 | |||
| 225 | } while (0); | ||
| 226 | } | ||
| 227 | |||
| 228 | |||
| 229 | static void bt3c_receive(bt3c_info_t *info) | ||
| 230 | { | ||
| 231 | unsigned int iobase; | ||
| 232 | int size = 0, avail; | ||
| 233 | |||
| 234 | if (!info) { | ||
| 235 | BT_ERR("Unknown device"); | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 239 | iobase = info->link.io.BasePort1; | ||
| 240 | |||
| 241 | avail = bt3c_read(iobase, 0x7006); | ||
| 242 | //printk("bt3c_cs: receiving %d bytes\n", avail); | ||
| 243 | |||
| 244 | bt3c_address(iobase, 0x7480); | ||
| 245 | while (size < avail) { | ||
| 246 | size++; | ||
| 247 | info->hdev->stat.byte_rx++; | ||
| 248 | |||
| 249 | /* Allocate packet */ | ||
| 250 | if (info->rx_skb == NULL) { | ||
| 251 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 252 | info->rx_count = 0; | ||
| 253 | if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
| 254 | BT_ERR("Can't allocate mem for new packet"); | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | |||
| 260 | if (info->rx_state == RECV_WAIT_PACKET_TYPE) { | ||
| 261 | |||
| 262 | info->rx_skb->dev = (void *) info->hdev; | ||
| 263 | info->rx_skb->pkt_type = inb(iobase + DATA_L); | ||
| 264 | inb(iobase + DATA_H); | ||
| 265 | //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type); | ||
| 266 | |||
| 267 | switch (info->rx_skb->pkt_type) { | ||
| 268 | |||
| 269 | case HCI_EVENT_PKT: | ||
| 270 | info->rx_state = RECV_WAIT_EVENT_HEADER; | ||
| 271 | info->rx_count = HCI_EVENT_HDR_SIZE; | ||
| 272 | break; | ||
| 273 | |||
| 274 | case HCI_ACLDATA_PKT: | ||
| 275 | info->rx_state = RECV_WAIT_ACL_HEADER; | ||
| 276 | info->rx_count = HCI_ACL_HDR_SIZE; | ||
| 277 | break; | ||
| 278 | |||
| 279 | case HCI_SCODATA_PKT: | ||
| 280 | info->rx_state = RECV_WAIT_SCO_HEADER; | ||
| 281 | info->rx_count = HCI_SCO_HDR_SIZE; | ||
| 282 | break; | ||
| 283 | |||
| 284 | default: | ||
| 285 | /* Unknown packet */ | ||
| 286 | BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type); | ||
| 287 | info->hdev->stat.err_rx++; | ||
| 288 | clear_bit(HCI_RUNNING, &(info->hdev->flags)); | ||
| 289 | |||
| 290 | kfree_skb(info->rx_skb); | ||
| 291 | info->rx_skb = NULL; | ||
| 292 | break; | ||
| 293 | |||
| 294 | } | ||
| 295 | |||
| 296 | } else { | ||
| 297 | |||
| 298 | __u8 x = inb(iobase + DATA_L); | ||
| 299 | |||
| 300 | *skb_put(info->rx_skb, 1) = x; | ||
| 301 | inb(iobase + DATA_H); | ||
| 302 | info->rx_count--; | ||
| 303 | |||
| 304 | if (info->rx_count == 0) { | ||
| 305 | |||
| 306 | int dlen; | ||
| 307 | struct hci_event_hdr *eh; | ||
| 308 | struct hci_acl_hdr *ah; | ||
| 309 | struct hci_sco_hdr *sh; | ||
| 310 | |||
| 311 | switch (info->rx_state) { | ||
| 312 | |||
| 313 | case RECV_WAIT_EVENT_HEADER: | ||
| 314 | eh = (struct hci_event_hdr *)(info->rx_skb->data); | ||
| 315 | info->rx_state = RECV_WAIT_DATA; | ||
| 316 | info->rx_count = eh->plen; | ||
| 317 | break; | ||
| 318 | |||
| 319 | case RECV_WAIT_ACL_HEADER: | ||
| 320 | ah = (struct hci_acl_hdr *)(info->rx_skb->data); | ||
| 321 | dlen = __le16_to_cpu(ah->dlen); | ||
| 322 | info->rx_state = RECV_WAIT_DATA; | ||
| 323 | info->rx_count = dlen; | ||
| 324 | break; | ||
| 325 | |||
| 326 | case RECV_WAIT_SCO_HEADER: | ||
| 327 | sh = (struct hci_sco_hdr *)(info->rx_skb->data); | ||
| 328 | info->rx_state = RECV_WAIT_DATA; | ||
| 329 | info->rx_count = sh->dlen; | ||
| 330 | break; | ||
| 331 | |||
| 332 | case RECV_WAIT_DATA: | ||
| 333 | hci_recv_frame(info->rx_skb); | ||
| 334 | info->rx_skb = NULL; | ||
| 335 | break; | ||
| 336 | |||
| 337 | } | ||
| 338 | |||
| 339 | } | ||
| 340 | |||
| 341 | } | ||
| 342 | |||
| 343 | } | ||
| 344 | |||
| 345 | bt3c_io_write(iobase, 0x7006, 0x0000); | ||
| 346 | } | ||
| 347 | |||
| 348 | |||
| 349 | static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) | ||
| 350 | { | ||
| 351 | bt3c_info_t *info = dev_inst; | ||
| 352 | unsigned int iobase; | ||
| 353 | int iir; | ||
| 354 | |||
| 355 | if (!info || !info->hdev) { | ||
| 356 | BT_ERR("Call of irq %d for unknown device", irq); | ||
| 357 | return IRQ_NONE; | ||
| 358 | } | ||
| 359 | |||
| 360 | iobase = info->link.io.BasePort1; | ||
| 361 | |||
| 362 | spin_lock(&(info->lock)); | ||
| 363 | |||
| 364 | iir = inb(iobase + CONTROL); | ||
| 365 | if (iir & 0x80) { | ||
| 366 | int stat = bt3c_read(iobase, 0x7001); | ||
| 367 | |||
| 368 | if ((stat & 0xff) == 0x7f) { | ||
| 369 | BT_ERR("Very strange (stat=0x%04x)", stat); | ||
| 370 | } else if ((stat & 0xff) != 0xff) { | ||
| 371 | if (stat & 0x0020) { | ||
| 372 | int stat = bt3c_read(iobase, 0x7002) & 0x10; | ||
| 373 | BT_INFO("%s: Antenna %s", info->hdev->name, | ||
| 374 | stat ? "out" : "in"); | ||
| 375 | } | ||
| 376 | if (stat & 0x0001) | ||
| 377 | bt3c_receive(info); | ||
| 378 | if (stat & 0x0002) { | ||
| 379 | //BT_ERR("Ack (stat=0x%04x)", stat); | ||
| 380 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
| 381 | bt3c_write_wakeup(info); | ||
| 382 | } | ||
| 383 | |||
| 384 | bt3c_io_write(iobase, 0x7001, 0x0000); | ||
| 385 | |||
| 386 | outb(iir, iobase + CONTROL); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | spin_unlock(&(info->lock)); | ||
| 391 | |||
| 392 | return IRQ_HANDLED; | ||
| 393 | } | ||
| 394 | |||
| 395 | |||
| 396 | |||
| 397 | /* ======================== HCI interface ======================== */ | ||
| 398 | |||
| 399 | |||
| 400 | static int bt3c_hci_flush(struct hci_dev *hdev) | ||
| 401 | { | ||
| 402 | bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data); | ||
| 403 | |||
| 404 | /* Drop TX queue */ | ||
| 405 | skb_queue_purge(&(info->txq)); | ||
| 406 | |||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | |||
| 411 | static int bt3c_hci_open(struct hci_dev *hdev) | ||
| 412 | { | ||
| 413 | set_bit(HCI_RUNNING, &(hdev->flags)); | ||
| 414 | |||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | |||
| 419 | static int bt3c_hci_close(struct hci_dev *hdev) | ||
| 420 | { | ||
| 421 | if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | bt3c_hci_flush(hdev); | ||
| 425 | |||
| 426 | return 0; | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 430 | static int bt3c_hci_send_frame(struct sk_buff *skb) | ||
| 431 | { | ||
| 432 | bt3c_info_t *info; | ||
| 433 | struct hci_dev *hdev = (struct hci_dev *)(skb->dev); | ||
| 434 | unsigned long flags; | ||
| 435 | |||
| 436 | if (!hdev) { | ||
| 437 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
| 438 | return -ENODEV; | ||
| 439 | } | ||
| 440 | |||
| 441 | info = (bt3c_info_t *) (hdev->driver_data); | ||
| 442 | |||
| 443 | switch (skb->pkt_type) { | ||
| 444 | case HCI_COMMAND_PKT: | ||
| 445 | hdev->stat.cmd_tx++; | ||
| 446 | break; | ||
| 447 | case HCI_ACLDATA_PKT: | ||
| 448 | hdev->stat.acl_tx++; | ||
| 449 | break; | ||
| 450 | case HCI_SCODATA_PKT: | ||
| 451 | hdev->stat.sco_tx++; | ||
| 452 | break; | ||
| 453 | }; | ||
| 454 | |||
| 455 | /* Prepend skb with frame type */ | ||
| 456 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
| 457 | skb_queue_tail(&(info->txq), skb); | ||
| 458 | |||
| 459 | spin_lock_irqsave(&(info->lock), flags); | ||
| 460 | |||
| 461 | bt3c_write_wakeup(info); | ||
| 462 | |||
| 463 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 464 | |||
| 465 | return 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | |||
| 469 | static void bt3c_hci_destruct(struct hci_dev *hdev) | ||
| 470 | { | ||
| 471 | } | ||
| 472 | |||
| 473 | |||
| 474 | static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
| 475 | { | ||
| 476 | return -ENOIOCTLCMD; | ||
| 477 | } | ||
| 478 | |||
| 479 | |||
| 480 | |||
| 481 | /* ======================== Card services HCI interaction ======================== */ | ||
| 482 | |||
| 483 | |||
| 484 | static struct device *bt3c_device(void) | ||
| 485 | { | ||
| 486 | static struct device dev = { | ||
| 487 | .bus_id = "pcmcia", | ||
| 488 | }; | ||
| 489 | kobject_set_name(&dev.kobj, "bt3c"); | ||
| 490 | kobject_init(&dev.kobj); | ||
| 491 | |||
| 492 | return &dev; | ||
| 493 | } | ||
| 494 | |||
| 495 | |||
| 496 | static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count) | ||
| 497 | { | ||
| 498 | char *ptr = (char *) firmware; | ||
| 499 | char b[9]; | ||
| 500 | unsigned int iobase, size, addr, fcs, tmp; | ||
| 501 | int i, err = 0; | ||
| 502 | |||
| 503 | iobase = info->link.io.BasePort1; | ||
| 504 | |||
| 505 | /* Reset */ | ||
| 506 | bt3c_io_write(iobase, 0x8040, 0x0404); | ||
| 507 | bt3c_io_write(iobase, 0x8040, 0x0400); | ||
| 508 | |||
| 509 | udelay(1); | ||
| 510 | |||
| 511 | bt3c_io_write(iobase, 0x8040, 0x0404); | ||
| 512 | |||
| 513 | udelay(17); | ||
| 514 | |||
| 515 | /* Load */ | ||
| 516 | while (count) { | ||
| 517 | if (ptr[0] != 'S') { | ||
| 518 | BT_ERR("Bad address in firmware"); | ||
| 519 | err = -EFAULT; | ||
| 520 | goto error; | ||
| 521 | } | ||
| 522 | |||
| 523 | memset(b, 0, sizeof(b)); | ||
| 524 | memcpy(b, ptr + 2, 2); | ||
| 525 | size = simple_strtol(b, NULL, 16); | ||
| 526 | |||
| 527 | memset(b, 0, sizeof(b)); | ||
| 528 | memcpy(b, ptr + 4, 8); | ||
| 529 | addr = simple_strtol(b, NULL, 16); | ||
| 530 | |||
| 531 | memset(b, 0, sizeof(b)); | ||
| 532 | memcpy(b, ptr + (size * 2) + 2, 2); | ||
| 533 | fcs = simple_strtol(b, NULL, 16); | ||
| 534 | |||
| 535 | memset(b, 0, sizeof(b)); | ||
| 536 | for (tmp = 0, i = 0; i < size; i++) { | ||
| 537 | memcpy(b, ptr + (i * 2) + 2, 2); | ||
| 538 | tmp += simple_strtol(b, NULL, 16); | ||
| 539 | } | ||
| 540 | |||
| 541 | if (((tmp + fcs) & 0xff) != 0xff) { | ||
| 542 | BT_ERR("Checksum error in firmware"); | ||
| 543 | err = -EILSEQ; | ||
| 544 | goto error; | ||
| 545 | } | ||
| 546 | |||
| 547 | if (ptr[1] == '3') { | ||
| 548 | bt3c_address(iobase, addr); | ||
| 549 | |||
| 550 | memset(b, 0, sizeof(b)); | ||
| 551 | for (i = 0; i < (size - 4) / 2; i++) { | ||
| 552 | memcpy(b, ptr + (i * 4) + 12, 4); | ||
| 553 | tmp = simple_strtol(b, NULL, 16); | ||
| 554 | bt3c_put(iobase, tmp); | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | ptr += (size * 2) + 6; | ||
| 559 | count -= (size * 2) + 6; | ||
| 560 | } | ||
| 561 | |||
| 562 | udelay(17); | ||
| 563 | |||
| 564 | /* Boot */ | ||
| 565 | bt3c_address(iobase, 0x3000); | ||
| 566 | outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL); | ||
| 567 | |||
| 568 | error: | ||
| 569 | udelay(17); | ||
| 570 | |||
| 571 | /* Clear */ | ||
| 572 | bt3c_io_write(iobase, 0x7006, 0x0000); | ||
| 573 | bt3c_io_write(iobase, 0x7005, 0x0000); | ||
| 574 | bt3c_io_write(iobase, 0x7001, 0x0000); | ||
| 575 | |||
| 576 | return err; | ||
| 577 | } | ||
| 578 | |||
| 579 | |||
| 580 | static int bt3c_open(bt3c_info_t *info) | ||
| 581 | { | ||
| 582 | const struct firmware *firmware; | ||
| 583 | struct hci_dev *hdev; | ||
| 584 | int err; | ||
| 585 | |||
| 586 | spin_lock_init(&(info->lock)); | ||
| 587 | |||
| 588 | skb_queue_head_init(&(info->txq)); | ||
| 589 | |||
| 590 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 591 | info->rx_count = 0; | ||
| 592 | info->rx_skb = NULL; | ||
| 593 | |||
| 594 | /* Initialize HCI device */ | ||
| 595 | hdev = hci_alloc_dev(); | ||
| 596 | if (!hdev) { | ||
| 597 | BT_ERR("Can't allocate HCI device"); | ||
| 598 | return -ENOMEM; | ||
| 599 | } | ||
| 600 | |||
| 601 | info->hdev = hdev; | ||
| 602 | |||
| 603 | hdev->type = HCI_PCCARD; | ||
| 604 | hdev->driver_data = info; | ||
| 605 | |||
| 606 | hdev->open = bt3c_hci_open; | ||
| 607 | hdev->close = bt3c_hci_close; | ||
| 608 | hdev->flush = bt3c_hci_flush; | ||
| 609 | hdev->send = bt3c_hci_send_frame; | ||
| 610 | hdev->destruct = bt3c_hci_destruct; | ||
| 611 | hdev->ioctl = bt3c_hci_ioctl; | ||
| 612 | |||
| 613 | hdev->owner = THIS_MODULE; | ||
| 614 | |||
| 615 | /* Load firmware */ | ||
| 616 | err = request_firmware(&firmware, "BT3CPCC.bin", bt3c_device()); | ||
| 617 | if (err < 0) { | ||
| 618 | BT_ERR("Firmware request failed"); | ||
| 619 | goto error; | ||
| 620 | } | ||
| 621 | |||
| 622 | err = bt3c_load_firmware(info, firmware->data, firmware->size); | ||
| 623 | |||
| 624 | release_firmware(firmware); | ||
| 625 | |||
| 626 | if (err < 0) { | ||
| 627 | BT_ERR("Firmware loading failed"); | ||
| 628 | goto error; | ||
| 629 | } | ||
| 630 | |||
| 631 | /* Timeout before it is safe to send the first HCI packet */ | ||
| 632 | msleep(1000); | ||
| 633 | |||
| 634 | /* Register HCI device */ | ||
| 635 | err = hci_register_dev(hdev); | ||
| 636 | if (err < 0) { | ||
| 637 | BT_ERR("Can't register HCI device"); | ||
| 638 | goto error; | ||
| 639 | } | ||
| 640 | |||
| 641 | return 0; | ||
| 642 | |||
| 643 | error: | ||
| 644 | info->hdev = NULL; | ||
| 645 | hci_free_dev(hdev); | ||
| 646 | return err; | ||
| 647 | } | ||
| 648 | |||
| 649 | |||
| 650 | static int bt3c_close(bt3c_info_t *info) | ||
| 651 | { | ||
| 652 | struct hci_dev *hdev = info->hdev; | ||
| 653 | |||
| 654 | if (!hdev) | ||
| 655 | return -ENODEV; | ||
| 656 | |||
| 657 | bt3c_hci_close(hdev); | ||
| 658 | |||
| 659 | if (hci_unregister_dev(hdev) < 0) | ||
| 660 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 661 | |||
| 662 | hci_free_dev(hdev); | ||
| 663 | |||
| 664 | return 0; | ||
| 665 | } | ||
| 666 | |||
| 667 | static dev_link_t *bt3c_attach(void) | ||
| 668 | { | ||
| 669 | bt3c_info_t *info; | ||
| 670 | client_reg_t client_reg; | ||
| 671 | dev_link_t *link; | ||
| 672 | int ret; | ||
| 673 | |||
| 674 | /* Create new info device */ | ||
| 675 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
| 676 | if (!info) | ||
| 677 | return NULL; | ||
| 678 | memset(info, 0, sizeof(*info)); | ||
| 679 | |||
| 680 | link = &info->link; | ||
| 681 | link->priv = info; | ||
| 682 | |||
| 683 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
| 684 | link->io.NumPorts1 = 8; | ||
| 685 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
| 686 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
| 687 | |||
| 688 | link->irq.Handler = bt3c_interrupt; | ||
| 689 | link->irq.Instance = info; | ||
| 690 | |||
| 691 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
| 692 | link->conf.Vcc = 50; | ||
| 693 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
| 694 | |||
| 695 | /* Register with Card Services */ | ||
| 696 | link->next = dev_list; | ||
| 697 | dev_list = link; | ||
| 698 | client_reg.dev_info = &dev_info; | ||
| 699 | client_reg.EventMask = | ||
| 700 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
| 701 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
| 702 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
| 703 | client_reg.event_handler = &bt3c_event; | ||
| 704 | client_reg.Version = 0x0210; | ||
| 705 | client_reg.event_callback_args.client_data = link; | ||
| 706 | |||
| 707 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
| 708 | if (ret != CS_SUCCESS) { | ||
| 709 | cs_error(link->handle, RegisterClient, ret); | ||
| 710 | bt3c_detach(link); | ||
| 711 | return NULL; | ||
| 712 | } | ||
| 713 | |||
| 714 | return link; | ||
| 715 | } | ||
| 716 | |||
| 717 | |||
| 718 | static void bt3c_detach(dev_link_t *link) | ||
| 719 | { | ||
| 720 | bt3c_info_t *info = link->priv; | ||
| 721 | dev_link_t **linkp; | ||
| 722 | int ret; | ||
| 723 | |||
| 724 | /* Locate device structure */ | ||
| 725 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
| 726 | if (*linkp == link) | ||
| 727 | break; | ||
| 728 | |||
| 729 | if (*linkp == NULL) | ||
| 730 | return; | ||
| 731 | |||
| 732 | if (link->state & DEV_CONFIG) | ||
| 733 | bt3c_release(link); | ||
| 734 | |||
| 735 | if (link->handle) { | ||
| 736 | ret = pcmcia_deregister_client(link->handle); | ||
| 737 | if (ret != CS_SUCCESS) | ||
| 738 | cs_error(link->handle, DeregisterClient, ret); | ||
| 739 | } | ||
| 740 | |||
| 741 | /* Unlink device structure, free bits */ | ||
| 742 | *linkp = link->next; | ||
| 743 | |||
| 744 | kfree(info); | ||
| 745 | } | ||
| 746 | |||
| 747 | static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 748 | { | ||
| 749 | int i; | ||
| 750 | |||
| 751 | i = pcmcia_get_tuple_data(handle, tuple); | ||
| 752 | if (i != CS_SUCCESS) | ||
| 753 | return i; | ||
| 754 | |||
| 755 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
| 756 | } | ||
| 757 | |||
| 758 | static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 759 | { | ||
| 760 | if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) | ||
| 761 | return CS_NO_MORE_ITEMS; | ||
| 762 | return get_tuple(handle, tuple, parse); | ||
| 763 | } | ||
| 764 | |||
| 765 | static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 766 | { | ||
| 767 | if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) | ||
| 768 | return CS_NO_MORE_ITEMS; | ||
| 769 | return get_tuple(handle, tuple, parse); | ||
| 770 | } | ||
| 771 | |||
| 772 | static void bt3c_config(dev_link_t *link) | ||
| 773 | { | ||
| 774 | static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | ||
| 775 | client_handle_t handle = link->handle; | ||
| 776 | bt3c_info_t *info = link->priv; | ||
| 777 | tuple_t tuple; | ||
| 778 | u_short buf[256]; | ||
| 779 | cisparse_t parse; | ||
| 780 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
| 781 | config_info_t config; | ||
| 782 | int i, j, try, last_ret, last_fn; | ||
| 783 | |||
| 784 | tuple.TupleData = (cisdata_t *)buf; | ||
| 785 | tuple.TupleOffset = 0; | ||
| 786 | tuple.TupleDataMax = 255; | ||
| 787 | tuple.Attributes = 0; | ||
| 788 | |||
| 789 | /* Get configuration register information */ | ||
| 790 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
| 791 | last_ret = first_tuple(handle, &tuple, &parse); | ||
| 792 | if (last_ret != CS_SUCCESS) { | ||
| 793 | last_fn = ParseTuple; | ||
| 794 | goto cs_failed; | ||
| 795 | } | ||
| 796 | link->conf.ConfigBase = parse.config.base; | ||
| 797 | link->conf.Present = parse.config.rmask[0]; | ||
| 798 | |||
| 799 | /* Configure card */ | ||
| 800 | link->state |= DEV_CONFIG; | ||
| 801 | i = pcmcia_get_configuration_info(handle, &config); | ||
| 802 | link->conf.Vcc = config.Vcc; | ||
| 803 | |||
| 804 | /* First pass: look for a config entry that looks normal. */ | ||
| 805 | tuple.TupleData = (cisdata_t *)buf; | ||
| 806 | tuple.TupleOffset = 0; | ||
| 807 | tuple.TupleDataMax = 255; | ||
| 808 | tuple.Attributes = 0; | ||
| 809 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
| 810 | /* Two tries: without IO aliases, then with aliases */ | ||
| 811 | for (try = 0; try < 2; try++) { | ||
| 812 | i = first_tuple(handle, &tuple, &parse); | ||
| 813 | while (i != CS_NO_MORE_ITEMS) { | ||
| 814 | if (i != CS_SUCCESS) | ||
| 815 | goto next_entry; | ||
| 816 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
| 817 | link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
| 818 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { | ||
| 819 | link->conf.ConfigIndex = cf->index; | ||
| 820 | link->io.BasePort1 = cf->io.win[0].base; | ||
| 821 | link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | ||
| 822 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 823 | if (i == CS_SUCCESS) | ||
| 824 | goto found_port; | ||
| 825 | } | ||
| 826 | next_entry: | ||
| 827 | i = next_tuple(handle, &tuple, &parse); | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | /* Second pass: try to find an entry that isn't picky about | ||
| 832 | its base address, then try to grab any standard serial port | ||
| 833 | address, and finally try to get any free port. */ | ||
| 834 | i = first_tuple(handle, &tuple, &parse); | ||
| 835 | while (i != CS_NO_MORE_ITEMS) { | ||
| 836 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | ||
| 837 | link->conf.ConfigIndex = cf->index; | ||
| 838 | for (j = 0; j < 5; j++) { | ||
| 839 | link->io.BasePort1 = base[j]; | ||
| 840 | link->io.IOAddrLines = base[j] ? 16 : 3; | ||
| 841 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 842 | if (i == CS_SUCCESS) | ||
| 843 | goto found_port; | ||
| 844 | } | ||
| 845 | } | ||
| 846 | i = next_tuple(handle, &tuple, &parse); | ||
| 847 | } | ||
| 848 | |||
| 849 | found_port: | ||
| 850 | if (i != CS_SUCCESS) { | ||
| 851 | BT_ERR("No usable port range found"); | ||
| 852 | cs_error(link->handle, RequestIO, i); | ||
| 853 | goto failed; | ||
| 854 | } | ||
| 855 | |||
| 856 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
| 857 | if (i != CS_SUCCESS) { | ||
| 858 | cs_error(link->handle, RequestIRQ, i); | ||
| 859 | link->irq.AssignedIRQ = 0; | ||
| 860 | } | ||
| 861 | |||
| 862 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
| 863 | if (i != CS_SUCCESS) { | ||
| 864 | cs_error(link->handle, RequestConfiguration, i); | ||
| 865 | goto failed; | ||
| 866 | } | ||
| 867 | |||
| 868 | if (bt3c_open(info) != 0) | ||
| 869 | goto failed; | ||
| 870 | |||
| 871 | strcpy(info->node.dev_name, info->hdev->name); | ||
| 872 | link->dev = &info->node; | ||
| 873 | link->state &= ~DEV_CONFIG_PENDING; | ||
| 874 | |||
| 875 | return; | ||
| 876 | |||
| 877 | cs_failed: | ||
| 878 | cs_error(link->handle, last_fn, last_ret); | ||
| 879 | |||
| 880 | failed: | ||
| 881 | bt3c_release(link); | ||
| 882 | } | ||
| 883 | |||
| 884 | |||
| 885 | static void bt3c_release(dev_link_t *link) | ||
| 886 | { | ||
| 887 | bt3c_info_t *info = link->priv; | ||
| 888 | |||
| 889 | if (link->state & DEV_PRESENT) | ||
| 890 | bt3c_close(info); | ||
| 891 | |||
| 892 | link->dev = NULL; | ||
| 893 | |||
| 894 | pcmcia_release_configuration(link->handle); | ||
| 895 | pcmcia_release_io(link->handle, &link->io); | ||
| 896 | pcmcia_release_irq(link->handle, &link->irq); | ||
| 897 | |||
| 898 | link->state &= ~DEV_CONFIG; | ||
| 899 | } | ||
| 900 | |||
| 901 | |||
| 902 | static int bt3c_event(event_t event, int priority, event_callback_args_t *args) | ||
| 903 | { | ||
| 904 | dev_link_t *link = args->client_data; | ||
| 905 | bt3c_info_t *info = link->priv; | ||
| 906 | |||
| 907 | switch (event) { | ||
| 908 | case CS_EVENT_CARD_REMOVAL: | ||
| 909 | link->state &= ~DEV_PRESENT; | ||
| 910 | if (link->state & DEV_CONFIG) { | ||
| 911 | bt3c_close(info); | ||
| 912 | bt3c_release(link); | ||
| 913 | } | ||
| 914 | break; | ||
| 915 | case CS_EVENT_CARD_INSERTION: | ||
| 916 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
| 917 | bt3c_config(link); | ||
| 918 | break; | ||
| 919 | case CS_EVENT_PM_SUSPEND: | ||
| 920 | link->state |= DEV_SUSPEND; | ||
| 921 | /* Fall through... */ | ||
| 922 | case CS_EVENT_RESET_PHYSICAL: | ||
| 923 | if (link->state & DEV_CONFIG) | ||
| 924 | pcmcia_release_configuration(link->handle); | ||
| 925 | break; | ||
| 926 | case CS_EVENT_PM_RESUME: | ||
| 927 | link->state &= ~DEV_SUSPEND; | ||
| 928 | /* Fall through... */ | ||
| 929 | case CS_EVENT_CARD_RESET: | ||
| 930 | if (DEV_OK(link)) | ||
| 931 | pcmcia_request_configuration(link->handle, &link->conf); | ||
| 932 | break; | ||
| 933 | } | ||
| 934 | |||
| 935 | return 0; | ||
| 936 | } | ||
| 937 | |||
| 938 | static struct pcmcia_driver bt3c_driver = { | ||
| 939 | .owner = THIS_MODULE, | ||
| 940 | .drv = { | ||
| 941 | .name = "bt3c_cs", | ||
| 942 | }, | ||
| 943 | .attach = bt3c_attach, | ||
| 944 | .detach = bt3c_detach, | ||
| 945 | }; | ||
| 946 | |||
| 947 | static int __init init_bt3c_cs(void) | ||
| 948 | { | ||
| 949 | return pcmcia_register_driver(&bt3c_driver); | ||
| 950 | } | ||
| 951 | |||
| 952 | |||
| 953 | static void __exit exit_bt3c_cs(void) | ||
| 954 | { | ||
| 955 | pcmcia_unregister_driver(&bt3c_driver); | ||
| 956 | BUG_ON(dev_list != NULL); | ||
| 957 | } | ||
| 958 | |||
| 959 | module_init(init_bt3c_cs); | ||
| 960 | module_exit(exit_bt3c_cs); | ||
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c new file mode 100644 index 000000000000..ad8d972444a5 --- /dev/null +++ b/drivers/bluetooth/btuart_cs.c | |||
| @@ -0,0 +1,880 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * Driver for Bluetooth PCMCIA cards with HCI UART interface | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation; | ||
| 11 | * | ||
| 12 | * Software distributed under the License is distributed on an "AS | ||
| 13 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
| 14 | * implied. See the License for the specific language governing | ||
| 15 | * rights and limitations under the License. | ||
| 16 | * | ||
| 17 | * The initial developer of the original code is David A. Hinds | ||
| 18 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
| 19 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/config.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/types.h> | ||
| 30 | #include <linux/sched.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/errno.h> | ||
| 33 | #include <linux/ptrace.h> | ||
| 34 | #include <linux/ioport.h> | ||
| 35 | #include <linux/spinlock.h> | ||
| 36 | #include <linux/moduleparam.h> | ||
| 37 | |||
| 38 | #include <linux/skbuff.h> | ||
| 39 | #include <linux/string.h> | ||
| 40 | #include <linux/serial.h> | ||
| 41 | #include <linux/serial_reg.h> | ||
| 42 | #include <linux/bitops.h> | ||
| 43 | #include <asm/system.h> | ||
| 44 | #include <asm/io.h> | ||
| 45 | |||
| 46 | #include <pcmcia/version.h> | ||
| 47 | #include <pcmcia/cs_types.h> | ||
| 48 | #include <pcmcia/cs.h> | ||
| 49 | #include <pcmcia/cistpl.h> | ||
| 50 | #include <pcmcia/ciscode.h> | ||
| 51 | #include <pcmcia/ds.h> | ||
| 52 | #include <pcmcia/cisreg.h> | ||
| 53 | |||
| 54 | #include <net/bluetooth/bluetooth.h> | ||
| 55 | #include <net/bluetooth/hci_core.h> | ||
| 56 | |||
| 57 | |||
| 58 | |||
| 59 | /* ======================== Module parameters ======================== */ | ||
| 60 | |||
| 61 | |||
| 62 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 63 | MODULE_DESCRIPTION("Bluetooth driver for Bluetooth PCMCIA cards with HCI UART interface"); | ||
| 64 | MODULE_LICENSE("GPL"); | ||
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | /* ======================== Local structures ======================== */ | ||
| 69 | |||
| 70 | |||
| 71 | typedef struct btuart_info_t { | ||
| 72 | dev_link_t link; | ||
| 73 | dev_node_t node; | ||
| 74 | |||
| 75 | struct hci_dev *hdev; | ||
| 76 | |||
| 77 | spinlock_t lock; /* For serializing operations */ | ||
| 78 | |||
| 79 | struct sk_buff_head txq; | ||
| 80 | unsigned long tx_state; | ||
| 81 | |||
| 82 | unsigned long rx_state; | ||
| 83 | unsigned long rx_count; | ||
| 84 | struct sk_buff *rx_skb; | ||
| 85 | } btuart_info_t; | ||
| 86 | |||
| 87 | |||
| 88 | static void btuart_config(dev_link_t *link); | ||
| 89 | static void btuart_release(dev_link_t *link); | ||
| 90 | static int btuart_event(event_t event, int priority, event_callback_args_t *args); | ||
| 91 | |||
| 92 | static dev_info_t dev_info = "btuart_cs"; | ||
| 93 | |||
| 94 | static dev_link_t *btuart_attach(void); | ||
| 95 | static void btuart_detach(dev_link_t *); | ||
| 96 | |||
| 97 | static dev_link_t *dev_list = NULL; | ||
| 98 | |||
| 99 | |||
| 100 | /* Maximum baud rate */ | ||
| 101 | #define SPEED_MAX 115200 | ||
| 102 | |||
| 103 | /* Default baud rate: 57600, 115200, 230400 or 460800 */ | ||
| 104 | #define DEFAULT_BAUD_RATE 115200 | ||
| 105 | |||
| 106 | |||
| 107 | /* Transmit states */ | ||
| 108 | #define XMIT_SENDING 1 | ||
| 109 | #define XMIT_WAKEUP 2 | ||
| 110 | #define XMIT_WAITING 8 | ||
| 111 | |||
| 112 | /* Receiver states */ | ||
| 113 | #define RECV_WAIT_PACKET_TYPE 0 | ||
| 114 | #define RECV_WAIT_EVENT_HEADER 1 | ||
| 115 | #define RECV_WAIT_ACL_HEADER 2 | ||
| 116 | #define RECV_WAIT_SCO_HEADER 3 | ||
| 117 | #define RECV_WAIT_DATA 4 | ||
| 118 | |||
| 119 | |||
| 120 | |||
| 121 | /* ======================== Interrupt handling ======================== */ | ||
| 122 | |||
| 123 | |||
| 124 | static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) | ||
| 125 | { | ||
| 126 | int actual = 0; | ||
| 127 | |||
| 128 | /* Tx FIFO should be empty */ | ||
| 129 | if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) | ||
| 130 | return 0; | ||
| 131 | |||
| 132 | /* Fill FIFO with current frame */ | ||
| 133 | while ((fifo_size-- > 0) && (actual < len)) { | ||
| 134 | /* Transmit next byte */ | ||
| 135 | outb(buf[actual], iobase + UART_TX); | ||
| 136 | actual++; | ||
| 137 | } | ||
| 138 | |||
| 139 | return actual; | ||
| 140 | } | ||
| 141 | |||
| 142 | |||
| 143 | static void btuart_write_wakeup(btuart_info_t *info) | ||
| 144 | { | ||
| 145 | if (!info) { | ||
| 146 | BT_ERR("Unknown device"); | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { | ||
| 151 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 152 | return; | ||
| 153 | } | ||
| 154 | |||
| 155 | do { | ||
| 156 | register unsigned int iobase = info->link.io.BasePort1; | ||
| 157 | register struct sk_buff *skb; | ||
| 158 | register int len; | ||
| 159 | |||
| 160 | clear_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 161 | |||
| 162 | if (!(info->link.state & DEV_PRESENT)) | ||
| 163 | return; | ||
| 164 | |||
| 165 | if (!(skb = skb_dequeue(&(info->txq)))) | ||
| 166 | break; | ||
| 167 | |||
| 168 | /* Send frame */ | ||
| 169 | len = btuart_write(iobase, 16, skb->data, skb->len); | ||
| 170 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 171 | |||
| 172 | if (len == skb->len) { | ||
| 173 | kfree_skb(skb); | ||
| 174 | } else { | ||
| 175 | skb_pull(skb, len); | ||
| 176 | skb_queue_head(&(info->txq), skb); | ||
| 177 | } | ||
| 178 | |||
| 179 | info->hdev->stat.byte_tx += len; | ||
| 180 | |||
| 181 | } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); | ||
| 182 | |||
| 183 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
| 184 | } | ||
| 185 | |||
| 186 | |||
| 187 | static void btuart_receive(btuart_info_t *info) | ||
| 188 | { | ||
| 189 | unsigned int iobase; | ||
| 190 | int boguscount = 0; | ||
| 191 | |||
| 192 | if (!info) { | ||
| 193 | BT_ERR("Unknown device"); | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | |||
| 197 | iobase = info->link.io.BasePort1; | ||
| 198 | |||
| 199 | do { | ||
| 200 | info->hdev->stat.byte_rx++; | ||
| 201 | |||
| 202 | /* Allocate packet */ | ||
| 203 | if (info->rx_skb == NULL) { | ||
| 204 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 205 | info->rx_count = 0; | ||
| 206 | if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
| 207 | BT_ERR("Can't allocate mem for new packet"); | ||
| 208 | return; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | if (info->rx_state == RECV_WAIT_PACKET_TYPE) { | ||
| 213 | |||
| 214 | info->rx_skb->dev = (void *) info->hdev; | ||
| 215 | info->rx_skb->pkt_type = inb(iobase + UART_RX); | ||
| 216 | |||
| 217 | switch (info->rx_skb->pkt_type) { | ||
| 218 | |||
| 219 | case HCI_EVENT_PKT: | ||
| 220 | info->rx_state = RECV_WAIT_EVENT_HEADER; | ||
| 221 | info->rx_count = HCI_EVENT_HDR_SIZE; | ||
| 222 | break; | ||
| 223 | |||
| 224 | case HCI_ACLDATA_PKT: | ||
| 225 | info->rx_state = RECV_WAIT_ACL_HEADER; | ||
| 226 | info->rx_count = HCI_ACL_HDR_SIZE; | ||
| 227 | break; | ||
| 228 | |||
| 229 | case HCI_SCODATA_PKT: | ||
| 230 | info->rx_state = RECV_WAIT_SCO_HEADER; | ||
| 231 | info->rx_count = HCI_SCO_HDR_SIZE; | ||
| 232 | break; | ||
| 233 | |||
| 234 | default: | ||
| 235 | /* Unknown packet */ | ||
| 236 | BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type); | ||
| 237 | info->hdev->stat.err_rx++; | ||
| 238 | clear_bit(HCI_RUNNING, &(info->hdev->flags)); | ||
| 239 | |||
| 240 | kfree_skb(info->rx_skb); | ||
| 241 | info->rx_skb = NULL; | ||
| 242 | break; | ||
| 243 | |||
| 244 | } | ||
| 245 | |||
| 246 | } else { | ||
| 247 | |||
| 248 | *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); | ||
| 249 | info->rx_count--; | ||
| 250 | |||
| 251 | if (info->rx_count == 0) { | ||
| 252 | |||
| 253 | int dlen; | ||
| 254 | struct hci_event_hdr *eh; | ||
| 255 | struct hci_acl_hdr *ah; | ||
| 256 | struct hci_sco_hdr *sh; | ||
| 257 | |||
| 258 | |||
| 259 | switch (info->rx_state) { | ||
| 260 | |||
| 261 | case RECV_WAIT_EVENT_HEADER: | ||
| 262 | eh = (struct hci_event_hdr *)(info->rx_skb->data); | ||
| 263 | info->rx_state = RECV_WAIT_DATA; | ||
| 264 | info->rx_count = eh->plen; | ||
| 265 | break; | ||
| 266 | |||
| 267 | case RECV_WAIT_ACL_HEADER: | ||
| 268 | ah = (struct hci_acl_hdr *)(info->rx_skb->data); | ||
| 269 | dlen = __le16_to_cpu(ah->dlen); | ||
| 270 | info->rx_state = RECV_WAIT_DATA; | ||
| 271 | info->rx_count = dlen; | ||
| 272 | break; | ||
| 273 | |||
| 274 | case RECV_WAIT_SCO_HEADER: | ||
| 275 | sh = (struct hci_sco_hdr *)(info->rx_skb->data); | ||
| 276 | info->rx_state = RECV_WAIT_DATA; | ||
| 277 | info->rx_count = sh->dlen; | ||
| 278 | break; | ||
| 279 | |||
| 280 | case RECV_WAIT_DATA: | ||
| 281 | hci_recv_frame(info->rx_skb); | ||
| 282 | info->rx_skb = NULL; | ||
| 283 | break; | ||
| 284 | |||
| 285 | } | ||
| 286 | |||
| 287 | } | ||
| 288 | |||
| 289 | } | ||
| 290 | |||
| 291 | /* Make sure we don't stay here too long */ | ||
| 292 | if (boguscount++ > 16) | ||
| 293 | break; | ||
| 294 | |||
| 295 | } while (inb(iobase + UART_LSR) & UART_LSR_DR); | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 299 | static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) | ||
| 300 | { | ||
| 301 | btuart_info_t *info = dev_inst; | ||
| 302 | unsigned int iobase; | ||
| 303 | int boguscount = 0; | ||
| 304 | int iir, lsr; | ||
| 305 | |||
| 306 | if (!info || !info->hdev) { | ||
| 307 | BT_ERR("Call of irq %d for unknown device", irq); | ||
| 308 | return IRQ_NONE; | ||
| 309 | } | ||
| 310 | |||
| 311 | iobase = info->link.io.BasePort1; | ||
| 312 | |||
| 313 | spin_lock(&(info->lock)); | ||
| 314 | |||
| 315 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
| 316 | while (iir) { | ||
| 317 | |||
| 318 | /* Clear interrupt */ | ||
| 319 | lsr = inb(iobase + UART_LSR); | ||
| 320 | |||
| 321 | switch (iir) { | ||
| 322 | case UART_IIR_RLSI: | ||
| 323 | BT_ERR("RLSI"); | ||
| 324 | break; | ||
| 325 | case UART_IIR_RDI: | ||
| 326 | /* Receive interrupt */ | ||
| 327 | btuart_receive(info); | ||
| 328 | break; | ||
| 329 | case UART_IIR_THRI: | ||
| 330 | if (lsr & UART_LSR_THRE) { | ||
| 331 | /* Transmitter ready for data */ | ||
| 332 | btuart_write_wakeup(info); | ||
| 333 | } | ||
| 334 | break; | ||
| 335 | default: | ||
| 336 | BT_ERR("Unhandled IIR=%#x", iir); | ||
| 337 | break; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* Make sure we don't stay here too long */ | ||
| 341 | if (boguscount++ > 100) | ||
| 342 | break; | ||
| 343 | |||
| 344 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
| 345 | |||
| 346 | } | ||
| 347 | |||
| 348 | spin_unlock(&(info->lock)); | ||
| 349 | |||
| 350 | return IRQ_HANDLED; | ||
| 351 | } | ||
| 352 | |||
| 353 | |||
| 354 | static void btuart_change_speed(btuart_info_t *info, unsigned int speed) | ||
| 355 | { | ||
| 356 | unsigned long flags; | ||
| 357 | unsigned int iobase; | ||
| 358 | int fcr; /* FIFO control reg */ | ||
| 359 | int lcr; /* Line control reg */ | ||
| 360 | int divisor; | ||
| 361 | |||
| 362 | if (!info) { | ||
| 363 | BT_ERR("Unknown device"); | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 367 | iobase = info->link.io.BasePort1; | ||
| 368 | |||
| 369 | spin_lock_irqsave(&(info->lock), flags); | ||
| 370 | |||
| 371 | /* Turn off interrupts */ | ||
| 372 | outb(0, iobase + UART_IER); | ||
| 373 | |||
| 374 | divisor = SPEED_MAX / speed; | ||
| 375 | |||
| 376 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; | ||
| 377 | |||
| 378 | /* | ||
| 379 | * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and | ||
| 380 | * almost 1,7 ms at 19200 bps. At speeds above that we can just forget | ||
| 381 | * about this timeout since it will always be fast enough. | ||
| 382 | */ | ||
| 383 | |||
| 384 | if (speed < 38400) | ||
| 385 | fcr |= UART_FCR_TRIGGER_1; | ||
| 386 | else | ||
| 387 | fcr |= UART_FCR_TRIGGER_14; | ||
| 388 | |||
| 389 | /* Bluetooth cards use 8N1 */ | ||
| 390 | lcr = UART_LCR_WLEN8; | ||
| 391 | |||
| 392 | outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ | ||
| 393 | outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ | ||
| 394 | outb(divisor >> 8, iobase + UART_DLM); | ||
| 395 | outb(lcr, iobase + UART_LCR); /* Set 8N1 */ | ||
| 396 | outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ | ||
| 397 | |||
| 398 | /* Turn on interrups */ | ||
| 399 | outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); | ||
| 400 | |||
| 401 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 402 | } | ||
| 403 | |||
| 404 | |||
| 405 | |||
| 406 | /* ======================== HCI interface ======================== */ | ||
| 407 | |||
| 408 | |||
| 409 | static int btuart_hci_flush(struct hci_dev *hdev) | ||
| 410 | { | ||
| 411 | btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); | ||
| 412 | |||
| 413 | /* Drop TX queue */ | ||
| 414 | skb_queue_purge(&(info->txq)); | ||
| 415 | |||
| 416 | return 0; | ||
| 417 | } | ||
| 418 | |||
| 419 | |||
| 420 | static int btuart_hci_open(struct hci_dev *hdev) | ||
| 421 | { | ||
| 422 | set_bit(HCI_RUNNING, &(hdev->flags)); | ||
| 423 | |||
| 424 | return 0; | ||
| 425 | } | ||
| 426 | |||
| 427 | |||
| 428 | static int btuart_hci_close(struct hci_dev *hdev) | ||
| 429 | { | ||
| 430 | if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) | ||
| 431 | return 0; | ||
| 432 | |||
| 433 | btuart_hci_flush(hdev); | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | |||
| 439 | static int btuart_hci_send_frame(struct sk_buff *skb) | ||
| 440 | { | ||
| 441 | btuart_info_t *info; | ||
| 442 | struct hci_dev *hdev = (struct hci_dev *)(skb->dev); | ||
| 443 | |||
| 444 | if (!hdev) { | ||
| 445 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
| 446 | return -ENODEV; | ||
| 447 | } | ||
| 448 | |||
| 449 | info = (btuart_info_t *)(hdev->driver_data); | ||
| 450 | |||
| 451 | switch (skb->pkt_type) { | ||
| 452 | case HCI_COMMAND_PKT: | ||
| 453 | hdev->stat.cmd_tx++; | ||
| 454 | break; | ||
| 455 | case HCI_ACLDATA_PKT: | ||
| 456 | hdev->stat.acl_tx++; | ||
| 457 | break; | ||
| 458 | case HCI_SCODATA_PKT: | ||
| 459 | hdev->stat.sco_tx++; | ||
| 460 | break; | ||
| 461 | }; | ||
| 462 | |||
| 463 | /* Prepend skb with frame type */ | ||
| 464 | memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); | ||
| 465 | skb_queue_tail(&(info->txq), skb); | ||
| 466 | |||
| 467 | btuart_write_wakeup(info); | ||
| 468 | |||
| 469 | return 0; | ||
| 470 | } | ||
| 471 | |||
| 472 | |||
| 473 | static void btuart_hci_destruct(struct hci_dev *hdev) | ||
| 474 | { | ||
| 475 | } | ||
| 476 | |||
| 477 | |||
| 478 | static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
| 479 | { | ||
| 480 | return -ENOIOCTLCMD; | ||
| 481 | } | ||
| 482 | |||
| 483 | |||
| 484 | |||
| 485 | /* ======================== Card services HCI interaction ======================== */ | ||
| 486 | |||
| 487 | |||
| 488 | static int btuart_open(btuart_info_t *info) | ||
| 489 | { | ||
| 490 | unsigned long flags; | ||
| 491 | unsigned int iobase = info->link.io.BasePort1; | ||
| 492 | struct hci_dev *hdev; | ||
| 493 | |||
| 494 | spin_lock_init(&(info->lock)); | ||
| 495 | |||
| 496 | skb_queue_head_init(&(info->txq)); | ||
| 497 | |||
| 498 | info->rx_state = RECV_WAIT_PACKET_TYPE; | ||
| 499 | info->rx_count = 0; | ||
| 500 | info->rx_skb = NULL; | ||
| 501 | |||
| 502 | /* Initialize HCI device */ | ||
| 503 | hdev = hci_alloc_dev(); | ||
| 504 | if (!hdev) { | ||
| 505 | BT_ERR("Can't allocate HCI device"); | ||
| 506 | return -ENOMEM; | ||
| 507 | } | ||
| 508 | |||
| 509 | info->hdev = hdev; | ||
| 510 | |||
| 511 | hdev->type = HCI_PCCARD; | ||
| 512 | hdev->driver_data = info; | ||
| 513 | |||
| 514 | hdev->open = btuart_hci_open; | ||
| 515 | hdev->close = btuart_hci_close; | ||
| 516 | hdev->flush = btuart_hci_flush; | ||
| 517 | hdev->send = btuart_hci_send_frame; | ||
| 518 | hdev->destruct = btuart_hci_destruct; | ||
| 519 | hdev->ioctl = btuart_hci_ioctl; | ||
| 520 | |||
| 521 | hdev->owner = THIS_MODULE; | ||
| 522 | |||
| 523 | spin_lock_irqsave(&(info->lock), flags); | ||
| 524 | |||
| 525 | /* Reset UART */ | ||
| 526 | outb(0, iobase + UART_MCR); | ||
| 527 | |||
| 528 | /* Turn off interrupts */ | ||
| 529 | outb(0, iobase + UART_IER); | ||
| 530 | |||
| 531 | /* Initialize UART */ | ||
| 532 | outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ | ||
| 533 | outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); | ||
| 534 | |||
| 535 | /* Turn on interrupts */ | ||
| 536 | // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); | ||
| 537 | |||
| 538 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 539 | |||
| 540 | btuart_change_speed(info, DEFAULT_BAUD_RATE); | ||
| 541 | |||
| 542 | /* Timeout before it is safe to send the first HCI packet */ | ||
| 543 | msleep(1000); | ||
| 544 | |||
| 545 | /* Register HCI device */ | ||
| 546 | if (hci_register_dev(hdev) < 0) { | ||
| 547 | BT_ERR("Can't register HCI device"); | ||
| 548 | info->hdev = NULL; | ||
| 549 | hci_free_dev(hdev); | ||
| 550 | return -ENODEV; | ||
| 551 | } | ||
| 552 | |||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | |||
| 557 | static int btuart_close(btuart_info_t *info) | ||
| 558 | { | ||
| 559 | unsigned long flags; | ||
| 560 | unsigned int iobase = info->link.io.BasePort1; | ||
| 561 | struct hci_dev *hdev = info->hdev; | ||
| 562 | |||
| 563 | if (!hdev) | ||
| 564 | return -ENODEV; | ||
| 565 | |||
| 566 | btuart_hci_close(hdev); | ||
| 567 | |||
| 568 | spin_lock_irqsave(&(info->lock), flags); | ||
| 569 | |||
| 570 | /* Reset UART */ | ||
| 571 | outb(0, iobase + UART_MCR); | ||
| 572 | |||
| 573 | /* Turn off interrupts */ | ||
| 574 | outb(0, iobase + UART_IER); | ||
| 575 | |||
| 576 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 577 | |||
| 578 | if (hci_unregister_dev(hdev) < 0) | ||
| 579 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 580 | |||
| 581 | hci_free_dev(hdev); | ||
| 582 | |||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | static dev_link_t *btuart_attach(void) | ||
| 587 | { | ||
| 588 | btuart_info_t *info; | ||
| 589 | client_reg_t client_reg; | ||
| 590 | dev_link_t *link; | ||
| 591 | int ret; | ||
| 592 | |||
| 593 | /* Create new info device */ | ||
| 594 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
| 595 | if (!info) | ||
| 596 | return NULL; | ||
| 597 | memset(info, 0, sizeof(*info)); | ||
| 598 | |||
| 599 | link = &info->link; | ||
| 600 | link->priv = info; | ||
| 601 | |||
| 602 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
| 603 | link->io.NumPorts1 = 8; | ||
| 604 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
| 605 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
| 606 | |||
| 607 | link->irq.Handler = btuart_interrupt; | ||
| 608 | link->irq.Instance = info; | ||
| 609 | |||
| 610 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
| 611 | link->conf.Vcc = 50; | ||
| 612 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
| 613 | |||
| 614 | /* Register with Card Services */ | ||
| 615 | link->next = dev_list; | ||
| 616 | dev_list = link; | ||
| 617 | client_reg.dev_info = &dev_info; | ||
| 618 | client_reg.EventMask = | ||
| 619 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
| 620 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
| 621 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
| 622 | client_reg.event_handler = &btuart_event; | ||
| 623 | client_reg.Version = 0x0210; | ||
| 624 | client_reg.event_callback_args.client_data = link; | ||
| 625 | |||
| 626 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
| 627 | if (ret != CS_SUCCESS) { | ||
| 628 | cs_error(link->handle, RegisterClient, ret); | ||
| 629 | btuart_detach(link); | ||
| 630 | return NULL; | ||
| 631 | } | ||
| 632 | |||
| 633 | return link; | ||
| 634 | } | ||
| 635 | |||
| 636 | |||
| 637 | static void btuart_detach(dev_link_t *link) | ||
| 638 | { | ||
| 639 | btuart_info_t *info = link->priv; | ||
| 640 | dev_link_t **linkp; | ||
| 641 | int ret; | ||
| 642 | |||
| 643 | /* Locate device structure */ | ||
| 644 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
| 645 | if (*linkp == link) | ||
| 646 | break; | ||
| 647 | |||
| 648 | if (*linkp == NULL) | ||
| 649 | return; | ||
| 650 | |||
| 651 | if (link->state & DEV_CONFIG) | ||
| 652 | btuart_release(link); | ||
| 653 | |||
| 654 | if (link->handle) { | ||
| 655 | ret = pcmcia_deregister_client(link->handle); | ||
| 656 | if (ret != CS_SUCCESS) | ||
| 657 | cs_error(link->handle, DeregisterClient, ret); | ||
| 658 | } | ||
| 659 | |||
| 660 | /* Unlink device structure, free bits */ | ||
| 661 | *linkp = link->next; | ||
| 662 | |||
| 663 | kfree(info); | ||
| 664 | } | ||
| 665 | |||
| 666 | static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 667 | { | ||
| 668 | int i; | ||
| 669 | |||
| 670 | i = pcmcia_get_tuple_data(handle, tuple); | ||
| 671 | if (i != CS_SUCCESS) | ||
| 672 | return i; | ||
| 673 | |||
| 674 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
| 675 | } | ||
| 676 | |||
| 677 | static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 678 | { | ||
| 679 | if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) | ||
| 680 | return CS_NO_MORE_ITEMS; | ||
| 681 | return get_tuple(handle, tuple, parse); | ||
| 682 | } | ||
| 683 | |||
| 684 | static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 685 | { | ||
| 686 | if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) | ||
| 687 | return CS_NO_MORE_ITEMS; | ||
| 688 | return get_tuple(handle, tuple, parse); | ||
| 689 | } | ||
| 690 | |||
| 691 | static void btuart_config(dev_link_t *link) | ||
| 692 | { | ||
| 693 | static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; | ||
| 694 | client_handle_t handle = link->handle; | ||
| 695 | btuart_info_t *info = link->priv; | ||
| 696 | tuple_t tuple; | ||
| 697 | u_short buf[256]; | ||
| 698 | cisparse_t parse; | ||
| 699 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
| 700 | config_info_t config; | ||
| 701 | int i, j, try, last_ret, last_fn; | ||
| 702 | |||
| 703 | tuple.TupleData = (cisdata_t *)buf; | ||
| 704 | tuple.TupleOffset = 0; | ||
| 705 | tuple.TupleDataMax = 255; | ||
| 706 | tuple.Attributes = 0; | ||
| 707 | |||
| 708 | /* Get configuration register information */ | ||
| 709 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
| 710 | last_ret = first_tuple(handle, &tuple, &parse); | ||
| 711 | if (last_ret != CS_SUCCESS) { | ||
| 712 | last_fn = ParseTuple; | ||
| 713 | goto cs_failed; | ||
| 714 | } | ||
| 715 | link->conf.ConfigBase = parse.config.base; | ||
| 716 | link->conf.Present = parse.config.rmask[0]; | ||
| 717 | |||
| 718 | /* Configure card */ | ||
| 719 | link->state |= DEV_CONFIG; | ||
| 720 | i = pcmcia_get_configuration_info(handle, &config); | ||
| 721 | link->conf.Vcc = config.Vcc; | ||
| 722 | |||
| 723 | /* First pass: look for a config entry that looks normal. */ | ||
| 724 | tuple.TupleData = (cisdata_t *) buf; | ||
| 725 | tuple.TupleOffset = 0; | ||
| 726 | tuple.TupleDataMax = 255; | ||
| 727 | tuple.Attributes = 0; | ||
| 728 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
| 729 | /* Two tries: without IO aliases, then with aliases */ | ||
| 730 | for (try = 0; try < 2; try++) { | ||
| 731 | i = first_tuple(handle, &tuple, &parse); | ||
| 732 | while (i != CS_NO_MORE_ITEMS) { | ||
| 733 | if (i != CS_SUCCESS) | ||
| 734 | goto next_entry; | ||
| 735 | if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) | ||
| 736 | link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; | ||
| 737 | if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { | ||
| 738 | link->conf.ConfigIndex = cf->index; | ||
| 739 | link->io.BasePort1 = cf->io.win[0].base; | ||
| 740 | link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; | ||
| 741 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 742 | if (i == CS_SUCCESS) | ||
| 743 | goto found_port; | ||
| 744 | } | ||
| 745 | next_entry: | ||
| 746 | i = next_tuple(handle, &tuple, &parse); | ||
| 747 | } | ||
| 748 | } | ||
| 749 | |||
| 750 | /* Second pass: try to find an entry that isn't picky about | ||
| 751 | its base address, then try to grab any standard serial port | ||
| 752 | address, and finally try to get any free port. */ | ||
| 753 | i = first_tuple(handle, &tuple, &parse); | ||
| 754 | while (i != CS_NO_MORE_ITEMS) { | ||
| 755 | if ((i == CS_SUCCESS) && (cf->io.nwin > 0) | ||
| 756 | && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { | ||
| 757 | link->conf.ConfigIndex = cf->index; | ||
| 758 | for (j = 0; j < 5; j++) { | ||
| 759 | link->io.BasePort1 = base[j]; | ||
| 760 | link->io.IOAddrLines = base[j] ? 16 : 3; | ||
| 761 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 762 | if (i == CS_SUCCESS) | ||
| 763 | goto found_port; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | i = next_tuple(handle, &tuple, &parse); | ||
| 767 | } | ||
| 768 | |||
| 769 | found_port: | ||
| 770 | if (i != CS_SUCCESS) { | ||
| 771 | BT_ERR("No usable port range found"); | ||
| 772 | cs_error(link->handle, RequestIO, i); | ||
| 773 | goto failed; | ||
| 774 | } | ||
| 775 | |||
| 776 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
| 777 | if (i != CS_SUCCESS) { | ||
| 778 | cs_error(link->handle, RequestIRQ, i); | ||
| 779 | link->irq.AssignedIRQ = 0; | ||
| 780 | } | ||
| 781 | |||
| 782 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
| 783 | if (i != CS_SUCCESS) { | ||
| 784 | cs_error(link->handle, RequestConfiguration, i); | ||
| 785 | goto failed; | ||
| 786 | } | ||
| 787 | |||
| 788 | if (btuart_open(info) != 0) | ||
| 789 | goto failed; | ||
| 790 | |||
| 791 | strcpy(info->node.dev_name, info->hdev->name); | ||
| 792 | link->dev = &info->node; | ||
| 793 | link->state &= ~DEV_CONFIG_PENDING; | ||
| 794 | |||
| 795 | return; | ||
| 796 | |||
| 797 | cs_failed: | ||
| 798 | cs_error(link->handle, last_fn, last_ret); | ||
| 799 | |||
| 800 | failed: | ||
| 801 | btuart_release(link); | ||
| 802 | } | ||
| 803 | |||
| 804 | |||
| 805 | static void btuart_release(dev_link_t *link) | ||
| 806 | { | ||
| 807 | btuart_info_t *info = link->priv; | ||
| 808 | |||
| 809 | if (link->state & DEV_PRESENT) | ||
| 810 | btuart_close(info); | ||
| 811 | |||
| 812 | link->dev = NULL; | ||
| 813 | |||
| 814 | pcmcia_release_configuration(link->handle); | ||
| 815 | pcmcia_release_io(link->handle, &link->io); | ||
| 816 | pcmcia_release_irq(link->handle, &link->irq); | ||
| 817 | |||
| 818 | link->state &= ~DEV_CONFIG; | ||
| 819 | } | ||
| 820 | |||
| 821 | |||
| 822 | static int btuart_event(event_t event, int priority, event_callback_args_t *args) | ||
| 823 | { | ||
| 824 | dev_link_t *link = args->client_data; | ||
| 825 | btuart_info_t *info = link->priv; | ||
| 826 | |||
| 827 | switch (event) { | ||
| 828 | case CS_EVENT_CARD_REMOVAL: | ||
| 829 | link->state &= ~DEV_PRESENT; | ||
| 830 | if (link->state & DEV_CONFIG) { | ||
| 831 | btuart_close(info); | ||
| 832 | btuart_release(link); | ||
| 833 | } | ||
| 834 | break; | ||
| 835 | case CS_EVENT_CARD_INSERTION: | ||
| 836 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
| 837 | btuart_config(link); | ||
| 838 | break; | ||
| 839 | case CS_EVENT_PM_SUSPEND: | ||
| 840 | link->state |= DEV_SUSPEND; | ||
| 841 | /* Fall through... */ | ||
| 842 | case CS_EVENT_RESET_PHYSICAL: | ||
| 843 | if (link->state & DEV_CONFIG) | ||
| 844 | pcmcia_release_configuration(link->handle); | ||
| 845 | break; | ||
| 846 | case CS_EVENT_PM_RESUME: | ||
| 847 | link->state &= ~DEV_SUSPEND; | ||
| 848 | /* Fall through... */ | ||
| 849 | case CS_EVENT_CARD_RESET: | ||
| 850 | if (DEV_OK(link)) | ||
| 851 | pcmcia_request_configuration(link->handle, &link->conf); | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | |||
| 855 | return 0; | ||
| 856 | } | ||
| 857 | |||
| 858 | static struct pcmcia_driver btuart_driver = { | ||
| 859 | .owner = THIS_MODULE, | ||
| 860 | .drv = { | ||
| 861 | .name = "btuart_cs", | ||
| 862 | }, | ||
| 863 | .attach = btuart_attach, | ||
| 864 | .detach = btuart_detach, | ||
| 865 | }; | ||
| 866 | |||
| 867 | static int __init init_btuart_cs(void) | ||
| 868 | { | ||
| 869 | return pcmcia_register_driver(&btuart_driver); | ||
| 870 | } | ||
| 871 | |||
| 872 | |||
| 873 | static void __exit exit_btuart_cs(void) | ||
| 874 | { | ||
| 875 | pcmcia_unregister_driver(&btuart_driver); | ||
| 876 | BUG_ON(dev_list != NULL); | ||
| 877 | } | ||
| 878 | |||
| 879 | module_init(init_btuart_cs); | ||
| 880 | module_exit(exit_btuart_cs); | ||
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c new file mode 100644 index 000000000000..fe954e5d9a1d --- /dev/null +++ b/drivers/bluetooth/dtl1_cs.c | |||
| @@ -0,0 +1,832 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * A driver for Nokia Connectivity Card DTL-1 devices | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> | ||
| 6 | * | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation; | ||
| 11 | * | ||
| 12 | * Software distributed under the License is distributed on an "AS | ||
| 13 | * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
| 14 | * implied. See the License for the specific language governing | ||
| 15 | * rights and limitations under the License. | ||
| 16 | * | ||
| 17 | * The initial developer of the original code is David A. Hinds | ||
| 18 | * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | ||
| 19 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/config.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/types.h> | ||
| 30 | #include <linux/sched.h> | ||
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/errno.h> | ||
| 33 | #include <linux/ptrace.h> | ||
| 34 | #include <linux/ioport.h> | ||
| 35 | #include <linux/spinlock.h> | ||
| 36 | #include <linux/moduleparam.h> | ||
| 37 | |||
| 38 | #include <linux/skbuff.h> | ||
| 39 | #include <linux/string.h> | ||
| 40 | #include <linux/serial.h> | ||
| 41 | #include <linux/serial_reg.h> | ||
| 42 | #include <linux/bitops.h> | ||
| 43 | #include <asm/system.h> | ||
| 44 | #include <asm/io.h> | ||
| 45 | |||
| 46 | #include <pcmcia/version.h> | ||
| 47 | #include <pcmcia/cs_types.h> | ||
| 48 | #include <pcmcia/cs.h> | ||
| 49 | #include <pcmcia/cistpl.h> | ||
| 50 | #include <pcmcia/ciscode.h> | ||
| 51 | #include <pcmcia/ds.h> | ||
| 52 | #include <pcmcia/cisreg.h> | ||
| 53 | |||
| 54 | #include <net/bluetooth/bluetooth.h> | ||
| 55 | #include <net/bluetooth/hci_core.h> | ||
| 56 | |||
| 57 | |||
| 58 | |||
| 59 | /* ======================== Module parameters ======================== */ | ||
| 60 | |||
| 61 | |||
| 62 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); | ||
| 63 | MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1"); | ||
| 64 | MODULE_LICENSE("GPL"); | ||
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | /* ======================== Local structures ======================== */ | ||
| 69 | |||
| 70 | |||
| 71 | typedef struct dtl1_info_t { | ||
| 72 | dev_link_t link; | ||
| 73 | dev_node_t node; | ||
| 74 | |||
| 75 | struct hci_dev *hdev; | ||
| 76 | |||
| 77 | spinlock_t lock; /* For serializing operations */ | ||
| 78 | |||
| 79 | unsigned long flowmask; /* HCI flow mask */ | ||
| 80 | int ri_latch; | ||
| 81 | |||
| 82 | struct sk_buff_head txq; | ||
| 83 | unsigned long tx_state; | ||
| 84 | |||
| 85 | unsigned long rx_state; | ||
| 86 | unsigned long rx_count; | ||
| 87 | struct sk_buff *rx_skb; | ||
| 88 | } dtl1_info_t; | ||
| 89 | |||
| 90 | |||
| 91 | static void dtl1_config(dev_link_t *link); | ||
| 92 | static void dtl1_release(dev_link_t *link); | ||
| 93 | static int dtl1_event(event_t event, int priority, event_callback_args_t *args); | ||
| 94 | |||
| 95 | static dev_info_t dev_info = "dtl1_cs"; | ||
| 96 | |||
| 97 | static dev_link_t *dtl1_attach(void); | ||
| 98 | static void dtl1_detach(dev_link_t *); | ||
| 99 | |||
| 100 | static dev_link_t *dev_list = NULL; | ||
| 101 | |||
| 102 | |||
| 103 | /* Transmit states */ | ||
| 104 | #define XMIT_SENDING 1 | ||
| 105 | #define XMIT_WAKEUP 2 | ||
| 106 | #define XMIT_WAITING 8 | ||
| 107 | |||
| 108 | /* Receiver States */ | ||
| 109 | #define RECV_WAIT_NSH 0 | ||
| 110 | #define RECV_WAIT_DATA 1 | ||
| 111 | |||
| 112 | |||
| 113 | typedef struct { | ||
| 114 | u8 type; | ||
| 115 | u8 zero; | ||
| 116 | u16 len; | ||
| 117 | } __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ | ||
| 118 | |||
| 119 | #define NSHL 4 /* Nokia Specific Header Length */ | ||
| 120 | |||
| 121 | |||
| 122 | |||
| 123 | /* ======================== Interrupt handling ======================== */ | ||
| 124 | |||
| 125 | |||
| 126 | static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) | ||
| 127 | { | ||
| 128 | int actual = 0; | ||
| 129 | |||
| 130 | /* Tx FIFO should be empty */ | ||
| 131 | if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) | ||
| 132 | return 0; | ||
| 133 | |||
| 134 | /* Fill FIFO with current frame */ | ||
| 135 | while ((fifo_size-- > 0) && (actual < len)) { | ||
| 136 | /* Transmit next byte */ | ||
| 137 | outb(buf[actual], iobase + UART_TX); | ||
| 138 | actual++; | ||
| 139 | } | ||
| 140 | |||
| 141 | return actual; | ||
| 142 | } | ||
| 143 | |||
| 144 | |||
| 145 | static void dtl1_write_wakeup(dtl1_info_t *info) | ||
| 146 | { | ||
| 147 | if (!info) { | ||
| 148 | BT_ERR("Unknown device"); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (test_bit(XMIT_WAITING, &(info->tx_state))) { | ||
| 153 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { | ||
| 158 | set_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | |||
| 162 | do { | ||
| 163 | register unsigned int iobase = info->link.io.BasePort1; | ||
| 164 | register struct sk_buff *skb; | ||
| 165 | register int len; | ||
| 166 | |||
| 167 | clear_bit(XMIT_WAKEUP, &(info->tx_state)); | ||
| 168 | |||
| 169 | if (!(info->link.state & DEV_PRESENT)) | ||
| 170 | return; | ||
| 171 | |||
| 172 | if (!(skb = skb_dequeue(&(info->txq)))) | ||
| 173 | break; | ||
| 174 | |||
| 175 | /* Send frame */ | ||
| 176 | len = dtl1_write(iobase, 32, skb->data, skb->len); | ||
| 177 | |||
| 178 | if (len == skb->len) { | ||
| 179 | set_bit(XMIT_WAITING, &(info->tx_state)); | ||
| 180 | kfree_skb(skb); | ||
| 181 | } else { | ||
| 182 | skb_pull(skb, len); | ||
| 183 | skb_queue_head(&(info->txq), skb); | ||
| 184 | } | ||
| 185 | |||
| 186 | info->hdev->stat.byte_tx += len; | ||
| 187 | |||
| 188 | } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); | ||
| 189 | |||
| 190 | clear_bit(XMIT_SENDING, &(info->tx_state)); | ||
| 191 | } | ||
| 192 | |||
| 193 | |||
| 194 | static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) | ||
| 195 | { | ||
| 196 | u8 flowmask = *(u8 *)skb->data; | ||
| 197 | int i; | ||
| 198 | |||
| 199 | printk(KERN_INFO "Bluetooth: Nokia control data ="); | ||
| 200 | for (i = 0; i < skb->len; i++) { | ||
| 201 | printk(" %02x", skb->data[i]); | ||
| 202 | } | ||
| 203 | printk("\n"); | ||
| 204 | |||
| 205 | /* transition to active state */ | ||
| 206 | if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { | ||
| 207 | clear_bit(XMIT_WAITING, &(info->tx_state)); | ||
| 208 | dtl1_write_wakeup(info); | ||
| 209 | } | ||
| 210 | |||
| 211 | info->flowmask = flowmask; | ||
| 212 | |||
| 213 | kfree_skb(skb); | ||
| 214 | } | ||
| 215 | |||
| 216 | |||
| 217 | static void dtl1_receive(dtl1_info_t *info) | ||
| 218 | { | ||
| 219 | unsigned int iobase; | ||
| 220 | nsh_t *nsh; | ||
| 221 | int boguscount = 0; | ||
| 222 | |||
| 223 | if (!info) { | ||
| 224 | BT_ERR("Unknown device"); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | iobase = info->link.io.BasePort1; | ||
| 229 | |||
| 230 | do { | ||
| 231 | info->hdev->stat.byte_rx++; | ||
| 232 | |||
| 233 | /* Allocate packet */ | ||
| 234 | if (info->rx_skb == NULL) | ||
| 235 | if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { | ||
| 236 | BT_ERR("Can't allocate mem for new packet"); | ||
| 237 | info->rx_state = RECV_WAIT_NSH; | ||
| 238 | info->rx_count = NSHL; | ||
| 239 | return; | ||
| 240 | } | ||
| 241 | |||
| 242 | *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); | ||
| 243 | nsh = (nsh_t *)info->rx_skb->data; | ||
| 244 | |||
| 245 | info->rx_count--; | ||
| 246 | |||
| 247 | if (info->rx_count == 0) { | ||
| 248 | |||
| 249 | switch (info->rx_state) { | ||
| 250 | case RECV_WAIT_NSH: | ||
| 251 | info->rx_state = RECV_WAIT_DATA; | ||
| 252 | info->rx_count = nsh->len + (nsh->len & 0x0001); | ||
| 253 | break; | ||
| 254 | case RECV_WAIT_DATA: | ||
| 255 | info->rx_skb->pkt_type = nsh->type; | ||
| 256 | |||
| 257 | /* remove PAD byte if it exists */ | ||
| 258 | if (nsh->len & 0x0001) { | ||
| 259 | info->rx_skb->tail--; | ||
| 260 | info->rx_skb->len--; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* remove NSH */ | ||
| 264 | skb_pull(info->rx_skb, NSHL); | ||
| 265 | |||
| 266 | switch (info->rx_skb->pkt_type) { | ||
| 267 | case 0x80: | ||
| 268 | /* control data for the Nokia Card */ | ||
| 269 | dtl1_control(info, info->rx_skb); | ||
| 270 | break; | ||
| 271 | case 0x82: | ||
| 272 | case 0x83: | ||
| 273 | case 0x84: | ||
| 274 | /* send frame to the HCI layer */ | ||
| 275 | info->rx_skb->dev = (void *) info->hdev; | ||
| 276 | info->rx_skb->pkt_type &= 0x0f; | ||
| 277 | hci_recv_frame(info->rx_skb); | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | /* unknown packet */ | ||
| 281 | BT_ERR("Unknown HCI packet with type 0x%02x received", info->rx_skb->pkt_type); | ||
| 282 | kfree_skb(info->rx_skb); | ||
| 283 | break; | ||
| 284 | } | ||
| 285 | |||
| 286 | info->rx_state = RECV_WAIT_NSH; | ||
| 287 | info->rx_count = NSHL; | ||
| 288 | info->rx_skb = NULL; | ||
| 289 | break; | ||
| 290 | } | ||
| 291 | |||
| 292 | } | ||
| 293 | |||
| 294 | /* Make sure we don't stay here too long */ | ||
| 295 | if (boguscount++ > 32) | ||
| 296 | break; | ||
| 297 | |||
| 298 | } while (inb(iobase + UART_LSR) & UART_LSR_DR); | ||
| 299 | } | ||
| 300 | |||
| 301 | |||
| 302 | static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) | ||
| 303 | { | ||
| 304 | dtl1_info_t *info = dev_inst; | ||
| 305 | unsigned int iobase; | ||
| 306 | unsigned char msr; | ||
| 307 | int boguscount = 0; | ||
| 308 | int iir, lsr; | ||
| 309 | |||
| 310 | if (!info || !info->hdev) { | ||
| 311 | BT_ERR("Call of irq %d for unknown device", irq); | ||
| 312 | return IRQ_NONE; | ||
| 313 | } | ||
| 314 | |||
| 315 | iobase = info->link.io.BasePort1; | ||
| 316 | |||
| 317 | spin_lock(&(info->lock)); | ||
| 318 | |||
| 319 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
| 320 | while (iir) { | ||
| 321 | |||
| 322 | /* Clear interrupt */ | ||
| 323 | lsr = inb(iobase + UART_LSR); | ||
| 324 | |||
| 325 | switch (iir) { | ||
| 326 | case UART_IIR_RLSI: | ||
| 327 | BT_ERR("RLSI"); | ||
| 328 | break; | ||
| 329 | case UART_IIR_RDI: | ||
| 330 | /* Receive interrupt */ | ||
| 331 | dtl1_receive(info); | ||
| 332 | break; | ||
| 333 | case UART_IIR_THRI: | ||
| 334 | if (lsr & UART_LSR_THRE) { | ||
| 335 | /* Transmitter ready for data */ | ||
| 336 | dtl1_write_wakeup(info); | ||
| 337 | } | ||
| 338 | break; | ||
| 339 | default: | ||
| 340 | BT_ERR("Unhandled IIR=%#x", iir); | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | |||
| 344 | /* Make sure we don't stay here too long */ | ||
| 345 | if (boguscount++ > 100) | ||
| 346 | break; | ||
| 347 | |||
| 348 | iir = inb(iobase + UART_IIR) & UART_IIR_ID; | ||
| 349 | |||
| 350 | } | ||
| 351 | |||
| 352 | msr = inb(iobase + UART_MSR); | ||
| 353 | |||
| 354 | if (info->ri_latch ^ (msr & UART_MSR_RI)) { | ||
| 355 | info->ri_latch = msr & UART_MSR_RI; | ||
| 356 | clear_bit(XMIT_WAITING, &(info->tx_state)); | ||
| 357 | dtl1_write_wakeup(info); | ||
| 358 | } | ||
| 359 | |||
| 360 | spin_unlock(&(info->lock)); | ||
| 361 | |||
| 362 | return IRQ_HANDLED; | ||
| 363 | } | ||
| 364 | |||
| 365 | |||
| 366 | |||
| 367 | /* ======================== HCI interface ======================== */ | ||
| 368 | |||
| 369 | |||
| 370 | static int dtl1_hci_open(struct hci_dev *hdev) | ||
| 371 | { | ||
| 372 | set_bit(HCI_RUNNING, &(hdev->flags)); | ||
| 373 | |||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | static int dtl1_hci_flush(struct hci_dev *hdev) | ||
| 379 | { | ||
| 380 | dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); | ||
| 381 | |||
| 382 | /* Drop TX queue */ | ||
| 383 | skb_queue_purge(&(info->txq)); | ||
| 384 | |||
| 385 | return 0; | ||
| 386 | } | ||
| 387 | |||
| 388 | |||
| 389 | static int dtl1_hci_close(struct hci_dev *hdev) | ||
| 390 | { | ||
| 391 | if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) | ||
| 392 | return 0; | ||
| 393 | |||
| 394 | dtl1_hci_flush(hdev); | ||
| 395 | |||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | static int dtl1_hci_send_frame(struct sk_buff *skb) | ||
| 401 | { | ||
| 402 | dtl1_info_t *info; | ||
| 403 | struct hci_dev *hdev = (struct hci_dev *)(skb->dev); | ||
| 404 | struct sk_buff *s; | ||
| 405 | nsh_t nsh; | ||
| 406 | |||
| 407 | if (!hdev) { | ||
| 408 | BT_ERR("Frame for unknown HCI device (hdev=NULL)"); | ||
| 409 | return -ENODEV; | ||
| 410 | } | ||
| 411 | |||
| 412 | info = (dtl1_info_t *)(hdev->driver_data); | ||
| 413 | |||
| 414 | switch (skb->pkt_type) { | ||
| 415 | case HCI_COMMAND_PKT: | ||
| 416 | hdev->stat.cmd_tx++; | ||
| 417 | nsh.type = 0x81; | ||
| 418 | break; | ||
| 419 | case HCI_ACLDATA_PKT: | ||
| 420 | hdev->stat.acl_tx++; | ||
| 421 | nsh.type = 0x82; | ||
| 422 | break; | ||
| 423 | case HCI_SCODATA_PKT: | ||
| 424 | hdev->stat.sco_tx++; | ||
| 425 | nsh.type = 0x83; | ||
| 426 | break; | ||
| 427 | }; | ||
| 428 | |||
| 429 | nsh.zero = 0; | ||
| 430 | nsh.len = skb->len; | ||
| 431 | |||
| 432 | s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); | ||
| 433 | skb_reserve(s, NSHL); | ||
| 434 | memcpy(skb_put(s, skb->len), skb->data, skb->len); | ||
| 435 | if (skb->len & 0x0001) | ||
| 436 | *skb_put(s, 1) = 0; /* PAD */ | ||
| 437 | |||
| 438 | /* Prepend skb with Nokia frame header and queue */ | ||
| 439 | memcpy(skb_push(s, NSHL), &nsh, NSHL); | ||
| 440 | skb_queue_tail(&(info->txq), s); | ||
| 441 | |||
| 442 | dtl1_write_wakeup(info); | ||
| 443 | |||
| 444 | kfree_skb(skb); | ||
| 445 | |||
| 446 | return 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | |||
| 450 | static void dtl1_hci_destruct(struct hci_dev *hdev) | ||
| 451 | { | ||
| 452 | } | ||
| 453 | |||
| 454 | |||
| 455 | static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) | ||
| 456 | { | ||
| 457 | return -ENOIOCTLCMD; | ||
| 458 | } | ||
| 459 | |||
| 460 | |||
| 461 | |||
| 462 | /* ======================== Card services HCI interaction ======================== */ | ||
| 463 | |||
| 464 | |||
| 465 | static int dtl1_open(dtl1_info_t *info) | ||
| 466 | { | ||
| 467 | unsigned long flags; | ||
| 468 | unsigned int iobase = info->link.io.BasePort1; | ||
| 469 | struct hci_dev *hdev; | ||
| 470 | |||
| 471 | spin_lock_init(&(info->lock)); | ||
| 472 | |||
| 473 | skb_queue_head_init(&(info->txq)); | ||
| 474 | |||
| 475 | info->rx_state = RECV_WAIT_NSH; | ||
| 476 | info->rx_count = NSHL; | ||
| 477 | info->rx_skb = NULL; | ||
| 478 | |||
| 479 | set_bit(XMIT_WAITING, &(info->tx_state)); | ||
| 480 | |||
| 481 | /* Initialize HCI device */ | ||
| 482 | hdev = hci_alloc_dev(); | ||
| 483 | if (!hdev) { | ||
| 484 | BT_ERR("Can't allocate HCI device"); | ||
| 485 | return -ENOMEM; | ||
| 486 | } | ||
| 487 | |||
| 488 | info->hdev = hdev; | ||
| 489 | |||
| 490 | hdev->type = HCI_PCCARD; | ||
| 491 | hdev->driver_data = info; | ||
| 492 | |||
| 493 | hdev->open = dtl1_hci_open; | ||
| 494 | hdev->close = dtl1_hci_close; | ||
| 495 | hdev->flush = dtl1_hci_flush; | ||
| 496 | hdev->send = dtl1_hci_send_frame; | ||
| 497 | hdev->destruct = dtl1_hci_destruct; | ||
| 498 | hdev->ioctl = dtl1_hci_ioctl; | ||
| 499 | |||
| 500 | hdev->owner = THIS_MODULE; | ||
| 501 | |||
| 502 | spin_lock_irqsave(&(info->lock), flags); | ||
| 503 | |||
| 504 | /* Reset UART */ | ||
| 505 | outb(0, iobase + UART_MCR); | ||
| 506 | |||
| 507 | /* Turn off interrupts */ | ||
| 508 | outb(0, iobase + UART_IER); | ||
| 509 | |||
| 510 | /* Initialize UART */ | ||
| 511 | outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ | ||
| 512 | outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); | ||
| 513 | |||
| 514 | info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; | ||
| 515 | |||
| 516 | /* Turn on interrupts */ | ||
| 517 | outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); | ||
| 518 | |||
| 519 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 520 | |||
| 521 | /* Timeout before it is safe to send the first HCI packet */ | ||
| 522 | msleep(2000); | ||
| 523 | |||
| 524 | /* Register HCI device */ | ||
| 525 | if (hci_register_dev(hdev) < 0) { | ||
| 526 | BT_ERR("Can't register HCI device"); | ||
| 527 | info->hdev = NULL; | ||
| 528 | hci_free_dev(hdev); | ||
| 529 | return -ENODEV; | ||
| 530 | } | ||
| 531 | |||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | |||
| 536 | static int dtl1_close(dtl1_info_t *info) | ||
| 537 | { | ||
| 538 | unsigned long flags; | ||
| 539 | unsigned int iobase = info->link.io.BasePort1; | ||
| 540 | struct hci_dev *hdev = info->hdev; | ||
| 541 | |||
| 542 | if (!hdev) | ||
| 543 | return -ENODEV; | ||
| 544 | |||
| 545 | dtl1_hci_close(hdev); | ||
| 546 | |||
| 547 | spin_lock_irqsave(&(info->lock), flags); | ||
| 548 | |||
| 549 | /* Reset UART */ | ||
| 550 | outb(0, iobase + UART_MCR); | ||
| 551 | |||
| 552 | /* Turn off interrupts */ | ||
| 553 | outb(0, iobase + UART_IER); | ||
| 554 | |||
| 555 | spin_unlock_irqrestore(&(info->lock), flags); | ||
| 556 | |||
| 557 | if (hci_unregister_dev(hdev) < 0) | ||
| 558 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 559 | |||
| 560 | hci_free_dev(hdev); | ||
| 561 | |||
| 562 | return 0; | ||
| 563 | } | ||
| 564 | |||
| 565 | static dev_link_t *dtl1_attach(void) | ||
| 566 | { | ||
| 567 | dtl1_info_t *info; | ||
| 568 | client_reg_t client_reg; | ||
| 569 | dev_link_t *link; | ||
| 570 | int ret; | ||
| 571 | |||
| 572 | /* Create new info device */ | ||
| 573 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
| 574 | if (!info) | ||
| 575 | return NULL; | ||
| 576 | memset(info, 0, sizeof(*info)); | ||
| 577 | |||
| 578 | link = &info->link; | ||
| 579 | link->priv = info; | ||
| 580 | |||
| 581 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
| 582 | link->io.NumPorts1 = 8; | ||
| 583 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
| 584 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
| 585 | |||
| 586 | link->irq.Handler = dtl1_interrupt; | ||
| 587 | link->irq.Instance = info; | ||
| 588 | |||
| 589 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
| 590 | link->conf.Vcc = 50; | ||
| 591 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
| 592 | |||
| 593 | /* Register with Card Services */ | ||
| 594 | link->next = dev_list; | ||
| 595 | dev_list = link; | ||
| 596 | client_reg.dev_info = &dev_info; | ||
| 597 | client_reg.EventMask = | ||
| 598 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
| 599 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
| 600 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
| 601 | client_reg.event_handler = &dtl1_event; | ||
| 602 | client_reg.Version = 0x0210; | ||
| 603 | client_reg.event_callback_args.client_data = link; | ||
| 604 | |||
| 605 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
| 606 | if (ret != CS_SUCCESS) { | ||
| 607 | cs_error(link->handle, RegisterClient, ret); | ||
| 608 | dtl1_detach(link); | ||
| 609 | return NULL; | ||
| 610 | } | ||
| 611 | |||
| 612 | return link; | ||
| 613 | } | ||
| 614 | |||
| 615 | |||
| 616 | static void dtl1_detach(dev_link_t *link) | ||
| 617 | { | ||
| 618 | dtl1_info_t *info = link->priv; | ||
| 619 | dev_link_t **linkp; | ||
| 620 | int ret; | ||
| 621 | |||
| 622 | /* Locate device structure */ | ||
| 623 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
| 624 | if (*linkp == link) | ||
| 625 | break; | ||
| 626 | |||
| 627 | if (*linkp == NULL) | ||
| 628 | return; | ||
| 629 | |||
| 630 | if (link->state & DEV_CONFIG) | ||
| 631 | dtl1_release(link); | ||
| 632 | |||
| 633 | if (link->handle) { | ||
| 634 | ret = pcmcia_deregister_client(link->handle); | ||
| 635 | if (ret != CS_SUCCESS) | ||
| 636 | cs_error(link->handle, DeregisterClient, ret); | ||
| 637 | } | ||
| 638 | |||
| 639 | /* Unlink device structure, free bits */ | ||
| 640 | *linkp = link->next; | ||
| 641 | |||
| 642 | kfree(info); | ||
| 643 | } | ||
| 644 | |||
| 645 | static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 646 | { | ||
| 647 | int i; | ||
| 648 | |||
| 649 | i = pcmcia_get_tuple_data(handle, tuple); | ||
| 650 | if (i != CS_SUCCESS) | ||
| 651 | return i; | ||
| 652 | |||
| 653 | return pcmcia_parse_tuple(handle, tuple, parse); | ||
| 654 | } | ||
| 655 | |||
| 656 | static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 657 | { | ||
| 658 | if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) | ||
| 659 | return CS_NO_MORE_ITEMS; | ||
| 660 | return get_tuple(handle, tuple, parse); | ||
| 661 | } | ||
| 662 | |||
| 663 | static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) | ||
| 664 | { | ||
| 665 | if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) | ||
| 666 | return CS_NO_MORE_ITEMS; | ||
| 667 | return get_tuple(handle, tuple, parse); | ||
| 668 | } | ||
| 669 | |||
| 670 | static void dtl1_config(dev_link_t *link) | ||
| 671 | { | ||
| 672 | client_handle_t handle = link->handle; | ||
| 673 | dtl1_info_t *info = link->priv; | ||
| 674 | tuple_t tuple; | ||
| 675 | u_short buf[256]; | ||
| 676 | cisparse_t parse; | ||
| 677 | cistpl_cftable_entry_t *cf = &parse.cftable_entry; | ||
| 678 | config_info_t config; | ||
| 679 | int i, last_ret, last_fn; | ||
| 680 | |||
| 681 | tuple.TupleData = (cisdata_t *)buf; | ||
| 682 | tuple.TupleOffset = 0; | ||
| 683 | tuple.TupleDataMax = 255; | ||
| 684 | tuple.Attributes = 0; | ||
| 685 | |||
| 686 | /* Get configuration register information */ | ||
| 687 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
| 688 | last_ret = first_tuple(handle, &tuple, &parse); | ||
| 689 | if (last_ret != CS_SUCCESS) { | ||
| 690 | last_fn = ParseTuple; | ||
| 691 | goto cs_failed; | ||
| 692 | } | ||
| 693 | link->conf.ConfigBase = parse.config.base; | ||
| 694 | link->conf.Present = parse.config.rmask[0]; | ||
| 695 | |||
| 696 | /* Configure card */ | ||
| 697 | link->state |= DEV_CONFIG; | ||
| 698 | i = pcmcia_get_configuration_info(handle, &config); | ||
| 699 | link->conf.Vcc = config.Vcc; | ||
| 700 | |||
| 701 | tuple.TupleData = (cisdata_t *)buf; | ||
| 702 | tuple.TupleOffset = 0; | ||
| 703 | tuple.TupleDataMax = 255; | ||
| 704 | tuple.Attributes = 0; | ||
| 705 | tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; | ||
| 706 | |||
| 707 | /* Look for a generic full-sized window */ | ||
| 708 | link->io.NumPorts1 = 8; | ||
| 709 | i = first_tuple(handle, &tuple, &parse); | ||
| 710 | while (i != CS_NO_MORE_ITEMS) { | ||
| 711 | if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { | ||
| 712 | link->conf.ConfigIndex = cf->index; | ||
| 713 | link->io.BasePort1 = cf->io.win[0].base; | ||
| 714 | link->io.NumPorts1 = cf->io.win[0].len; /*yo */ | ||
| 715 | link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; | ||
| 716 | i = pcmcia_request_io(link->handle, &link->io); | ||
| 717 | if (i == CS_SUCCESS) | ||
| 718 | break; | ||
| 719 | } | ||
| 720 | i = next_tuple(handle, &tuple, &parse); | ||
| 721 | } | ||
| 722 | |||
| 723 | if (i != CS_SUCCESS) { | ||
| 724 | cs_error(link->handle, RequestIO, i); | ||
| 725 | goto failed; | ||
| 726 | } | ||
| 727 | |||
| 728 | i = pcmcia_request_irq(link->handle, &link->irq); | ||
| 729 | if (i != CS_SUCCESS) { | ||
| 730 | cs_error(link->handle, RequestIRQ, i); | ||
| 731 | link->irq.AssignedIRQ = 0; | ||
| 732 | } | ||
| 733 | |||
| 734 | i = pcmcia_request_configuration(link->handle, &link->conf); | ||
| 735 | if (i != CS_SUCCESS) { | ||
| 736 | cs_error(link->handle, RequestConfiguration, i); | ||
| 737 | goto failed; | ||
| 738 | } | ||
| 739 | |||
| 740 | if (dtl1_open(info) != 0) | ||
| 741 | goto failed; | ||
| 742 | |||
| 743 | strcpy(info->node.dev_name, info->hdev->name); | ||
| 744 | link->dev = &info->node; | ||
| 745 | link->state &= ~DEV_CONFIG_PENDING; | ||
| 746 | |||
| 747 | return; | ||
| 748 | |||
| 749 | cs_failed: | ||
| 750 | cs_error(link->handle, last_fn, last_ret); | ||
| 751 | |||
| 752 | failed: | ||
| 753 | dtl1_release(link); | ||
| 754 | } | ||
| 755 | |||
| 756 | |||
| 757 | static void dtl1_release(dev_link_t *link) | ||
| 758 | { | ||
| 759 | dtl1_info_t *info = link->priv; | ||
| 760 | |||
| 761 | if (link->state & DEV_PRESENT) | ||
| 762 | dtl1_close(info); | ||
| 763 | |||
| 764 | link->dev = NULL; | ||
| 765 | |||
| 766 | pcmcia_release_configuration(link->handle); | ||
| 767 | pcmcia_release_io(link->handle, &link->io); | ||
| 768 | pcmcia_release_irq(link->handle, &link->irq); | ||
| 769 | |||
| 770 | link->state &= ~DEV_CONFIG; | ||
| 771 | } | ||
| 772 | |||
| 773 | |||
| 774 | static int dtl1_event(event_t event, int priority, event_callback_args_t *args) | ||
| 775 | { | ||
| 776 | dev_link_t *link = args->client_data; | ||
| 777 | dtl1_info_t *info = link->priv; | ||
| 778 | |||
| 779 | switch (event) { | ||
| 780 | case CS_EVENT_CARD_REMOVAL: | ||
| 781 | link->state &= ~DEV_PRESENT; | ||
| 782 | if (link->state & DEV_CONFIG) { | ||
| 783 | dtl1_close(info); | ||
| 784 | dtl1_release(link); | ||
| 785 | } | ||
| 786 | break; | ||
| 787 | case CS_EVENT_CARD_INSERTION: | ||
| 788 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
| 789 | dtl1_config(link); | ||
| 790 | break; | ||
| 791 | case CS_EVENT_PM_SUSPEND: | ||
| 792 | link->state |= DEV_SUSPEND; | ||
| 793 | /* Fall through... */ | ||
| 794 | case CS_EVENT_RESET_PHYSICAL: | ||
| 795 | if (link->state & DEV_CONFIG) | ||
| 796 | pcmcia_release_configuration(link->handle); | ||
| 797 | break; | ||
| 798 | case CS_EVENT_PM_RESUME: | ||
| 799 | link->state &= ~DEV_SUSPEND; | ||
| 800 | /* Fall through... */ | ||
| 801 | case CS_EVENT_CARD_RESET: | ||
| 802 | if (DEV_OK(link)) | ||
| 803 | pcmcia_request_configuration(link->handle, &link->conf); | ||
| 804 | break; | ||
| 805 | } | ||
| 806 | |||
| 807 | return 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | static struct pcmcia_driver dtl1_driver = { | ||
| 811 | .owner = THIS_MODULE, | ||
| 812 | .drv = { | ||
| 813 | .name = "dtl1_cs", | ||
| 814 | }, | ||
| 815 | .attach = dtl1_attach, | ||
| 816 | .detach = dtl1_detach, | ||
| 817 | }; | ||
| 818 | |||
| 819 | static int __init init_dtl1_cs(void) | ||
| 820 | { | ||
| 821 | return pcmcia_register_driver(&dtl1_driver); | ||
| 822 | } | ||
| 823 | |||
| 824 | |||
| 825 | static void __exit exit_dtl1_cs(void) | ||
| 826 | { | ||
| 827 | pcmcia_unregister_driver(&dtl1_driver); | ||
| 828 | BUG_ON(dev_list != NULL); | ||
| 829 | } | ||
| 830 | |||
| 831 | module_init(init_dtl1_cs); | ||
| 832 | module_exit(exit_dtl1_cs); | ||
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c new file mode 100644 index 000000000000..c0ed213fc857 --- /dev/null +++ b/drivers/bluetooth/hci_bcsp.c | |||
| @@ -0,0 +1,749 @@ | |||
| 1 | /* | ||
| 2 | BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). | ||
| 3 | Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> | ||
| 4 | |||
| 5 | Based on | ||
| 6 | hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 7 | ABCSP by Carl Orsborn <cjo@csr.com> | ||
| 8 | |||
| 9 | This program is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License version 2 as | ||
| 11 | published by the Free Software Foundation; | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 17 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 18 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 19 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 20 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 21 | |||
| 22 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 23 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 24 | SOFTWARE IS DISCLAIMED. | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define VERSION "0.2" | ||
| 32 | |||
| 33 | #include <linux/config.h> | ||
| 34 | #include <linux/module.h> | ||
| 35 | |||
| 36 | #include <linux/kernel.h> | ||
| 37 | #include <linux/init.h> | ||
| 38 | #include <linux/sched.h> | ||
| 39 | #include <linux/types.h> | ||
| 40 | #include <linux/fcntl.h> | ||
| 41 | #include <linux/interrupt.h> | ||
| 42 | #include <linux/ptrace.h> | ||
| 43 | #include <linux/poll.h> | ||
| 44 | |||
| 45 | #include <linux/slab.h> | ||
| 46 | #include <linux/tty.h> | ||
| 47 | #include <linux/errno.h> | ||
| 48 | #include <linux/string.h> | ||
| 49 | #include <linux/signal.h> | ||
| 50 | #include <linux/ioctl.h> | ||
| 51 | #include <linux/skbuff.h> | ||
| 52 | |||
| 53 | #include <net/bluetooth/bluetooth.h> | ||
| 54 | #include <net/bluetooth/hci_core.h> | ||
| 55 | #include "hci_uart.h" | ||
| 56 | #include "hci_bcsp.h" | ||
| 57 | |||
| 58 | #ifndef CONFIG_BT_HCIUART_DEBUG | ||
| 59 | #undef BT_DBG | ||
| 60 | #define BT_DBG( A... ) | ||
| 61 | #undef BT_DMP | ||
| 62 | #define BT_DMP( A... ) | ||
| 63 | #endif | ||
| 64 | |||
| 65 | static int hciextn = 1; | ||
| 66 | |||
| 67 | /* ---- BCSP CRC calculation ---- */ | ||
| 68 | |||
| 69 | /* Table for calculating CRC for polynomial 0x1021, LSB processed first, | ||
| 70 | initial value 0xffff, bits shifted in reverse order. */ | ||
| 71 | |||
| 72 | static const u16 crc_table[] = { | ||
| 73 | 0x0000, 0x1081, 0x2102, 0x3183, | ||
| 74 | 0x4204, 0x5285, 0x6306, 0x7387, | ||
| 75 | 0x8408, 0x9489, 0xa50a, 0xb58b, | ||
| 76 | 0xc60c, 0xd68d, 0xe70e, 0xf78f | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* Initialise the crc calculator */ | ||
| 80 | #define BCSP_CRC_INIT(x) x = 0xffff | ||
| 81 | |||
| 82 | /* | ||
| 83 | Update crc with next data byte | ||
| 84 | |||
| 85 | Implementation note | ||
| 86 | The data byte is treated as two nibbles. The crc is generated | ||
| 87 | in reverse, i.e., bits are fed into the register from the top. | ||
| 88 | */ | ||
| 89 | static void bcsp_crc_update(u16 *crc, u8 d) | ||
| 90 | { | ||
| 91 | u16 reg = *crc; | ||
| 92 | |||
| 93 | reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; | ||
| 94 | reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; | ||
| 95 | |||
| 96 | *crc = reg; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | Get reverse of generated crc | ||
| 101 | |||
| 102 | Implementation note | ||
| 103 | The crc generator (bcsp_crc_init() and bcsp_crc_update()) | ||
| 104 | creates a reversed crc, so it needs to be swapped back before | ||
| 105 | being passed on. | ||
| 106 | */ | ||
| 107 | static u16 bcsp_crc_reverse(u16 crc) | ||
| 108 | { | ||
| 109 | u16 b, rev; | ||
| 110 | |||
| 111 | for (b = 0, rev = 0; b < 16; b++) { | ||
| 112 | rev = rev << 1; | ||
| 113 | rev |= (crc & 1); | ||
| 114 | crc = crc >> 1; | ||
| 115 | } | ||
| 116 | return (rev); | ||
| 117 | } | ||
| 118 | |||
| 119 | /* ---- BCSP core ---- */ | ||
| 120 | |||
| 121 | static void bcsp_slip_msgdelim(struct sk_buff *skb) | ||
| 122 | { | ||
| 123 | const char pkt_delim = 0xc0; | ||
| 124 | memcpy(skb_put(skb, 1), &pkt_delim, 1); | ||
| 125 | } | ||
| 126 | |||
| 127 | static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) | ||
| 128 | { | ||
| 129 | const char esc_c0[2] = { 0xdb, 0xdc }; | ||
| 130 | const char esc_db[2] = { 0xdb, 0xdd }; | ||
| 131 | |||
| 132 | switch (c) { | ||
| 133 | case 0xc0: | ||
| 134 | memcpy(skb_put(skb, 2), &esc_c0, 2); | ||
| 135 | break; | ||
| 136 | case 0xdb: | ||
| 137 | memcpy(skb_put(skb, 2), &esc_db, 2); | ||
| 138 | break; | ||
| 139 | default: | ||
| 140 | memcpy(skb_put(skb, 1), &c, 1); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb) | ||
| 145 | { | ||
| 146 | struct bcsp_struct *bcsp = hu->priv; | ||
| 147 | |||
| 148 | if (skb->len > 0xFFF) { | ||
| 149 | BT_ERR("Packet too long"); | ||
| 150 | kfree_skb(skb); | ||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | switch (skb->pkt_type) { | ||
| 155 | case HCI_ACLDATA_PKT: | ||
| 156 | case HCI_COMMAND_PKT: | ||
| 157 | skb_queue_tail(&bcsp->rel, skb); | ||
| 158 | break; | ||
| 159 | |||
| 160 | case HCI_SCODATA_PKT: | ||
| 161 | skb_queue_tail(&bcsp->unrel, skb); | ||
| 162 | break; | ||
| 163 | |||
| 164 | default: | ||
| 165 | BT_ERR("Unknown packet type"); | ||
| 166 | kfree_skb(skb); | ||
| 167 | break; | ||
| 168 | } | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, | ||
| 174 | int len, int pkt_type) | ||
| 175 | { | ||
| 176 | struct sk_buff *nskb; | ||
| 177 | u8 hdr[4], chan; | ||
| 178 | int rel, i; | ||
| 179 | |||
| 180 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
| 181 | u16 BCSP_CRC_INIT(bcsp_txmsg_crc); | ||
| 182 | #endif | ||
| 183 | |||
| 184 | switch (pkt_type) { | ||
| 185 | case HCI_ACLDATA_PKT: | ||
| 186 | chan = 6; /* BCSP ACL channel */ | ||
| 187 | rel = 1; /* reliable channel */ | ||
| 188 | break; | ||
| 189 | case HCI_COMMAND_PKT: | ||
| 190 | chan = 5; /* BCSP cmd/evt channel */ | ||
| 191 | rel = 1; /* reliable channel */ | ||
| 192 | break; | ||
| 193 | case HCI_SCODATA_PKT: | ||
| 194 | chan = 7; /* BCSP SCO channel */ | ||
| 195 | rel = 0; /* unreliable channel */ | ||
| 196 | break; | ||
| 197 | case BCSP_LE_PKT: | ||
| 198 | chan = 1; /* BCSP LE channel */ | ||
| 199 | rel = 0; /* unreliable channel */ | ||
| 200 | break; | ||
| 201 | case BCSP_ACK_PKT: | ||
| 202 | chan = 0; /* BCSP internal channel */ | ||
| 203 | rel = 0; /* unreliable channel */ | ||
| 204 | break; | ||
| 205 | default: | ||
| 206 | BT_ERR("Unknown packet type"); | ||
| 207 | return NULL; | ||
| 208 | } | ||
| 209 | |||
| 210 | if (hciextn && chan == 5) { | ||
| 211 | struct hci_command_hdr *hdr = (struct hci_command_hdr *) data; | ||
| 212 | |||
| 213 | if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) { | ||
| 214 | u8 desc = *(data + HCI_COMMAND_HDR_SIZE); | ||
| 215 | if ((desc & 0xf0) == 0xc0) { | ||
| 216 | data += HCI_COMMAND_HDR_SIZE + 1; | ||
| 217 | len -= HCI_COMMAND_HDR_SIZE + 1; | ||
| 218 | chan = desc & 0x0f; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2 | ||
| 224 | (because bytes 0xc0 and 0xdb are escaped, worst case is | ||
| 225 | when the packet is all made of 0xc0 and 0xdb :) ) | ||
| 226 | + 2 (0xc0 delimiters at start and end). */ | ||
| 227 | |||
| 228 | nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); | ||
| 229 | if (!nskb) | ||
| 230 | return NULL; | ||
| 231 | |||
| 232 | nskb->pkt_type = pkt_type; | ||
| 233 | |||
| 234 | bcsp_slip_msgdelim(nskb); | ||
| 235 | |||
| 236 | hdr[0] = bcsp->rxseq_txack << 3; | ||
| 237 | bcsp->txack_req = 0; | ||
| 238 | BT_DBG("We request packet no %u to card", bcsp->rxseq_txack); | ||
| 239 | |||
| 240 | if (rel) { | ||
| 241 | hdr[0] |= 0x80 + bcsp->msgq_txseq; | ||
| 242 | BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); | ||
| 243 | bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; | ||
| 244 | } | ||
| 245 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
| 246 | hdr[0] |= 0x40; | ||
| 247 | #endif | ||
| 248 | |||
| 249 | hdr[1] = ((len << 4) & 0xff) | chan; | ||
| 250 | hdr[2] = len >> 4; | ||
| 251 | hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); | ||
| 252 | |||
| 253 | /* Put BCSP header */ | ||
| 254 | for (i = 0; i < 4; i++) { | ||
| 255 | bcsp_slip_one_byte(nskb, hdr[i]); | ||
| 256 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
| 257 | bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); | ||
| 258 | #endif | ||
| 259 | } | ||
| 260 | |||
| 261 | /* Put payload */ | ||
| 262 | for (i = 0; i < len; i++) { | ||
| 263 | bcsp_slip_one_byte(nskb, data[i]); | ||
| 264 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
| 265 | bcsp_crc_update(&bcsp_txmsg_crc, data[i]); | ||
| 266 | #endif | ||
| 267 | } | ||
| 268 | |||
| 269 | #ifdef CONFIG_BT_HCIUART_BCSP_TXCRC | ||
| 270 | /* Put CRC */ | ||
| 271 | bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); | ||
| 272 | bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); | ||
| 273 | bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); | ||
| 274 | #endif | ||
| 275 | |||
| 276 | bcsp_slip_msgdelim(nskb); | ||
| 277 | return nskb; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* This is a rewrite of pkt_avail in ABCSP */ | ||
| 281 | static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) | ||
| 282 | { | ||
| 283 | struct bcsp_struct *bcsp = hu->priv; | ||
| 284 | unsigned long flags; | ||
| 285 | struct sk_buff *skb; | ||
| 286 | |||
| 287 | /* First of all, check for unreliable messages in the queue, | ||
| 288 | since they have priority */ | ||
| 289 | |||
| 290 | if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { | ||
| 291 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); | ||
| 292 | if (nskb) { | ||
| 293 | kfree_skb(skb); | ||
| 294 | return nskb; | ||
| 295 | } else { | ||
| 296 | skb_queue_head(&bcsp->unrel, skb); | ||
| 297 | BT_ERR("Could not dequeue pkt because alloc_skb failed"); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | /* Now, try to send a reliable pkt. We can only send a | ||
| 302 | reliable packet if the number of packets sent but not yet ack'ed | ||
| 303 | is < than the winsize */ | ||
| 304 | |||
| 305 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
| 306 | |||
| 307 | if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { | ||
| 308 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); | ||
| 309 | if (nskb) { | ||
| 310 | __skb_queue_tail(&bcsp->unack, skb); | ||
| 311 | mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); | ||
| 312 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
| 313 | return nskb; | ||
| 314 | } else { | ||
| 315 | skb_queue_head(&bcsp->rel, skb); | ||
| 316 | BT_ERR("Could not dequeue pkt because alloc_skb failed"); | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
| 321 | |||
| 322 | |||
| 323 | /* We could not send a reliable packet, either because there are | ||
| 324 | none or because there are too many unack'ed pkts. Did we receive | ||
| 325 | any packets we have not acknowledged yet ? */ | ||
| 326 | |||
| 327 | if (bcsp->txack_req) { | ||
| 328 | /* if so, craft an empty ACK pkt and send it on BCSP unreliable | ||
| 329 | channel 0 */ | ||
| 330 | struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT); | ||
| 331 | return nskb; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* We have nothing to send */ | ||
| 335 | return NULL; | ||
| 336 | } | ||
| 337 | |||
| 338 | static int bcsp_flush(struct hci_uart *hu) | ||
| 339 | { | ||
| 340 | BT_DBG("hu %p", hu); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | |||
| 344 | /* Remove ack'ed packets */ | ||
| 345 | static void bcsp_pkt_cull(struct bcsp_struct *bcsp) | ||
| 346 | { | ||
| 347 | unsigned long flags; | ||
| 348 | struct sk_buff *skb; | ||
| 349 | int i, pkts_to_be_removed; | ||
| 350 | u8 seqno; | ||
| 351 | |||
| 352 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
| 353 | |||
| 354 | pkts_to_be_removed = bcsp->unack.qlen; | ||
| 355 | seqno = bcsp->msgq_txseq; | ||
| 356 | |||
| 357 | while (pkts_to_be_removed) { | ||
| 358 | if (bcsp->rxack == seqno) | ||
| 359 | break; | ||
| 360 | pkts_to_be_removed--; | ||
| 361 | seqno = (seqno - 1) & 0x07; | ||
| 362 | } | ||
| 363 | |||
| 364 | if (bcsp->rxack != seqno) | ||
| 365 | BT_ERR("Peer acked invalid packet"); | ||
| 366 | |||
| 367 | BT_DBG("Removing %u pkts out of %u, up to seqno %u", | ||
| 368 | pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); | ||
| 369 | |||
| 370 | for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed | ||
| 371 | && skb != (struct sk_buff *) &bcsp->unack; i++) { | ||
| 372 | struct sk_buff *nskb; | ||
| 373 | |||
| 374 | nskb = skb->next; | ||
| 375 | __skb_unlink(skb, &bcsp->unack); | ||
| 376 | kfree_skb(skb); | ||
| 377 | skb = nskb; | ||
| 378 | } | ||
| 379 | if (bcsp->unack.qlen == 0) | ||
| 380 | del_timer(&bcsp->tbcsp); | ||
| 381 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
| 382 | |||
| 383 | if (i != pkts_to_be_removed) | ||
| 384 | BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); | ||
| 385 | } | ||
| 386 | |||
| 387 | /* Handle BCSP link-establishment packets. When we | ||
| 388 | detect a "sync" packet, symptom that the BT module has reset, | ||
| 389 | we do nothing :) (yet) */ | ||
| 390 | static void bcsp_handle_le_pkt(struct hci_uart *hu) | ||
| 391 | { | ||
| 392 | struct bcsp_struct *bcsp = hu->priv; | ||
| 393 | u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed }; | ||
| 394 | u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 }; | ||
| 395 | u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed }; | ||
| 396 | |||
| 397 | /* spot "conf" pkts and reply with a "conf rsp" pkt */ | ||
| 398 | if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && | ||
| 399 | !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) { | ||
| 400 | struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC); | ||
| 401 | |||
| 402 | BT_DBG("Found a LE conf pkt"); | ||
| 403 | if (!nskb) | ||
| 404 | return; | ||
| 405 | memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); | ||
| 406 | nskb->pkt_type = BCSP_LE_PKT; | ||
| 407 | |||
| 408 | skb_queue_head(&bcsp->unrel, nskb); | ||
| 409 | hci_uart_tx_wakeup(hu); | ||
| 410 | } | ||
| 411 | /* Spot "sync" pkts. If we find one...disaster! */ | ||
| 412 | else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && | ||
| 413 | !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) { | ||
| 414 | BT_ERR("Found a LE sync pkt, card has reset"); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte) | ||
| 419 | { | ||
| 420 | const u8 c0 = 0xc0, db = 0xdb; | ||
| 421 | |||
| 422 | switch (bcsp->rx_esc_state) { | ||
| 423 | case BCSP_ESCSTATE_NOESC: | ||
| 424 | switch (byte) { | ||
| 425 | case 0xdb: | ||
| 426 | bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; | ||
| 427 | break; | ||
| 428 | default: | ||
| 429 | memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); | ||
| 430 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
| 431 | bcsp->rx_state != BCSP_W4_CRC) | ||
| 432 | bcsp_crc_update(&bcsp->message_crc, byte); | ||
| 433 | bcsp->rx_count--; | ||
| 434 | } | ||
| 435 | break; | ||
| 436 | |||
| 437 | case BCSP_ESCSTATE_ESC: | ||
| 438 | switch (byte) { | ||
| 439 | case 0xdc: | ||
| 440 | memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); | ||
| 441 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
| 442 | bcsp->rx_state != BCSP_W4_CRC) | ||
| 443 | bcsp_crc_update(&bcsp-> message_crc, 0xc0); | ||
| 444 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
| 445 | bcsp->rx_count--; | ||
| 446 | break; | ||
| 447 | |||
| 448 | case 0xdd: | ||
| 449 | memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); | ||
| 450 | if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && | ||
| 451 | bcsp->rx_state != BCSP_W4_CRC) | ||
| 452 | bcsp_crc_update(&bcsp-> message_crc, 0xdb); | ||
| 453 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
| 454 | bcsp->rx_count--; | ||
| 455 | break; | ||
| 456 | |||
| 457 | default: | ||
| 458 | BT_ERR ("Invalid byte %02x after esc byte", byte); | ||
| 459 | kfree_skb(bcsp->rx_skb); | ||
| 460 | bcsp->rx_skb = NULL; | ||
| 461 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 462 | bcsp->rx_count = 0; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) | ||
| 468 | { | ||
| 469 | struct bcsp_struct *bcsp = hu->priv; | ||
| 470 | int pass_up; | ||
| 471 | |||
| 472 | if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */ | ||
| 473 | BT_DBG("Received seqno %u from card", bcsp->rxseq_txack); | ||
| 474 | bcsp->rxseq_txack++; | ||
| 475 | bcsp->rxseq_txack %= 0x8; | ||
| 476 | bcsp->txack_req = 1; | ||
| 477 | |||
| 478 | /* If needed, transmit an ack pkt */ | ||
| 479 | hci_uart_tx_wakeup(hu); | ||
| 480 | } | ||
| 481 | |||
| 482 | bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07; | ||
| 483 | BT_DBG("Request for pkt %u from card", bcsp->rxack); | ||
| 484 | |||
| 485 | bcsp_pkt_cull(bcsp); | ||
| 486 | if ((bcsp->rx_skb->data[1] & 0x0f) == 6 && | ||
| 487 | bcsp->rx_skb->data[0] & 0x80) { | ||
| 488 | bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT; | ||
| 489 | pass_up = 1; | ||
| 490 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 && | ||
| 491 | bcsp->rx_skb->data[0] & 0x80) { | ||
| 492 | bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; | ||
| 493 | pass_up = 1; | ||
| 494 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) { | ||
| 495 | bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT; | ||
| 496 | pass_up = 1; | ||
| 497 | } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 && | ||
| 498 | !(bcsp->rx_skb->data[0] & 0x80)) { | ||
| 499 | bcsp_handle_le_pkt(hu); | ||
| 500 | pass_up = 0; | ||
| 501 | } else | ||
| 502 | pass_up = 0; | ||
| 503 | |||
| 504 | if (!pass_up) { | ||
| 505 | struct hci_event_hdr hdr; | ||
| 506 | u8 desc = (bcsp->rx_skb->data[1] & 0x0f); | ||
| 507 | |||
| 508 | if (desc != 0 && desc != 1) { | ||
| 509 | if (hciextn) { | ||
| 510 | desc |= 0xc0; | ||
| 511 | skb_pull(bcsp->rx_skb, 4); | ||
| 512 | memcpy(skb_push(bcsp->rx_skb, 1), &desc, 1); | ||
| 513 | |||
| 514 | hdr.evt = 0xff; | ||
| 515 | hdr.plen = bcsp->rx_skb->len; | ||
| 516 | memcpy(skb_push(bcsp->rx_skb, HCI_EVENT_HDR_SIZE), &hdr, HCI_EVENT_HDR_SIZE); | ||
| 517 | bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; | ||
| 518 | |||
| 519 | hci_recv_frame(bcsp->rx_skb); | ||
| 520 | } else { | ||
| 521 | BT_ERR ("Packet for unknown channel (%u %s)", | ||
| 522 | bcsp->rx_skb->data[1] & 0x0f, | ||
| 523 | bcsp->rx_skb->data[0] & 0x80 ? | ||
| 524 | "reliable" : "unreliable"); | ||
| 525 | kfree_skb(bcsp->rx_skb); | ||
| 526 | } | ||
| 527 | } else | ||
| 528 | kfree_skb(bcsp->rx_skb); | ||
| 529 | } else { | ||
| 530 | /* Pull out BCSP hdr */ | ||
| 531 | skb_pull(bcsp->rx_skb, 4); | ||
| 532 | |||
| 533 | hci_recv_frame(bcsp->rx_skb); | ||
| 534 | } | ||
| 535 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 536 | bcsp->rx_skb = NULL; | ||
| 537 | } | ||
| 538 | |||
| 539 | /* Recv data */ | ||
| 540 | static int bcsp_recv(struct hci_uart *hu, void *data, int count) | ||
| 541 | { | ||
| 542 | struct bcsp_struct *bcsp = hu->priv; | ||
| 543 | register unsigned char *ptr; | ||
| 544 | |||
| 545 | BT_DBG("hu %p count %d rx_state %d rx_count %ld", | ||
| 546 | hu, count, bcsp->rx_state, bcsp->rx_count); | ||
| 547 | |||
| 548 | ptr = data; | ||
| 549 | while (count) { | ||
| 550 | if (bcsp->rx_count) { | ||
| 551 | if (*ptr == 0xc0) { | ||
| 552 | BT_ERR("Short BCSP packet"); | ||
| 553 | kfree_skb(bcsp->rx_skb); | ||
| 554 | bcsp->rx_state = BCSP_W4_PKT_START; | ||
| 555 | bcsp->rx_count = 0; | ||
| 556 | } else | ||
| 557 | bcsp_unslip_one_byte(bcsp, *ptr); | ||
| 558 | |||
| 559 | ptr++; count--; | ||
| 560 | continue; | ||
| 561 | } | ||
| 562 | |||
| 563 | switch (bcsp->rx_state) { | ||
| 564 | case BCSP_W4_BCSP_HDR: | ||
| 565 | if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] + | ||
| 566 | bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { | ||
| 567 | BT_ERR("Error in BCSP hdr checksum"); | ||
| 568 | kfree_skb(bcsp->rx_skb); | ||
| 569 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 570 | bcsp->rx_count = 0; | ||
| 571 | continue; | ||
| 572 | } | ||
| 573 | if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ | ||
| 574 | && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { | ||
| 575 | BT_ERR ("Out-of-order packet arrived, got %u expected %u", | ||
| 576 | bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); | ||
| 577 | |||
| 578 | kfree_skb(bcsp->rx_skb); | ||
| 579 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 580 | bcsp->rx_count = 0; | ||
| 581 | continue; | ||
| 582 | } | ||
| 583 | bcsp->rx_state = BCSP_W4_DATA; | ||
| 584 | bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + | ||
| 585 | (bcsp->rx_skb->data[2] << 4); /* May be 0 */ | ||
| 586 | continue; | ||
| 587 | |||
| 588 | case BCSP_W4_DATA: | ||
| 589 | if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */ | ||
| 590 | bcsp->rx_state = BCSP_W4_CRC; | ||
| 591 | bcsp->rx_count = 2; | ||
| 592 | } else | ||
| 593 | bcsp_complete_rx_pkt(hu); | ||
| 594 | continue; | ||
| 595 | |||
| 596 | case BCSP_W4_CRC: | ||
| 597 | if (bcsp_crc_reverse(bcsp->message_crc) != | ||
| 598 | (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + | ||
| 599 | bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { | ||
| 600 | |||
| 601 | BT_ERR ("Checksum failed: computed %04x received %04x", | ||
| 602 | bcsp_crc_reverse(bcsp->message_crc), | ||
| 603 | (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + | ||
| 604 | bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); | ||
| 605 | |||
| 606 | kfree_skb(bcsp->rx_skb); | ||
| 607 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 608 | bcsp->rx_count = 0; | ||
| 609 | continue; | ||
| 610 | } | ||
| 611 | skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2); | ||
| 612 | bcsp_complete_rx_pkt(hu); | ||
| 613 | continue; | ||
| 614 | |||
| 615 | case BCSP_W4_PKT_DELIMITER: | ||
| 616 | switch (*ptr) { | ||
| 617 | case 0xc0: | ||
| 618 | bcsp->rx_state = BCSP_W4_PKT_START; | ||
| 619 | break; | ||
| 620 | default: | ||
| 621 | /*BT_ERR("Ignoring byte %02x", *ptr);*/ | ||
| 622 | break; | ||
| 623 | } | ||
| 624 | ptr++; count--; | ||
| 625 | break; | ||
| 626 | |||
| 627 | case BCSP_W4_PKT_START: | ||
| 628 | switch (*ptr) { | ||
| 629 | case 0xc0: | ||
| 630 | ptr++; count--; | ||
| 631 | break; | ||
| 632 | |||
| 633 | default: | ||
| 634 | bcsp->rx_state = BCSP_W4_BCSP_HDR; | ||
| 635 | bcsp->rx_count = 4; | ||
| 636 | bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; | ||
| 637 | BCSP_CRC_INIT(bcsp->message_crc); | ||
| 638 | |||
| 639 | /* Do not increment ptr or decrement count | ||
| 640 | * Allocate packet. Max len of a BCSP pkt= | ||
| 641 | * 0xFFF (payload) +4 (header) +2 (crc) */ | ||
| 642 | |||
| 643 | bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC); | ||
| 644 | if (!bcsp->rx_skb) { | ||
| 645 | BT_ERR("Can't allocate mem for new packet"); | ||
| 646 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 647 | bcsp->rx_count = 0; | ||
| 648 | return 0; | ||
| 649 | } | ||
| 650 | bcsp->rx_skb->dev = (void *) hu->hdev; | ||
| 651 | break; | ||
| 652 | } | ||
| 653 | break; | ||
| 654 | } | ||
| 655 | } | ||
| 656 | return count; | ||
| 657 | } | ||
| 658 | |||
| 659 | /* Arrange to retransmit all messages in the relq. */ | ||
| 660 | static void bcsp_timed_event(unsigned long arg) | ||
| 661 | { | ||
| 662 | struct hci_uart *hu = (struct hci_uart *) arg; | ||
| 663 | struct bcsp_struct *bcsp = hu->priv; | ||
| 664 | struct sk_buff *skb; | ||
| 665 | unsigned long flags; | ||
| 666 | |||
| 667 | BT_DBG("hu %p retransmitting %u pkts", hu, bcsp->unack.qlen); | ||
| 668 | |||
| 669 | spin_lock_irqsave(&bcsp->unack.lock, flags); | ||
| 670 | |||
| 671 | while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { | ||
| 672 | bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07; | ||
| 673 | skb_queue_head(&bcsp->rel, skb); | ||
| 674 | } | ||
| 675 | |||
| 676 | spin_unlock_irqrestore(&bcsp->unack.lock, flags); | ||
| 677 | |||
| 678 | hci_uart_tx_wakeup(hu); | ||
| 679 | } | ||
| 680 | |||
| 681 | static int bcsp_open(struct hci_uart *hu) | ||
| 682 | { | ||
| 683 | struct bcsp_struct *bcsp; | ||
| 684 | |||
| 685 | BT_DBG("hu %p", hu); | ||
| 686 | |||
| 687 | bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); | ||
| 688 | if (!bcsp) | ||
| 689 | return -ENOMEM; | ||
| 690 | memset(bcsp, 0, sizeof(*bcsp)); | ||
| 691 | |||
| 692 | hu->priv = bcsp; | ||
| 693 | skb_queue_head_init(&bcsp->unack); | ||
| 694 | skb_queue_head_init(&bcsp->rel); | ||
| 695 | skb_queue_head_init(&bcsp->unrel); | ||
| 696 | |||
| 697 | init_timer(&bcsp->tbcsp); | ||
| 698 | bcsp->tbcsp.function = bcsp_timed_event; | ||
| 699 | bcsp->tbcsp.data = (u_long) hu; | ||
| 700 | |||
| 701 | bcsp->rx_state = BCSP_W4_PKT_DELIMITER; | ||
| 702 | |||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | static int bcsp_close(struct hci_uart *hu) | ||
| 707 | { | ||
| 708 | struct bcsp_struct *bcsp = hu->priv; | ||
| 709 | hu->priv = NULL; | ||
| 710 | |||
| 711 | BT_DBG("hu %p", hu); | ||
| 712 | |||
| 713 | skb_queue_purge(&bcsp->unack); | ||
| 714 | skb_queue_purge(&bcsp->rel); | ||
| 715 | skb_queue_purge(&bcsp->unrel); | ||
| 716 | del_timer(&bcsp->tbcsp); | ||
| 717 | |||
| 718 | kfree(bcsp); | ||
| 719 | return 0; | ||
| 720 | } | ||
| 721 | |||
| 722 | static struct hci_uart_proto bcsp = { | ||
| 723 | .id = HCI_UART_BCSP, | ||
| 724 | .open = bcsp_open, | ||
| 725 | .close = bcsp_close, | ||
| 726 | .enqueue = bcsp_enqueue, | ||
| 727 | .dequeue = bcsp_dequeue, | ||
| 728 | .recv = bcsp_recv, | ||
| 729 | .flush = bcsp_flush | ||
| 730 | }; | ||
| 731 | |||
| 732 | int bcsp_init(void) | ||
| 733 | { | ||
| 734 | int err = hci_uart_register_proto(&bcsp); | ||
| 735 | if (!err) | ||
| 736 | BT_INFO("HCI BCSP protocol initialized"); | ||
| 737 | else | ||
| 738 | BT_ERR("HCI BCSP protocol registration failed"); | ||
| 739 | |||
| 740 | return err; | ||
| 741 | } | ||
| 742 | |||
| 743 | int bcsp_deinit(void) | ||
| 744 | { | ||
| 745 | return hci_uart_unregister_proto(&bcsp); | ||
| 746 | } | ||
| 747 | |||
| 748 | module_param(hciextn, bool, 0644); | ||
| 749 | MODULE_PARM_DESC(hciextn, "Convert HCI Extensions into BCSP packets"); | ||
diff --git a/drivers/bluetooth/hci_bcsp.h b/drivers/bluetooth/hci_bcsp.h new file mode 100644 index 000000000000..a2b3bb92274b --- /dev/null +++ b/drivers/bluetooth/hci_bcsp.h | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* | ||
| 2 | BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). | ||
| 3 | Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> | ||
| 4 | |||
| 5 | Based on | ||
| 6 | hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 7 | ABCSP by Carl Orsborn <cjo@csr.com> | ||
| 8 | |||
| 9 | This program is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License version 2 as | ||
| 11 | published by the Free Software Foundation; | ||
| 12 | |||
| 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 17 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 18 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 19 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 20 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 21 | |||
| 22 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 23 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 24 | SOFTWARE IS DISCLAIMED. | ||
| 25 | */ | ||
| 26 | |||
| 27 | /* | ||
| 28 | * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $ | ||
| 29 | */ | ||
| 30 | |||
| 31 | #ifndef __HCI_BCSP_H__ | ||
| 32 | #define __HCI_BCSP_H__ | ||
| 33 | |||
| 34 | #define BCSP_TXWINSIZE 4 | ||
| 35 | |||
| 36 | #define BCSP_ACK_PKT 0x05 | ||
| 37 | #define BCSP_LE_PKT 0x06 | ||
| 38 | |||
| 39 | struct bcsp_struct { | ||
| 40 | struct sk_buff_head unack; /* Unack'ed packets queue */ | ||
| 41 | struct sk_buff_head rel; /* Reliable packets queue */ | ||
| 42 | struct sk_buff_head unrel; /* Unreliable packets queue */ | ||
| 43 | |||
| 44 | unsigned long rx_count; | ||
| 45 | struct sk_buff *rx_skb; | ||
| 46 | u8 rxseq_txack; /* rxseq == txack. */ | ||
| 47 | u8 rxack; /* Last packet sent by us that the peer ack'ed */ | ||
| 48 | struct timer_list tbcsp; | ||
| 49 | |||
| 50 | enum { | ||
| 51 | BCSP_W4_PKT_DELIMITER, | ||
| 52 | BCSP_W4_PKT_START, | ||
| 53 | BCSP_W4_BCSP_HDR, | ||
| 54 | BCSP_W4_DATA, | ||
| 55 | BCSP_W4_CRC | ||
| 56 | } rx_state; | ||
| 57 | |||
| 58 | enum { | ||
| 59 | BCSP_ESCSTATE_NOESC, | ||
| 60 | BCSP_ESCSTATE_ESC | ||
| 61 | } rx_esc_state; | ||
| 62 | |||
| 63 | u16 message_crc; | ||
| 64 | u8 txack_req; /* Do we need to send ack's to the peer? */ | ||
| 65 | |||
| 66 | /* Reliable packet sequence number - used to assign seq to each rel pkt. */ | ||
| 67 | u8 msgq_txseq; | ||
| 68 | }; | ||
| 69 | |||
| 70 | #endif /* __HCI_BCSP_H__ */ | ||
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c new file mode 100644 index 000000000000..ade94a57bb11 --- /dev/null +++ b/drivers/bluetooth/hci_h4.c | |||
| @@ -0,0 +1,282 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Bluetooth HCI UART(H4) protocol. | ||
| 27 | * | ||
| 28 | * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $ | ||
| 29 | */ | ||
| 30 | #define VERSION "1.2" | ||
| 31 | |||
| 32 | #include <linux/config.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | |||
| 35 | #include <linux/kernel.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/sched.h> | ||
| 38 | #include <linux/types.h> | ||
| 39 | #include <linux/fcntl.h> | ||
| 40 | #include <linux/interrupt.h> | ||
| 41 | #include <linux/ptrace.h> | ||
| 42 | #include <linux/poll.h> | ||
| 43 | |||
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/tty.h> | ||
| 46 | #include <linux/errno.h> | ||
| 47 | #include <linux/string.h> | ||
| 48 | #include <linux/signal.h> | ||
| 49 | #include <linux/ioctl.h> | ||
| 50 | #include <linux/skbuff.h> | ||
| 51 | |||
| 52 | #include <net/bluetooth/bluetooth.h> | ||
| 53 | #include <net/bluetooth/hci_core.h> | ||
| 54 | #include "hci_uart.h" | ||
| 55 | #include "hci_h4.h" | ||
| 56 | |||
| 57 | #ifndef CONFIG_BT_HCIUART_DEBUG | ||
| 58 | #undef BT_DBG | ||
| 59 | #define BT_DBG( A... ) | ||
| 60 | #undef BT_DMP | ||
| 61 | #define BT_DMP( A... ) | ||
| 62 | #endif | ||
| 63 | |||
| 64 | /* Initialize protocol */ | ||
| 65 | static int h4_open(struct hci_uart *hu) | ||
| 66 | { | ||
| 67 | struct h4_struct *h4; | ||
| 68 | |||
| 69 | BT_DBG("hu %p", hu); | ||
| 70 | |||
| 71 | h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); | ||
| 72 | if (!h4) | ||
| 73 | return -ENOMEM; | ||
| 74 | memset(h4, 0, sizeof(*h4)); | ||
| 75 | |||
| 76 | skb_queue_head_init(&h4->txq); | ||
| 77 | |||
| 78 | hu->priv = h4; | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* Flush protocol data */ | ||
| 83 | static int h4_flush(struct hci_uart *hu) | ||
| 84 | { | ||
| 85 | struct h4_struct *h4 = hu->priv; | ||
| 86 | |||
| 87 | BT_DBG("hu %p", hu); | ||
| 88 | skb_queue_purge(&h4->txq); | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | /* Close protocol */ | ||
| 93 | static int h4_close(struct hci_uart *hu) | ||
| 94 | { | ||
| 95 | struct h4_struct *h4 = hu->priv; | ||
| 96 | hu->priv = NULL; | ||
| 97 | |||
| 98 | BT_DBG("hu %p", hu); | ||
| 99 | |||
| 100 | skb_queue_purge(&h4->txq); | ||
| 101 | if (h4->rx_skb) | ||
| 102 | kfree_skb(h4->rx_skb); | ||
| 103 | |||
| 104 | hu->priv = NULL; | ||
| 105 | kfree(h4); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* Enqueue frame for transmittion (padding, crc, etc) */ | ||
| 110 | static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) | ||
| 111 | { | ||
| 112 | struct h4_struct *h4 = hu->priv; | ||
| 113 | |||
| 114 | BT_DBG("hu %p skb %p", hu, skb); | ||
| 115 | |||
| 116 | /* Prepend skb with frame type */ | ||
| 117 | memcpy(skb_push(skb, 1), &skb->pkt_type, 1); | ||
| 118 | skb_queue_tail(&h4->txq, skb); | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | static inline int h4_check_data_len(struct h4_struct *h4, int len) | ||
| 123 | { | ||
| 124 | register int room = skb_tailroom(h4->rx_skb); | ||
| 125 | |||
| 126 | BT_DBG("len %d room %d", len, room); | ||
| 127 | if (!len) { | ||
| 128 | BT_DMP(h4->rx_skb->data, h4->rx_skb->len); | ||
| 129 | hci_recv_frame(h4->rx_skb); | ||
| 130 | } else if (len > room) { | ||
| 131 | BT_ERR("Data length is too large"); | ||
| 132 | kfree_skb(h4->rx_skb); | ||
| 133 | } else { | ||
| 134 | h4->rx_state = H4_W4_DATA; | ||
| 135 | h4->rx_count = len; | ||
| 136 | return len; | ||
| 137 | } | ||
| 138 | |||
| 139 | h4->rx_state = H4_W4_PACKET_TYPE; | ||
| 140 | h4->rx_skb = NULL; | ||
| 141 | h4->rx_count = 0; | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | /* Recv data */ | ||
| 146 | static int h4_recv(struct hci_uart *hu, void *data, int count) | ||
| 147 | { | ||
| 148 | struct h4_struct *h4 = hu->priv; | ||
| 149 | register char *ptr; | ||
| 150 | struct hci_event_hdr *eh; | ||
| 151 | struct hci_acl_hdr *ah; | ||
| 152 | struct hci_sco_hdr *sh; | ||
| 153 | register int len, type, dlen; | ||
| 154 | |||
| 155 | BT_DBG("hu %p count %d rx_state %ld rx_count %ld", | ||
| 156 | hu, count, h4->rx_state, h4->rx_count); | ||
| 157 | |||
| 158 | ptr = data; | ||
| 159 | while (count) { | ||
| 160 | if (h4->rx_count) { | ||
| 161 | len = min_t(unsigned int, h4->rx_count, count); | ||
| 162 | memcpy(skb_put(h4->rx_skb, len), ptr, len); | ||
| 163 | h4->rx_count -= len; count -= len; ptr += len; | ||
| 164 | |||
| 165 | if (h4->rx_count) | ||
| 166 | continue; | ||
| 167 | |||
| 168 | switch (h4->rx_state) { | ||
| 169 | case H4_W4_DATA: | ||
| 170 | BT_DBG("Complete data"); | ||
| 171 | |||
| 172 | BT_DMP(h4->rx_skb->data, h4->rx_skb->len); | ||
| 173 | |||
| 174 | hci_recv_frame(h4->rx_skb); | ||
| 175 | |||
| 176 | h4->rx_state = H4_W4_PACKET_TYPE; | ||
| 177 | h4->rx_skb = NULL; | ||
| 178 | continue; | ||
| 179 | |||
| 180 | case H4_W4_EVENT_HDR: | ||
| 181 | eh = (struct hci_event_hdr *) h4->rx_skb->data; | ||
| 182 | |||
| 183 | BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); | ||
| 184 | |||
| 185 | h4_check_data_len(h4, eh->plen); | ||
| 186 | continue; | ||
| 187 | |||
| 188 | case H4_W4_ACL_HDR: | ||
| 189 | ah = (struct hci_acl_hdr *) h4->rx_skb->data; | ||
| 190 | dlen = __le16_to_cpu(ah->dlen); | ||
| 191 | |||
| 192 | BT_DBG("ACL header: dlen %d", dlen); | ||
| 193 | |||
| 194 | h4_check_data_len(h4, dlen); | ||
| 195 | continue; | ||
| 196 | |||
| 197 | case H4_W4_SCO_HDR: | ||
| 198 | sh = (struct hci_sco_hdr *) h4->rx_skb->data; | ||
| 199 | |||
| 200 | BT_DBG("SCO header: dlen %d", sh->dlen); | ||
| 201 | |||
| 202 | h4_check_data_len(h4, sh->dlen); | ||
| 203 | continue; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | /* H4_W4_PACKET_TYPE */ | ||
| 208 | switch (*ptr) { | ||
| 209 | case HCI_EVENT_PKT: | ||
| 210 | BT_DBG("Event packet"); | ||
| 211 | h4->rx_state = H4_W4_EVENT_HDR; | ||
| 212 | h4->rx_count = HCI_EVENT_HDR_SIZE; | ||
| 213 | type = HCI_EVENT_PKT; | ||
| 214 | break; | ||
| 215 | |||
| 216 | case HCI_ACLDATA_PKT: | ||
| 217 | BT_DBG("ACL packet"); | ||
| 218 | h4->rx_state = H4_W4_ACL_HDR; | ||
| 219 | h4->rx_count = HCI_ACL_HDR_SIZE; | ||
| 220 | type = HCI_ACLDATA_PKT; | ||
| 221 | break; | ||
| 222 | |||
| 223 | case HCI_SCODATA_PKT: | ||
| 224 | BT_DBG("SCO packet"); | ||
| 225 | h4->rx_state = H4_W4_SCO_HDR; | ||
| 226 | h4->rx_count = HCI_SCO_HDR_SIZE; | ||
| 227 | type = HCI_SCODATA_PKT; | ||
| 228 | break; | ||
| 229 | |||
| 230 | default: | ||
| 231 | BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); | ||
| 232 | hu->hdev->stat.err_rx++; | ||
| 233 | ptr++; count--; | ||
| 234 | continue; | ||
| 235 | }; | ||
| 236 | ptr++; count--; | ||
| 237 | |||
| 238 | /* Allocate packet */ | ||
| 239 | h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); | ||
| 240 | if (!h4->rx_skb) { | ||
| 241 | BT_ERR("Can't allocate mem for new packet"); | ||
| 242 | h4->rx_state = H4_W4_PACKET_TYPE; | ||
| 243 | h4->rx_count = 0; | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | h4->rx_skb->dev = (void *) hu->hdev; | ||
| 247 | h4->rx_skb->pkt_type = type; | ||
| 248 | } | ||
| 249 | return count; | ||
| 250 | } | ||
| 251 | |||
| 252 | static struct sk_buff *h4_dequeue(struct hci_uart *hu) | ||
| 253 | { | ||
| 254 | struct h4_struct *h4 = hu->priv; | ||
| 255 | return skb_dequeue(&h4->txq); | ||
| 256 | } | ||
| 257 | |||
| 258 | static struct hci_uart_proto h4p = { | ||
| 259 | .id = HCI_UART_H4, | ||
| 260 | .open = h4_open, | ||
| 261 | .close = h4_close, | ||
| 262 | .recv = h4_recv, | ||
| 263 | .enqueue = h4_enqueue, | ||
| 264 | .dequeue = h4_dequeue, | ||
| 265 | .flush = h4_flush, | ||
| 266 | }; | ||
| 267 | |||
| 268 | int h4_init(void) | ||
| 269 | { | ||
| 270 | int err = hci_uart_register_proto(&h4p); | ||
| 271 | if (!err) | ||
| 272 | BT_INFO("HCI H4 protocol initialized"); | ||
| 273 | else | ||
| 274 | BT_ERR("HCI H4 protocol registration failed"); | ||
| 275 | |||
| 276 | return err; | ||
| 277 | } | ||
| 278 | |||
| 279 | int h4_deinit(void) | ||
| 280 | { | ||
| 281 | return hci_uart_unregister_proto(&h4p); | ||
| 282 | } | ||
diff --git a/drivers/bluetooth/hci_h4.h b/drivers/bluetooth/hci_h4.h new file mode 100644 index 000000000000..b95ff54bfd47 --- /dev/null +++ b/drivers/bluetooth/hci_h4.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #ifdef __KERNEL__ | ||
| 30 | struct h4_struct { | ||
| 31 | unsigned long rx_state; | ||
| 32 | unsigned long rx_count; | ||
| 33 | struct sk_buff *rx_skb; | ||
| 34 | struct sk_buff_head txq; | ||
| 35 | }; | ||
| 36 | |||
| 37 | /* H4 receiver States */ | ||
| 38 | #define H4_W4_PACKET_TYPE 0 | ||
| 39 | #define H4_W4_EVENT_HDR 1 | ||
| 40 | #define H4_W4_ACL_HDR 2 | ||
| 41 | #define H4_W4_SCO_HDR 3 | ||
| 42 | #define H4_W4_DATA 4 | ||
| 43 | |||
| 44 | #endif /* __KERNEL__ */ | ||
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c new file mode 100644 index 000000000000..9075bbb56ad4 --- /dev/null +++ b/drivers/bluetooth/hci_ldisc.c | |||
| @@ -0,0 +1,593 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Bluetooth HCI UART driver. | ||
| 27 | * | ||
| 28 | * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ | ||
| 29 | */ | ||
| 30 | #define VERSION "2.1" | ||
| 31 | |||
| 32 | #include <linux/config.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | |||
| 35 | #include <linux/kernel.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/sched.h> | ||
| 38 | #include <linux/types.h> | ||
| 39 | #include <linux/fcntl.h> | ||
| 40 | #include <linux/interrupt.h> | ||
| 41 | #include <linux/ptrace.h> | ||
| 42 | #include <linux/poll.h> | ||
| 43 | |||
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/tty.h> | ||
| 46 | #include <linux/errno.h> | ||
| 47 | #include <linux/string.h> | ||
| 48 | #include <linux/signal.h> | ||
| 49 | #include <linux/ioctl.h> | ||
| 50 | #include <linux/skbuff.h> | ||
| 51 | |||
| 52 | #include <net/bluetooth/bluetooth.h> | ||
| 53 | #include <net/bluetooth/hci_core.h> | ||
| 54 | |||
| 55 | #include "hci_uart.h" | ||
| 56 | |||
| 57 | #ifndef CONFIG_BT_HCIUART_DEBUG | ||
| 58 | #undef BT_DBG | ||
| 59 | #define BT_DBG( A... ) | ||
| 60 | #undef BT_DMP | ||
| 61 | #define BT_DMP( A... ) | ||
| 62 | #endif | ||
| 63 | |||
| 64 | static int reset = 0; | ||
| 65 | |||
| 66 | static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; | ||
| 67 | |||
| 68 | int hci_uart_register_proto(struct hci_uart_proto *p) | ||
| 69 | { | ||
| 70 | if (p->id >= HCI_UART_MAX_PROTO) | ||
| 71 | return -EINVAL; | ||
| 72 | |||
| 73 | if (hup[p->id]) | ||
| 74 | return -EEXIST; | ||
| 75 | |||
| 76 | hup[p->id] = p; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | int hci_uart_unregister_proto(struct hci_uart_proto *p) | ||
| 81 | { | ||
| 82 | if (p->id >= HCI_UART_MAX_PROTO) | ||
| 83 | return -EINVAL; | ||
| 84 | |||
| 85 | if (!hup[p->id]) | ||
| 86 | return -EINVAL; | ||
| 87 | |||
| 88 | hup[p->id] = NULL; | ||
| 89 | return 0; | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) | ||
| 93 | { | ||
| 94 | if (id >= HCI_UART_MAX_PROTO) | ||
| 95 | return NULL; | ||
| 96 | return hup[id]; | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) | ||
| 100 | { | ||
| 101 | struct hci_dev *hdev = hu->hdev; | ||
| 102 | |||
| 103 | /* Update HCI stat counters */ | ||
| 104 | switch (pkt_type) { | ||
| 105 | case HCI_COMMAND_PKT: | ||
| 106 | hdev->stat.cmd_tx++; | ||
| 107 | break; | ||
| 108 | |||
| 109 | case HCI_ACLDATA_PKT: | ||
| 110 | hdev->stat.acl_tx++; | ||
| 111 | break; | ||
| 112 | |||
| 113 | case HCI_SCODATA_PKT: | ||
| 114 | hdev->stat.cmd_tx++; | ||
| 115 | break; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) | ||
| 120 | { | ||
| 121 | struct sk_buff *skb = hu->tx_skb; | ||
| 122 | if (!skb) | ||
| 123 | skb = hu->proto->dequeue(hu); | ||
| 124 | else | ||
| 125 | hu->tx_skb = NULL; | ||
| 126 | return skb; | ||
| 127 | } | ||
| 128 | |||
| 129 | int hci_uart_tx_wakeup(struct hci_uart *hu) | ||
| 130 | { | ||
| 131 | struct tty_struct *tty = hu->tty; | ||
| 132 | struct hci_dev *hdev = hu->hdev; | ||
| 133 | struct sk_buff *skb; | ||
| 134 | |||
| 135 | if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { | ||
| 136 | set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | BT_DBG(""); | ||
| 141 | |||
| 142 | restart: | ||
| 143 | clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); | ||
| 144 | |||
| 145 | while ((skb = hci_uart_dequeue(hu))) { | ||
| 146 | int len; | ||
| 147 | |||
| 148 | set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
| 149 | len = tty->driver->write(tty, skb->data, skb->len); | ||
| 150 | hdev->stat.byte_tx += len; | ||
| 151 | |||
| 152 | skb_pull(skb, len); | ||
| 153 | if (skb->len) { | ||
| 154 | hu->tx_skb = skb; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | hci_uart_tx_complete(hu, skb->pkt_type); | ||
| 159 | kfree_skb(skb); | ||
| 160 | } | ||
| 161 | |||
| 162 | if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) | ||
| 163 | goto restart; | ||
| 164 | |||
| 165 | clear_bit(HCI_UART_SENDING, &hu->tx_state); | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* ------- Interface to HCI layer ------ */ | ||
| 170 | /* Initialize device */ | ||
| 171 | static int hci_uart_open(struct hci_dev *hdev) | ||
| 172 | { | ||
| 173 | BT_DBG("%s %p", hdev->name, hdev); | ||
| 174 | |||
| 175 | /* Nothing to do for UART driver */ | ||
| 176 | |||
| 177 | set_bit(HCI_RUNNING, &hdev->flags); | ||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Reset device */ | ||
| 182 | static int hci_uart_flush(struct hci_dev *hdev) | ||
| 183 | { | ||
| 184 | struct hci_uart *hu = (struct hci_uart *) hdev->driver_data; | ||
| 185 | struct tty_struct *tty = hu->tty; | ||
| 186 | |||
| 187 | BT_DBG("hdev %p tty %p", hdev, tty); | ||
| 188 | |||
| 189 | if (hu->tx_skb) { | ||
| 190 | kfree_skb(hu->tx_skb); hu->tx_skb = NULL; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* Flush any pending characters in the driver and discipline. */ | ||
| 194 | tty_ldisc_flush(tty); | ||
| 195 | if (tty->driver->flush_buffer) | ||
| 196 | tty->driver->flush_buffer(tty); | ||
| 197 | |||
| 198 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) | ||
| 199 | hu->proto->flush(hu); | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* Close device */ | ||
| 205 | static int hci_uart_close(struct hci_dev *hdev) | ||
| 206 | { | ||
| 207 | BT_DBG("hdev %p", hdev); | ||
| 208 | |||
| 209 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | hci_uart_flush(hdev); | ||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | |||
| 216 | /* Send frames from HCI layer */ | ||
| 217 | static int hci_uart_send_frame(struct sk_buff *skb) | ||
| 218 | { | ||
| 219 | struct hci_dev* hdev = (struct hci_dev *) skb->dev; | ||
| 220 | struct tty_struct *tty; | ||
| 221 | struct hci_uart *hu; | ||
| 222 | |||
| 223 | if (!hdev) { | ||
| 224 | BT_ERR("Frame for uknown device (hdev=NULL)"); | ||
| 225 | return -ENODEV; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 229 | return -EBUSY; | ||
| 230 | |||
| 231 | hu = (struct hci_uart *) hdev->driver_data; | ||
| 232 | tty = hu->tty; | ||
| 233 | |||
| 234 | BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); | ||
| 235 | |||
| 236 | hu->proto->enqueue(hu, skb); | ||
| 237 | |||
| 238 | hci_uart_tx_wakeup(hu); | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | static void hci_uart_destruct(struct hci_dev *hdev) | ||
| 243 | { | ||
| 244 | struct hci_uart *hu; | ||
| 245 | |||
| 246 | if (!hdev) return; | ||
| 247 | |||
| 248 | BT_DBG("%s", hdev->name); | ||
| 249 | |||
| 250 | hu = (struct hci_uart *) hdev->driver_data; | ||
| 251 | kfree(hu); | ||
| 252 | } | ||
| 253 | |||
| 254 | /* ------ LDISC part ------ */ | ||
| 255 | /* hci_uart_tty_open | ||
| 256 | * | ||
| 257 | * Called when line discipline changed to HCI_UART. | ||
| 258 | * | ||
| 259 | * Arguments: | ||
| 260 | * tty pointer to tty info structure | ||
| 261 | * Return Value: | ||
| 262 | * 0 if success, otherwise error code | ||
| 263 | */ | ||
| 264 | static int hci_uart_tty_open(struct tty_struct *tty) | ||
| 265 | { | ||
| 266 | struct hci_uart *hu = (void *) tty->disc_data; | ||
| 267 | |||
| 268 | BT_DBG("tty %p", tty); | ||
| 269 | |||
| 270 | if (hu) | ||
| 271 | return -EEXIST; | ||
| 272 | |||
| 273 | if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) { | ||
| 274 | BT_ERR("Can't allocate controll structure"); | ||
| 275 | return -ENFILE; | ||
| 276 | } | ||
| 277 | memset(hu, 0, sizeof(struct hci_uart)); | ||
| 278 | |||
| 279 | tty->disc_data = hu; | ||
| 280 | hu->tty = tty; | ||
| 281 | |||
| 282 | spin_lock_init(&hu->rx_lock); | ||
| 283 | |||
| 284 | /* Flush any pending characters in the driver and line discipline. */ | ||
| 285 | /* FIXME: why is this needed. Note don't use ldisc_ref here as the | ||
| 286 | open path is before the ldisc is referencable */ | ||
| 287 | if (tty->ldisc.flush_buffer) | ||
| 288 | tty->ldisc.flush_buffer(tty); | ||
| 289 | |||
| 290 | if (tty->driver->flush_buffer) | ||
| 291 | tty->driver->flush_buffer(tty); | ||
| 292 | |||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | /* hci_uart_tty_close() | ||
| 297 | * | ||
| 298 | * Called when the line discipline is changed to something | ||
| 299 | * else, the tty is closed, or the tty detects a hangup. | ||
| 300 | */ | ||
| 301 | static void hci_uart_tty_close(struct tty_struct *tty) | ||
| 302 | { | ||
| 303 | struct hci_uart *hu = (void *)tty->disc_data; | ||
| 304 | |||
| 305 | BT_DBG("tty %p", tty); | ||
| 306 | |||
| 307 | /* Detach from the tty */ | ||
| 308 | tty->disc_data = NULL; | ||
| 309 | |||
| 310 | if (hu) { | ||
| 311 | struct hci_dev *hdev = hu->hdev; | ||
| 312 | hci_uart_close(hdev); | ||
| 313 | |||
| 314 | if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { | ||
| 315 | hu->proto->close(hu); | ||
| 316 | hci_unregister_dev(hdev); | ||
| 317 | hci_free_dev(hdev); | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /* hci_uart_tty_wakeup() | ||
| 323 | * | ||
| 324 | * Callback for transmit wakeup. Called when low level | ||
| 325 | * device driver can accept more send data. | ||
| 326 | * | ||
| 327 | * Arguments: tty pointer to associated tty instance data | ||
| 328 | * Return Value: None | ||
| 329 | */ | ||
| 330 | static void hci_uart_tty_wakeup(struct tty_struct *tty) | ||
| 331 | { | ||
| 332 | struct hci_uart *hu = (void *)tty->disc_data; | ||
| 333 | |||
| 334 | BT_DBG(""); | ||
| 335 | |||
| 336 | if (!hu) | ||
| 337 | return; | ||
| 338 | |||
| 339 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
| 340 | |||
| 341 | if (tty != hu->tty) | ||
| 342 | return; | ||
| 343 | |||
| 344 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) | ||
| 345 | hci_uart_tx_wakeup(hu); | ||
| 346 | } | ||
| 347 | |||
| 348 | /* hci_uart_tty_room() | ||
| 349 | * | ||
| 350 | * Callback function from tty driver. Return the amount of | ||
| 351 | * space left in the receiver's buffer to decide if remote | ||
| 352 | * transmitter is to be throttled. | ||
| 353 | * | ||
| 354 | * Arguments: tty pointer to associated tty instance data | ||
| 355 | * Return Value: number of bytes left in receive buffer | ||
| 356 | */ | ||
| 357 | static int hci_uart_tty_room (struct tty_struct *tty) | ||
| 358 | { | ||
| 359 | return 65536; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* hci_uart_tty_receive() | ||
| 363 | * | ||
| 364 | * Called by tty low level driver when receive data is | ||
| 365 | * available. | ||
| 366 | * | ||
| 367 | * Arguments: tty pointer to tty isntance data | ||
| 368 | * data pointer to received data | ||
| 369 | * flags pointer to flags for data | ||
| 370 | * count count of received data in bytes | ||
| 371 | * | ||
| 372 | * Return Value: None | ||
| 373 | */ | ||
| 374 | static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) | ||
| 375 | { | ||
| 376 | struct hci_uart *hu = (void *)tty->disc_data; | ||
| 377 | |||
| 378 | if (!hu || tty != hu->tty) | ||
| 379 | return; | ||
| 380 | |||
| 381 | if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) | ||
| 382 | return; | ||
| 383 | |||
| 384 | spin_lock(&hu->rx_lock); | ||
| 385 | hu->proto->recv(hu, (void *) data, count); | ||
| 386 | hu->hdev->stat.byte_rx += count; | ||
| 387 | spin_unlock(&hu->rx_lock); | ||
| 388 | |||
| 389 | if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver->unthrottle) | ||
| 390 | tty->driver->unthrottle(tty); | ||
| 391 | } | ||
| 392 | |||
| 393 | static int hci_uart_register_dev(struct hci_uart *hu) | ||
| 394 | { | ||
| 395 | struct hci_dev *hdev; | ||
| 396 | |||
| 397 | BT_DBG(""); | ||
| 398 | |||
| 399 | /* Initialize and register HCI device */ | ||
| 400 | hdev = hci_alloc_dev(); | ||
| 401 | if (!hdev) { | ||
| 402 | BT_ERR("Can't allocate HCI device"); | ||
| 403 | return -ENOMEM; | ||
| 404 | } | ||
| 405 | |||
| 406 | hu->hdev = hdev; | ||
| 407 | |||
| 408 | hdev->type = HCI_UART; | ||
| 409 | hdev->driver_data = hu; | ||
| 410 | |||
| 411 | hdev->open = hci_uart_open; | ||
| 412 | hdev->close = hci_uart_close; | ||
| 413 | hdev->flush = hci_uart_flush; | ||
| 414 | hdev->send = hci_uart_send_frame; | ||
| 415 | hdev->destruct = hci_uart_destruct; | ||
| 416 | |||
| 417 | hdev->owner = THIS_MODULE; | ||
| 418 | |||
| 419 | if (reset) | ||
| 420 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); | ||
| 421 | |||
| 422 | if (hci_register_dev(hdev) < 0) { | ||
| 423 | BT_ERR("Can't register HCI device"); | ||
| 424 | hci_free_dev(hdev); | ||
| 425 | return -ENODEV; | ||
| 426 | } | ||
| 427 | |||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | static int hci_uart_set_proto(struct hci_uart *hu, int id) | ||
| 432 | { | ||
| 433 | struct hci_uart_proto *p; | ||
| 434 | int err; | ||
| 435 | |||
| 436 | p = hci_uart_get_proto(id); | ||
| 437 | if (!p) | ||
| 438 | return -EPROTONOSUPPORT; | ||
| 439 | |||
| 440 | err = p->open(hu); | ||
| 441 | if (err) | ||
| 442 | return err; | ||
| 443 | |||
| 444 | hu->proto = p; | ||
| 445 | |||
| 446 | err = hci_uart_register_dev(hu); | ||
| 447 | if (err) { | ||
| 448 | p->close(hu); | ||
| 449 | return err; | ||
| 450 | } | ||
| 451 | return 0; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* hci_uart_tty_ioctl() | ||
| 455 | * | ||
| 456 | * Process IOCTL system call for the tty device. | ||
| 457 | * | ||
| 458 | * Arguments: | ||
| 459 | * | ||
| 460 | * tty pointer to tty instance data | ||
| 461 | * file pointer to open file object for device | ||
| 462 | * cmd IOCTL command code | ||
| 463 | * arg argument for IOCTL call (cmd dependent) | ||
| 464 | * | ||
| 465 | * Return Value: Command dependent | ||
| 466 | */ | ||
| 467 | static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, | ||
| 468 | unsigned int cmd, unsigned long arg) | ||
| 469 | { | ||
| 470 | struct hci_uart *hu = (void *)tty->disc_data; | ||
| 471 | int err = 0; | ||
| 472 | |||
| 473 | BT_DBG(""); | ||
| 474 | |||
| 475 | /* Verify the status of the device */ | ||
| 476 | if (!hu) | ||
| 477 | return -EBADF; | ||
| 478 | |||
| 479 | switch (cmd) { | ||
| 480 | case HCIUARTSETPROTO: | ||
| 481 | if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { | ||
| 482 | err = hci_uart_set_proto(hu, arg); | ||
| 483 | if (err) { | ||
| 484 | clear_bit(HCI_UART_PROTO_SET, &hu->flags); | ||
| 485 | return err; | ||
| 486 | } | ||
| 487 | tty->low_latency = 1; | ||
| 488 | } else | ||
| 489 | return -EBUSY; | ||
| 490 | |||
| 491 | case HCIUARTGETPROTO: | ||
| 492 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) | ||
| 493 | return hu->proto->id; | ||
| 494 | return -EUNATCH; | ||
| 495 | |||
| 496 | default: | ||
| 497 | err = n_tty_ioctl(tty, file, cmd, arg); | ||
| 498 | break; | ||
| 499 | }; | ||
| 500 | |||
| 501 | return err; | ||
| 502 | } | ||
| 503 | |||
| 504 | /* | ||
| 505 | * We don't provide read/write/poll interface for user space. | ||
| 506 | */ | ||
| 507 | static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) | ||
| 508 | { | ||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) | ||
| 512 | { | ||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) | ||
| 516 | { | ||
| 517 | return 0; | ||
| 518 | } | ||
| 519 | |||
| 520 | #ifdef CONFIG_BT_HCIUART_H4 | ||
| 521 | int h4_init(void); | ||
| 522 | int h4_deinit(void); | ||
| 523 | #endif | ||
| 524 | #ifdef CONFIG_BT_HCIUART_BCSP | ||
| 525 | int bcsp_init(void); | ||
| 526 | int bcsp_deinit(void); | ||
| 527 | #endif | ||
| 528 | |||
| 529 | static int __init hci_uart_init(void) | ||
| 530 | { | ||
| 531 | static struct tty_ldisc hci_uart_ldisc; | ||
| 532 | int err; | ||
| 533 | |||
| 534 | BT_INFO("HCI UART driver ver %s", VERSION); | ||
| 535 | |||
| 536 | /* Register the tty discipline */ | ||
| 537 | |||
| 538 | memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); | ||
| 539 | hci_uart_ldisc.magic = TTY_LDISC_MAGIC; | ||
| 540 | hci_uart_ldisc.name = "n_hci"; | ||
| 541 | hci_uart_ldisc.open = hci_uart_tty_open; | ||
| 542 | hci_uart_ldisc.close = hci_uart_tty_close; | ||
| 543 | hci_uart_ldisc.read = hci_uart_tty_read; | ||
| 544 | hci_uart_ldisc.write = hci_uart_tty_write; | ||
| 545 | hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; | ||
| 546 | hci_uart_ldisc.poll = hci_uart_tty_poll; | ||
| 547 | hci_uart_ldisc.receive_room= hci_uart_tty_room; | ||
| 548 | hci_uart_ldisc.receive_buf = hci_uart_tty_receive; | ||
| 549 | hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; | ||
| 550 | hci_uart_ldisc.owner = THIS_MODULE; | ||
| 551 | |||
| 552 | if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { | ||
| 553 | BT_ERR("HCI line discipline registration failed. (%d)", err); | ||
| 554 | return err; | ||
| 555 | } | ||
| 556 | |||
| 557 | #ifdef CONFIG_BT_HCIUART_H4 | ||
| 558 | h4_init(); | ||
| 559 | #endif | ||
| 560 | #ifdef CONFIG_BT_HCIUART_BCSP | ||
| 561 | bcsp_init(); | ||
| 562 | #endif | ||
| 563 | |||
| 564 | return 0; | ||
| 565 | } | ||
| 566 | |||
| 567 | static void __exit hci_uart_exit(void) | ||
| 568 | { | ||
| 569 | int err; | ||
| 570 | |||
| 571 | #ifdef CONFIG_BT_HCIUART_H4 | ||
| 572 | h4_deinit(); | ||
| 573 | #endif | ||
| 574 | #ifdef CONFIG_BT_HCIUART_BCSP | ||
| 575 | bcsp_deinit(); | ||
| 576 | #endif | ||
| 577 | |||
| 578 | /* Release tty registration of line discipline */ | ||
| 579 | if ((err = tty_register_ldisc(N_HCI, NULL))) | ||
| 580 | BT_ERR("Can't unregister HCI line discipline (%d)", err); | ||
| 581 | } | ||
| 582 | |||
| 583 | module_init(hci_uart_init); | ||
| 584 | module_exit(hci_uart_exit); | ||
| 585 | |||
| 586 | module_param(reset, bool, 0644); | ||
| 587 | MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); | ||
| 588 | |||
| 589 | MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); | ||
| 590 | MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); | ||
| 591 | MODULE_VERSION(VERSION); | ||
| 592 | MODULE_LICENSE("GPL"); | ||
| 593 | MODULE_ALIAS_LDISC(N_HCI); | ||
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h new file mode 100644 index 000000000000..0a57d72790ec --- /dev/null +++ b/drivers/bluetooth/hci_uart.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #ifndef N_HCI | ||
| 30 | #define N_HCI 15 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* Ioctls */ | ||
| 34 | #define HCIUARTSETPROTO _IOW('U', 200, int) | ||
| 35 | #define HCIUARTGETPROTO _IOR('U', 201, int) | ||
| 36 | |||
| 37 | /* UART protocols */ | ||
| 38 | #define HCI_UART_MAX_PROTO 4 | ||
| 39 | |||
| 40 | #define HCI_UART_H4 0 | ||
| 41 | #define HCI_UART_BCSP 1 | ||
| 42 | #define HCI_UART_3WIRE 2 | ||
| 43 | #define HCI_UART_H4DS 3 | ||
| 44 | |||
| 45 | #ifdef __KERNEL__ | ||
| 46 | struct hci_uart; | ||
| 47 | |||
| 48 | struct hci_uart_proto { | ||
| 49 | unsigned int id; | ||
| 50 | int (*open)(struct hci_uart *hu); | ||
| 51 | int (*close)(struct hci_uart *hu); | ||
| 52 | int (*flush)(struct hci_uart *hu); | ||
| 53 | int (*recv)(struct hci_uart *hu, void *data, int len); | ||
| 54 | int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); | ||
| 55 | struct sk_buff *(*dequeue)(struct hci_uart *hu); | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct hci_uart { | ||
| 59 | struct tty_struct *tty; | ||
| 60 | struct hci_dev *hdev; | ||
| 61 | unsigned long flags; | ||
| 62 | |||
| 63 | struct hci_uart_proto *proto; | ||
| 64 | void *priv; | ||
| 65 | |||
| 66 | struct sk_buff *tx_skb; | ||
| 67 | unsigned long tx_state; | ||
| 68 | spinlock_t rx_lock; | ||
| 69 | }; | ||
| 70 | |||
| 71 | /* HCI_UART flag bits */ | ||
| 72 | #define HCI_UART_PROTO_SET 0 | ||
| 73 | |||
| 74 | /* TX states */ | ||
| 75 | #define HCI_UART_SENDING 1 | ||
| 76 | #define HCI_UART_TX_WAKEUP 2 | ||
| 77 | |||
| 78 | int hci_uart_register_proto(struct hci_uart_proto *p); | ||
| 79 | int hci_uart_unregister_proto(struct hci_uart_proto *p); | ||
| 80 | int hci_uart_tx_wakeup(struct hci_uart *hu); | ||
| 81 | |||
| 82 | #endif /* __KERNEL__ */ | ||
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c new file mode 100644 index 000000000000..b120ecf7b8c9 --- /dev/null +++ b/drivers/bluetooth/hci_usb.c | |||
| @@ -0,0 +1,1075 @@ | |||
| 1 | /* | ||
| 2 | HCI USB driver for Linux Bluetooth protocol stack (BlueZ) | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 5 | |||
| 6 | Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 7 | |||
| 8 | This program is free software; you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License version 2 as | ||
| 10 | published by the Free Software Foundation; | ||
| 11 | |||
| 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 13 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 15 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 16 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 17 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 18 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 19 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 20 | |||
| 21 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 22 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 23 | SOFTWARE IS DISCLAIMED. | ||
| 24 | */ | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Bluetooth HCI USB driver. | ||
| 28 | * Based on original USB Bluetooth driver for Linux kernel | ||
| 29 | * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com> | ||
| 30 | * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> | ||
| 31 | * | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/config.h> | ||
| 35 | #include <linux/module.h> | ||
| 36 | |||
| 37 | #include <linux/kernel.h> | ||
| 38 | #include <linux/init.h> | ||
| 39 | #include <linux/sched.h> | ||
| 40 | #include <linux/unistd.h> | ||
| 41 | #include <linux/types.h> | ||
| 42 | #include <linux/interrupt.h> | ||
| 43 | #include <linux/moduleparam.h> | ||
| 44 | |||
| 45 | #include <linux/slab.h> | ||
| 46 | #include <linux/errno.h> | ||
| 47 | #include <linux/string.h> | ||
| 48 | #include <linux/skbuff.h> | ||
| 49 | |||
| 50 | #include <linux/usb.h> | ||
| 51 | |||
| 52 | #include <net/bluetooth/bluetooth.h> | ||
| 53 | #include <net/bluetooth/hci_core.h> | ||
| 54 | |||
| 55 | #include "hci_usb.h" | ||
| 56 | |||
| 57 | #ifndef CONFIG_BT_HCIUSB_DEBUG | ||
| 58 | #undef BT_DBG | ||
| 59 | #define BT_DBG(D...) | ||
| 60 | #undef BT_DMP | ||
| 61 | #define BT_DMP(D...) | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #ifndef CONFIG_BT_HCIUSB_ZERO_PACKET | ||
| 65 | #undef URB_ZERO_PACKET | ||
| 66 | #define URB_ZERO_PACKET 0 | ||
| 67 | #endif | ||
| 68 | |||
| 69 | static int ignore = 0; | ||
| 70 | static int reset = 0; | ||
| 71 | |||
| 72 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 73 | static int isoc = 2; | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #define VERSION "2.8" | ||
| 77 | |||
| 78 | static struct usb_driver hci_usb_driver; | ||
| 79 | |||
| 80 | static struct usb_device_id bluetooth_ids[] = { | ||
| 81 | /* Generic Bluetooth USB device */ | ||
| 82 | { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, | ||
| 83 | |||
| 84 | /* AVM BlueFRITZ! USB v2.0 */ | ||
| 85 | { USB_DEVICE(0x057c, 0x3800) }, | ||
| 86 | |||
| 87 | /* Bluetooth Ultraport Module from IBM */ | ||
| 88 | { USB_DEVICE(0x04bf, 0x030a) }, | ||
| 89 | |||
| 90 | /* ALPS Modules with non-standard id */ | ||
| 91 | { USB_DEVICE(0x044e, 0x3001) }, | ||
| 92 | { USB_DEVICE(0x044e, 0x3002) }, | ||
| 93 | |||
| 94 | /* Ericsson with non-standard id */ | ||
| 95 | { USB_DEVICE(0x0bdb, 0x1002) }, | ||
| 96 | |||
| 97 | { } /* Terminating entry */ | ||
| 98 | }; | ||
| 99 | |||
| 100 | MODULE_DEVICE_TABLE (usb, bluetooth_ids); | ||
| 101 | |||
| 102 | static struct usb_device_id blacklist_ids[] = { | ||
| 103 | /* Broadcom BCM2033 without firmware */ | ||
| 104 | { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, | ||
| 105 | |||
| 106 | /* Broadcom BCM2035 */ | ||
| 107 | { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, | ||
| 108 | { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, | ||
| 109 | |||
| 110 | /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ | ||
| 111 | { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, | ||
| 112 | |||
| 113 | /* ISSC Bluetooth Adapter v3.1 */ | ||
| 114 | { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, | ||
| 115 | |||
| 116 | /* RTX Telecom based adapter with buggy SCO support */ | ||
| 117 | { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, | ||
| 118 | |||
| 119 | /* Digianswer devices */ | ||
| 120 | { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, | ||
| 121 | { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, | ||
| 122 | |||
| 123 | /* CSR BlueCore Bluetooth Sniffer */ | ||
| 124 | { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, | ||
| 125 | |||
| 126 | { } /* Terminating entry */ | ||
| 127 | }; | ||
| 128 | |||
| 129 | static struct _urb *_urb_alloc(int isoc, int gfp) | ||
| 130 | { | ||
| 131 | struct _urb *_urb = kmalloc(sizeof(struct _urb) + | ||
| 132 | sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); | ||
| 133 | if (_urb) { | ||
| 134 | memset(_urb, 0, sizeof(*_urb)); | ||
| 135 | usb_init_urb(&_urb->urb); | ||
| 136 | } | ||
| 137 | return _urb; | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct _urb *_urb_dequeue(struct _urb_queue *q) | ||
| 141 | { | ||
| 142 | struct _urb *_urb = NULL; | ||
| 143 | unsigned long flags; | ||
| 144 | spin_lock_irqsave(&q->lock, flags); | ||
| 145 | { | ||
| 146 | struct list_head *head = &q->head; | ||
| 147 | struct list_head *next = head->next; | ||
| 148 | if (next != head) { | ||
| 149 | _urb = list_entry(next, struct _urb, list); | ||
| 150 | list_del(next); _urb->queue = NULL; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 154 | return _urb; | ||
| 155 | } | ||
| 156 | |||
| 157 | static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs); | ||
| 158 | static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs); | ||
| 159 | |||
| 160 | #define __pending_tx(husb, type) (&husb->pending_tx[type-1]) | ||
| 161 | #define __pending_q(husb, type) (&husb->pending_q[type-1]) | ||
| 162 | #define __completed_q(husb, type) (&husb->completed_q[type-1]) | ||
| 163 | #define __transmit_q(husb, type) (&husb->transmit_q[type-1]) | ||
| 164 | #define __reassembly(husb, type) (husb->reassembly[type-1]) | ||
| 165 | |||
| 166 | static inline struct _urb *__get_completed(struct hci_usb *husb, int type) | ||
| 167 | { | ||
| 168 | return _urb_dequeue(__completed_q(husb, type)); | ||
| 169 | } | ||
| 170 | |||
| 171 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 172 | static void __fill_isoc_desc(struct urb *urb, int len, int mtu) | ||
| 173 | { | ||
| 174 | int offset = 0, i; | ||
| 175 | |||
| 176 | BT_DBG("len %d mtu %d", len, mtu); | ||
| 177 | |||
| 178 | for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { | ||
| 179 | urb->iso_frame_desc[i].offset = offset; | ||
| 180 | urb->iso_frame_desc[i].length = mtu; | ||
| 181 | BT_DBG("desc %d offset %d len %d", i, offset, mtu); | ||
| 182 | } | ||
| 183 | if (len && i < HCI_MAX_ISOC_FRAMES) { | ||
| 184 | urb->iso_frame_desc[i].offset = offset; | ||
| 185 | urb->iso_frame_desc[i].length = len; | ||
| 186 | BT_DBG("desc %d offset %d len %d", i, offset, len); | ||
| 187 | i++; | ||
| 188 | } | ||
| 189 | urb->number_of_packets = i; | ||
| 190 | } | ||
| 191 | #endif | ||
| 192 | |||
| 193 | static int hci_usb_intr_rx_submit(struct hci_usb *husb) | ||
| 194 | { | ||
| 195 | struct _urb *_urb; | ||
| 196 | struct urb *urb; | ||
| 197 | int err, pipe, interval, size; | ||
| 198 | void *buf; | ||
| 199 | |||
| 200 | BT_DBG("%s", husb->hdev->name); | ||
| 201 | |||
| 202 | size = le16_to_cpu(husb->intr_in_ep->desc.wMaxPacketSize); | ||
| 203 | |||
| 204 | buf = kmalloc(size, GFP_ATOMIC); | ||
| 205 | if (!buf) | ||
| 206 | return -ENOMEM; | ||
| 207 | |||
| 208 | _urb = _urb_alloc(0, GFP_ATOMIC); | ||
| 209 | if (!_urb) { | ||
| 210 | kfree(buf); | ||
| 211 | return -ENOMEM; | ||
| 212 | } | ||
| 213 | _urb->type = HCI_EVENT_PKT; | ||
| 214 | _urb_queue_tail(__pending_q(husb, _urb->type), _urb); | ||
| 215 | |||
| 216 | urb = &_urb->urb; | ||
| 217 | pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->desc.bEndpointAddress); | ||
| 218 | interval = husb->intr_in_ep->desc.bInterval; | ||
| 219 | usb_fill_int_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); | ||
| 220 | |||
| 221 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 222 | if (err) { | ||
| 223 | BT_ERR("%s intr rx submit failed urb %p err %d", | ||
| 224 | husb->hdev->name, urb, err); | ||
| 225 | _urb_unlink(_urb); | ||
| 226 | _urb_free(_urb); | ||
| 227 | kfree(buf); | ||
| 228 | } | ||
| 229 | return err; | ||
| 230 | } | ||
| 231 | |||
| 232 | static int hci_usb_bulk_rx_submit(struct hci_usb *husb) | ||
| 233 | { | ||
| 234 | struct _urb *_urb; | ||
| 235 | struct urb *urb; | ||
| 236 | int err, pipe, size = HCI_MAX_FRAME_SIZE; | ||
| 237 | void *buf; | ||
| 238 | |||
| 239 | buf = kmalloc(size, GFP_ATOMIC); | ||
| 240 | if (!buf) | ||
| 241 | return -ENOMEM; | ||
| 242 | |||
| 243 | _urb = _urb_alloc(0, GFP_ATOMIC); | ||
| 244 | if (!_urb) { | ||
| 245 | kfree(buf); | ||
| 246 | return -ENOMEM; | ||
| 247 | } | ||
| 248 | _urb->type = HCI_ACLDATA_PKT; | ||
| 249 | _urb_queue_tail(__pending_q(husb, _urb->type), _urb); | ||
| 250 | |||
| 251 | urb = &_urb->urb; | ||
| 252 | pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->desc.bEndpointAddress); | ||
| 253 | usb_fill_bulk_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); | ||
| 254 | urb->transfer_flags = 0; | ||
| 255 | |||
| 256 | BT_DBG("%s urb %p", husb->hdev->name, urb); | ||
| 257 | |||
| 258 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 259 | if (err) { | ||
| 260 | BT_ERR("%s bulk rx submit failed urb %p err %d", | ||
| 261 | husb->hdev->name, urb, err); | ||
| 262 | _urb_unlink(_urb); | ||
| 263 | _urb_free(_urb); | ||
| 264 | kfree(buf); | ||
| 265 | } | ||
| 266 | return err; | ||
| 267 | } | ||
| 268 | |||
| 269 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 270 | static int hci_usb_isoc_rx_submit(struct hci_usb *husb) | ||
| 271 | { | ||
| 272 | struct _urb *_urb; | ||
| 273 | struct urb *urb; | ||
| 274 | int err, mtu, size; | ||
| 275 | void *buf; | ||
| 276 | |||
| 277 | mtu = le16_to_cpu(husb->isoc_in_ep->desc.wMaxPacketSize); | ||
| 278 | size = mtu * HCI_MAX_ISOC_FRAMES; | ||
| 279 | |||
| 280 | buf = kmalloc(size, GFP_ATOMIC); | ||
| 281 | if (!buf) | ||
| 282 | return -ENOMEM; | ||
| 283 | |||
| 284 | _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); | ||
| 285 | if (!_urb) { | ||
| 286 | kfree(buf); | ||
| 287 | return -ENOMEM; | ||
| 288 | } | ||
| 289 | _urb->type = HCI_SCODATA_PKT; | ||
| 290 | _urb_queue_tail(__pending_q(husb, _urb->type), _urb); | ||
| 291 | |||
| 292 | urb = &_urb->urb; | ||
| 293 | |||
| 294 | urb->context = husb; | ||
| 295 | urb->dev = husb->udev; | ||
| 296 | urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->desc.bEndpointAddress); | ||
| 297 | urb->complete = hci_usb_rx_complete; | ||
| 298 | |||
| 299 | urb->interval = husb->isoc_in_ep->desc.bInterval; | ||
| 300 | |||
| 301 | urb->transfer_buffer_length = size; | ||
| 302 | urb->transfer_buffer = buf; | ||
| 303 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 304 | |||
| 305 | __fill_isoc_desc(urb, size, mtu); | ||
| 306 | |||
| 307 | BT_DBG("%s urb %p", husb->hdev->name, urb); | ||
| 308 | |||
| 309 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 310 | if (err) { | ||
| 311 | BT_ERR("%s isoc rx submit failed urb %p err %d", | ||
| 312 | husb->hdev->name, urb, err); | ||
| 313 | _urb_unlink(_urb); | ||
| 314 | _urb_free(_urb); | ||
| 315 | kfree(buf); | ||
| 316 | } | ||
| 317 | return err; | ||
| 318 | } | ||
| 319 | #endif | ||
| 320 | |||
| 321 | /* Initialize device */ | ||
| 322 | static int hci_usb_open(struct hci_dev *hdev) | ||
| 323 | { | ||
| 324 | struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; | ||
| 325 | int i, err; | ||
| 326 | unsigned long flags; | ||
| 327 | |||
| 328 | BT_DBG("%s", hdev->name); | ||
| 329 | |||
| 330 | if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) | ||
| 331 | return 0; | ||
| 332 | |||
| 333 | write_lock_irqsave(&husb->completion_lock, flags); | ||
| 334 | |||
| 335 | err = hci_usb_intr_rx_submit(husb); | ||
| 336 | if (!err) { | ||
| 337 | for (i = 0; i < HCI_MAX_BULK_RX; i++) | ||
| 338 | hci_usb_bulk_rx_submit(husb); | ||
| 339 | |||
| 340 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 341 | if (husb->isoc_iface) | ||
| 342 | for (i = 0; i < HCI_MAX_ISOC_RX; i++) | ||
| 343 | hci_usb_isoc_rx_submit(husb); | ||
| 344 | #endif | ||
| 345 | } else { | ||
| 346 | clear_bit(HCI_RUNNING, &hdev->flags); | ||
| 347 | } | ||
| 348 | |||
| 349 | write_unlock_irqrestore(&husb->completion_lock, flags); | ||
| 350 | return err; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* Reset device */ | ||
| 354 | static int hci_usb_flush(struct hci_dev *hdev) | ||
| 355 | { | ||
| 356 | struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; | ||
| 357 | int i; | ||
| 358 | |||
| 359 | BT_DBG("%s", hdev->name); | ||
| 360 | |||
| 361 | for (i = 0; i < 4; i++) | ||
| 362 | skb_queue_purge(&husb->transmit_q[i]); | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | |||
| 366 | static void hci_usb_unlink_urbs(struct hci_usb *husb) | ||
| 367 | { | ||
| 368 | int i; | ||
| 369 | |||
| 370 | BT_DBG("%s", husb->hdev->name); | ||
| 371 | |||
| 372 | for (i = 0; i < 4; i++) { | ||
| 373 | struct _urb *_urb; | ||
| 374 | struct urb *urb; | ||
| 375 | |||
| 376 | /* Kill pending requests */ | ||
| 377 | while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { | ||
| 378 | urb = &_urb->urb; | ||
| 379 | BT_DBG("%s unlinking _urb %p type %d urb %p", | ||
| 380 | husb->hdev->name, _urb, _urb->type, urb); | ||
| 381 | usb_kill_urb(urb); | ||
| 382 | _urb_queue_tail(__completed_q(husb, _urb->type), _urb); | ||
| 383 | } | ||
| 384 | |||
| 385 | /* Release completed requests */ | ||
| 386 | while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { | ||
| 387 | urb = &_urb->urb; | ||
| 388 | BT_DBG("%s freeing _urb %p type %d urb %p", | ||
| 389 | husb->hdev->name, _urb, _urb->type, urb); | ||
| 390 | if (urb->setup_packet) | ||
| 391 | kfree(urb->setup_packet); | ||
| 392 | if (urb->transfer_buffer) | ||
| 393 | kfree(urb->transfer_buffer); | ||
| 394 | _urb_free(_urb); | ||
| 395 | } | ||
| 396 | |||
| 397 | /* Release reassembly buffers */ | ||
| 398 | if (husb->reassembly[i]) { | ||
| 399 | kfree_skb(husb->reassembly[i]); | ||
| 400 | husb->reassembly[i] = NULL; | ||
| 401 | } | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | /* Close device */ | ||
| 406 | static int hci_usb_close(struct hci_dev *hdev) | ||
| 407 | { | ||
| 408 | struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; | ||
| 409 | unsigned long flags; | ||
| 410 | |||
| 411 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | ||
| 412 | return 0; | ||
| 413 | |||
| 414 | BT_DBG("%s", hdev->name); | ||
| 415 | |||
| 416 | /* Synchronize with completion handlers */ | ||
| 417 | write_lock_irqsave(&husb->completion_lock, flags); | ||
| 418 | write_unlock_irqrestore(&husb->completion_lock, flags); | ||
| 419 | |||
| 420 | hci_usb_unlink_urbs(husb); | ||
| 421 | hci_usb_flush(hdev); | ||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) | ||
| 426 | { | ||
| 427 | struct urb *urb = &_urb->urb; | ||
| 428 | int err; | ||
| 429 | |||
| 430 | BT_DBG("%s urb %p type %d", husb->hdev->name, urb, _urb->type); | ||
| 431 | |||
| 432 | _urb_queue_tail(__pending_q(husb, _urb->type), _urb); | ||
| 433 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 434 | if (err) { | ||
| 435 | BT_ERR("%s tx submit failed urb %p type %d err %d", | ||
| 436 | husb->hdev->name, urb, _urb->type, err); | ||
| 437 | _urb_unlink(_urb); | ||
| 438 | _urb_queue_tail(__completed_q(husb, _urb->type), _urb); | ||
| 439 | } else | ||
| 440 | atomic_inc(__pending_tx(husb, _urb->type)); | ||
| 441 | |||
| 442 | return err; | ||
| 443 | } | ||
| 444 | |||
| 445 | static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) | ||
| 446 | { | ||
| 447 | struct _urb *_urb = __get_completed(husb, skb->pkt_type); | ||
| 448 | struct usb_ctrlrequest *dr; | ||
| 449 | struct urb *urb; | ||
| 450 | |||
| 451 | if (!_urb) { | ||
| 452 | _urb = _urb_alloc(0, GFP_ATOMIC); | ||
| 453 | if (!_urb) | ||
| 454 | return -ENOMEM; | ||
| 455 | _urb->type = skb->pkt_type; | ||
| 456 | |||
| 457 | dr = kmalloc(sizeof(*dr), GFP_ATOMIC); | ||
| 458 | if (!dr) { | ||
| 459 | _urb_free(_urb); | ||
| 460 | return -ENOMEM; | ||
| 461 | } | ||
| 462 | } else | ||
| 463 | dr = (void *) _urb->urb.setup_packet; | ||
| 464 | |||
| 465 | dr->bRequestType = husb->ctrl_req; | ||
| 466 | dr->bRequest = 0; | ||
| 467 | dr->wIndex = 0; | ||
| 468 | dr->wValue = 0; | ||
| 469 | dr->wLength = __cpu_to_le16(skb->len); | ||
| 470 | |||
| 471 | urb = &_urb->urb; | ||
| 472 | usb_fill_control_urb(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), | ||
| 473 | (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); | ||
| 474 | |||
| 475 | BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); | ||
| 476 | |||
| 477 | _urb->priv = skb; | ||
| 478 | return __tx_submit(husb, _urb); | ||
| 479 | } | ||
| 480 | |||
| 481 | static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) | ||
| 482 | { | ||
| 483 | struct _urb *_urb = __get_completed(husb, skb->pkt_type); | ||
| 484 | struct urb *urb; | ||
| 485 | int pipe; | ||
| 486 | |||
| 487 | if (!_urb) { | ||
| 488 | _urb = _urb_alloc(0, GFP_ATOMIC); | ||
| 489 | if (!_urb) | ||
| 490 | return -ENOMEM; | ||
| 491 | _urb->type = skb->pkt_type; | ||
| 492 | } | ||
| 493 | |||
| 494 | urb = &_urb->urb; | ||
| 495 | pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress); | ||
| 496 | usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, | ||
| 497 | hci_usb_tx_complete, husb); | ||
| 498 | urb->transfer_flags = URB_ZERO_PACKET; | ||
| 499 | |||
| 500 | BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); | ||
| 501 | |||
| 502 | _urb->priv = skb; | ||
| 503 | return __tx_submit(husb, _urb); | ||
| 504 | } | ||
| 505 | |||
| 506 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 507 | static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) | ||
| 508 | { | ||
| 509 | struct _urb *_urb = __get_completed(husb, skb->pkt_type); | ||
| 510 | struct urb *urb; | ||
| 511 | |||
| 512 | if (!_urb) { | ||
| 513 | _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); | ||
| 514 | if (!_urb) | ||
| 515 | return -ENOMEM; | ||
| 516 | _urb->type = skb->pkt_type; | ||
| 517 | } | ||
| 518 | |||
| 519 | BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); | ||
| 520 | |||
| 521 | urb = &_urb->urb; | ||
| 522 | |||
| 523 | urb->context = husb; | ||
| 524 | urb->dev = husb->udev; | ||
| 525 | urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->desc.bEndpointAddress); | ||
| 526 | urb->complete = hci_usb_tx_complete; | ||
| 527 | urb->transfer_flags = URB_ISO_ASAP; | ||
| 528 | |||
| 529 | urb->interval = husb->isoc_out_ep->desc.bInterval; | ||
| 530 | |||
| 531 | urb->transfer_buffer = skb->data; | ||
| 532 | urb->transfer_buffer_length = skb->len; | ||
| 533 | |||
| 534 | __fill_isoc_desc(urb, skb->len, le16_to_cpu(husb->isoc_out_ep->desc.wMaxPacketSize)); | ||
| 535 | |||
| 536 | _urb->priv = skb; | ||
| 537 | return __tx_submit(husb, _urb); | ||
| 538 | } | ||
| 539 | #endif | ||
| 540 | |||
| 541 | static void hci_usb_tx_process(struct hci_usb *husb) | ||
| 542 | { | ||
| 543 | struct sk_buff_head *q; | ||
| 544 | struct sk_buff *skb; | ||
| 545 | |||
| 546 | BT_DBG("%s", husb->hdev->name); | ||
| 547 | |||
| 548 | do { | ||
| 549 | clear_bit(HCI_USB_TX_WAKEUP, &husb->state); | ||
| 550 | |||
| 551 | /* Process command queue */ | ||
| 552 | q = __transmit_q(husb, HCI_COMMAND_PKT); | ||
| 553 | if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && | ||
| 554 | (skb = skb_dequeue(q))) { | ||
| 555 | if (hci_usb_send_ctrl(husb, skb) < 0) | ||
| 556 | skb_queue_head(q, skb); | ||
| 557 | } | ||
| 558 | |||
| 559 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 560 | /* Process SCO queue */ | ||
| 561 | q = __transmit_q(husb, HCI_SCODATA_PKT); | ||
| 562 | if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && | ||
| 563 | (skb = skb_dequeue(q))) { | ||
| 564 | if (hci_usb_send_isoc(husb, skb) < 0) | ||
| 565 | skb_queue_head(q, skb); | ||
| 566 | } | ||
| 567 | #endif | ||
| 568 | |||
| 569 | /* Process ACL queue */ | ||
| 570 | q = __transmit_q(husb, HCI_ACLDATA_PKT); | ||
| 571 | while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && | ||
| 572 | (skb = skb_dequeue(q))) { | ||
| 573 | if (hci_usb_send_bulk(husb, skb) < 0) { | ||
| 574 | skb_queue_head(q, skb); | ||
| 575 | break; | ||
| 576 | } | ||
| 577 | } | ||
| 578 | } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); | ||
| 579 | } | ||
| 580 | |||
| 581 | static inline void hci_usb_tx_wakeup(struct hci_usb *husb) | ||
| 582 | { | ||
| 583 | /* Serialize TX queue processing to avoid data reordering */ | ||
| 584 | if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { | ||
| 585 | hci_usb_tx_process(husb); | ||
| 586 | clear_bit(HCI_USB_TX_PROCESS, &husb->state); | ||
| 587 | } else | ||
| 588 | set_bit(HCI_USB_TX_WAKEUP, &husb->state); | ||
| 589 | } | ||
| 590 | |||
| 591 | /* Send frames from HCI layer */ | ||
| 592 | static int hci_usb_send_frame(struct sk_buff *skb) | ||
| 593 | { | ||
| 594 | struct hci_dev *hdev = (struct hci_dev *) skb->dev; | ||
| 595 | struct hci_usb *husb; | ||
| 596 | |||
| 597 | if (!hdev) { | ||
| 598 | BT_ERR("frame for uknown device (hdev=NULL)"); | ||
| 599 | return -ENODEV; | ||
| 600 | } | ||
| 601 | |||
| 602 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 603 | return -EBUSY; | ||
| 604 | |||
| 605 | BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); | ||
| 606 | |||
| 607 | husb = (struct hci_usb *) hdev->driver_data; | ||
| 608 | |||
| 609 | switch (skb->pkt_type) { | ||
| 610 | case HCI_COMMAND_PKT: | ||
| 611 | hdev->stat.cmd_tx++; | ||
| 612 | break; | ||
| 613 | |||
| 614 | case HCI_ACLDATA_PKT: | ||
| 615 | hdev->stat.acl_tx++; | ||
| 616 | break; | ||
| 617 | |||
| 618 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 619 | case HCI_SCODATA_PKT: | ||
| 620 | hdev->stat.sco_tx++; | ||
| 621 | break; | ||
| 622 | #endif | ||
| 623 | |||
| 624 | default: | ||
| 625 | kfree_skb(skb); | ||
| 626 | return 0; | ||
| 627 | } | ||
| 628 | |||
| 629 | read_lock(&husb->completion_lock); | ||
| 630 | |||
| 631 | skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb); | ||
| 632 | hci_usb_tx_wakeup(husb); | ||
| 633 | |||
| 634 | read_unlock(&husb->completion_lock); | ||
| 635 | return 0; | ||
| 636 | } | ||
| 637 | |||
| 638 | static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count) | ||
| 639 | { | ||
| 640 | BT_DBG("%s type %d data %p count %d", husb->hdev->name, type, data, count); | ||
| 641 | |||
| 642 | husb->hdev->stat.byte_rx += count; | ||
| 643 | |||
| 644 | while (count) { | ||
| 645 | struct sk_buff *skb = __reassembly(husb, type); | ||
| 646 | struct { int expect; } *scb; | ||
| 647 | int len = 0; | ||
| 648 | |||
| 649 | if (!skb) { | ||
| 650 | /* Start of the frame */ | ||
| 651 | |||
| 652 | switch (type) { | ||
| 653 | case HCI_EVENT_PKT: | ||
| 654 | if (count >= HCI_EVENT_HDR_SIZE) { | ||
| 655 | struct hci_event_hdr *h = data; | ||
| 656 | len = HCI_EVENT_HDR_SIZE + h->plen; | ||
| 657 | } else | ||
| 658 | return -EILSEQ; | ||
| 659 | break; | ||
| 660 | |||
| 661 | case HCI_ACLDATA_PKT: | ||
| 662 | if (count >= HCI_ACL_HDR_SIZE) { | ||
| 663 | struct hci_acl_hdr *h = data; | ||
| 664 | len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); | ||
| 665 | } else | ||
| 666 | return -EILSEQ; | ||
| 667 | break; | ||
| 668 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 669 | case HCI_SCODATA_PKT: | ||
| 670 | if (count >= HCI_SCO_HDR_SIZE) { | ||
| 671 | struct hci_sco_hdr *h = data; | ||
| 672 | len = HCI_SCO_HDR_SIZE + h->dlen; | ||
| 673 | } else | ||
| 674 | return -EILSEQ; | ||
| 675 | break; | ||
| 676 | #endif | ||
| 677 | } | ||
| 678 | BT_DBG("new packet len %d", len); | ||
| 679 | |||
| 680 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
| 681 | if (!skb) { | ||
| 682 | BT_ERR("%s no memory for the packet", husb->hdev->name); | ||
| 683 | return -ENOMEM; | ||
| 684 | } | ||
| 685 | skb->dev = (void *) husb->hdev; | ||
| 686 | skb->pkt_type = type; | ||
| 687 | |||
| 688 | __reassembly(husb, type) = skb; | ||
| 689 | |||
| 690 | scb = (void *) skb->cb; | ||
| 691 | scb->expect = len; | ||
| 692 | } else { | ||
| 693 | /* Continuation */ | ||
| 694 | scb = (void *) skb->cb; | ||
| 695 | len = scb->expect; | ||
| 696 | } | ||
| 697 | |||
| 698 | len = min(len, count); | ||
| 699 | |||
| 700 | memcpy(skb_put(skb, len), data, len); | ||
| 701 | |||
| 702 | scb->expect -= len; | ||
| 703 | if (!scb->expect) { | ||
| 704 | /* Complete frame */ | ||
| 705 | __reassembly(husb, type) = NULL; | ||
| 706 | hci_recv_frame(skb); | ||
| 707 | } | ||
| 708 | |||
| 709 | count -= len; data += len; | ||
| 710 | } | ||
| 711 | return 0; | ||
| 712 | } | ||
| 713 | |||
| 714 | static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs) | ||
| 715 | { | ||
| 716 | struct _urb *_urb = container_of(urb, struct _urb, urb); | ||
| 717 | struct hci_usb *husb = (void *) urb->context; | ||
| 718 | struct hci_dev *hdev = husb->hdev; | ||
| 719 | int err, count = urb->actual_length; | ||
| 720 | |||
| 721 | BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, | ||
| 722 | _urb->type, urb->status, count, urb->transfer_flags); | ||
| 723 | |||
| 724 | read_lock(&husb->completion_lock); | ||
| 725 | |||
| 726 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 727 | goto unlock; | ||
| 728 | |||
| 729 | if (urb->status || !count) | ||
| 730 | goto resubmit; | ||
| 731 | |||
| 732 | if (_urb->type == HCI_SCODATA_PKT) { | ||
| 733 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 734 | int i; | ||
| 735 | for (i=0; i < urb->number_of_packets; i++) { | ||
| 736 | BT_DBG("desc %d status %d offset %d len %d", i, | ||
| 737 | urb->iso_frame_desc[i].status, | ||
| 738 | urb->iso_frame_desc[i].offset, | ||
| 739 | urb->iso_frame_desc[i].actual_length); | ||
| 740 | |||
| 741 | if (!urb->iso_frame_desc[i].status) | ||
| 742 | __recv_frame(husb, _urb->type, | ||
| 743 | urb->transfer_buffer + urb->iso_frame_desc[i].offset, | ||
| 744 | urb->iso_frame_desc[i].actual_length); | ||
| 745 | } | ||
| 746 | #else | ||
| 747 | ; | ||
| 748 | #endif | ||
| 749 | } else { | ||
| 750 | err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count); | ||
| 751 | if (err < 0) { | ||
| 752 | BT_ERR("%s corrupted packet: type %d count %d", | ||
| 753 | husb->hdev->name, _urb->type, count); | ||
| 754 | hdev->stat.err_rx++; | ||
| 755 | } | ||
| 756 | } | ||
| 757 | |||
| 758 | resubmit: | ||
| 759 | urb->dev = husb->udev; | ||
| 760 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 761 | BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, | ||
| 762 | _urb->type, err); | ||
| 763 | |||
| 764 | unlock: | ||
| 765 | read_unlock(&husb->completion_lock); | ||
| 766 | } | ||
| 767 | |||
| 768 | static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs) | ||
| 769 | { | ||
| 770 | struct _urb *_urb = container_of(urb, struct _urb, urb); | ||
| 771 | struct hci_usb *husb = (void *) urb->context; | ||
| 772 | struct hci_dev *hdev = husb->hdev; | ||
| 773 | |||
| 774 | BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, | ||
| 775 | urb->status, urb->transfer_flags); | ||
| 776 | |||
| 777 | atomic_dec(__pending_tx(husb, _urb->type)); | ||
| 778 | |||
| 779 | urb->transfer_buffer = NULL; | ||
| 780 | kfree_skb((struct sk_buff *) _urb->priv); | ||
| 781 | |||
| 782 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 783 | return; | ||
| 784 | |||
| 785 | if (!urb->status) | ||
| 786 | hdev->stat.byte_tx += urb->transfer_buffer_length; | ||
| 787 | else | ||
| 788 | hdev->stat.err_tx++; | ||
| 789 | |||
| 790 | read_lock(&husb->completion_lock); | ||
| 791 | |||
| 792 | _urb_unlink(_urb); | ||
| 793 | _urb_queue_tail(__completed_q(husb, _urb->type), _urb); | ||
| 794 | |||
| 795 | hci_usb_tx_wakeup(husb); | ||
| 796 | |||
| 797 | read_unlock(&husb->completion_lock); | ||
| 798 | } | ||
| 799 | |||
| 800 | static void hci_usb_destruct(struct hci_dev *hdev) | ||
| 801 | { | ||
| 802 | struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; | ||
| 803 | |||
| 804 | BT_DBG("%s", hdev->name); | ||
| 805 | |||
| 806 | kfree(husb); | ||
| 807 | } | ||
| 808 | |||
| 809 | static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt) | ||
| 810 | { | ||
| 811 | BT_DBG("%s evt %d", hdev->name, evt); | ||
| 812 | } | ||
| 813 | |||
| 814 | static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
| 815 | { | ||
| 816 | struct usb_device *udev = interface_to_usbdev(intf); | ||
| 817 | struct usb_host_endpoint *bulk_out_ep = NULL; | ||
| 818 | struct usb_host_endpoint *bulk_in_ep = NULL; | ||
| 819 | struct usb_host_endpoint *intr_in_ep = NULL; | ||
| 820 | struct usb_host_endpoint *ep; | ||
| 821 | struct usb_host_interface *uif; | ||
| 822 | struct usb_interface *isoc_iface; | ||
| 823 | struct hci_usb *husb; | ||
| 824 | struct hci_dev *hdev; | ||
| 825 | int i, e, size, isoc_ifnum, isoc_alts; | ||
| 826 | |||
| 827 | BT_DBG("udev %p intf %p", udev, intf); | ||
| 828 | |||
| 829 | if (!id->driver_info) { | ||
| 830 | const struct usb_device_id *match; | ||
| 831 | match = usb_match_id(intf, blacklist_ids); | ||
| 832 | if (match) | ||
| 833 | id = match; | ||
| 834 | } | ||
| 835 | |||
| 836 | if (ignore || id->driver_info & HCI_IGNORE) | ||
| 837 | return -ENODEV; | ||
| 838 | |||
| 839 | if (intf->cur_altsetting->desc.bInterfaceNumber > 0) | ||
| 840 | return -ENODEV; | ||
| 841 | |||
| 842 | /* Find endpoints that we need */ | ||
| 843 | uif = intf->cur_altsetting; | ||
| 844 | for (e = 0; e < uif->desc.bNumEndpoints; e++) { | ||
| 845 | ep = &uif->endpoint[e]; | ||
| 846 | |||
| 847 | switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 848 | case USB_ENDPOINT_XFER_INT: | ||
| 849 | if (ep->desc.bEndpointAddress & USB_DIR_IN) | ||
| 850 | intr_in_ep = ep; | ||
| 851 | break; | ||
| 852 | |||
| 853 | case USB_ENDPOINT_XFER_BULK: | ||
| 854 | if (ep->desc.bEndpointAddress & USB_DIR_IN) | ||
| 855 | bulk_in_ep = ep; | ||
| 856 | else | ||
| 857 | bulk_out_ep = ep; | ||
| 858 | break; | ||
| 859 | } | ||
| 860 | } | ||
| 861 | |||
| 862 | if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { | ||
| 863 | BT_DBG("Bulk endpoints not found"); | ||
| 864 | goto done; | ||
| 865 | } | ||
| 866 | |||
| 867 | if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { | ||
| 868 | BT_ERR("Can't allocate: control structure"); | ||
| 869 | goto done; | ||
| 870 | } | ||
| 871 | |||
| 872 | memset(husb, 0, sizeof(struct hci_usb)); | ||
| 873 | |||
| 874 | husb->udev = udev; | ||
| 875 | husb->bulk_out_ep = bulk_out_ep; | ||
| 876 | husb->bulk_in_ep = bulk_in_ep; | ||
| 877 | husb->intr_in_ep = intr_in_ep; | ||
| 878 | |||
| 879 | if (id->driver_info & HCI_DIGIANSWER) | ||
| 880 | husb->ctrl_req = USB_TYPE_VENDOR; | ||
| 881 | else | ||
| 882 | husb->ctrl_req = USB_TYPE_CLASS; | ||
| 883 | |||
| 884 | /* Find isochronous endpoints that we can use */ | ||
| 885 | size = 0; | ||
| 886 | isoc_iface = NULL; | ||
| 887 | isoc_alts = 0; | ||
| 888 | isoc_ifnum = 1; | ||
| 889 | |||
| 890 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 891 | if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER))) | ||
| 892 | isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum); | ||
| 893 | |||
| 894 | if (isoc_iface) { | ||
| 895 | int a; | ||
| 896 | struct usb_host_endpoint *isoc_out_ep = NULL; | ||
| 897 | struct usb_host_endpoint *isoc_in_ep = NULL; | ||
| 898 | |||
| 899 | for (a = 0; a < isoc_iface->num_altsetting; a++) { | ||
| 900 | uif = &isoc_iface->altsetting[a]; | ||
| 901 | for (e = 0; e < uif->desc.bNumEndpoints; e++) { | ||
| 902 | ep = &uif->endpoint[e]; | ||
| 903 | |||
| 904 | switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 905 | case USB_ENDPOINT_XFER_ISOC: | ||
| 906 | if (le16_to_cpu(ep->desc.wMaxPacketSize) < size || | ||
| 907 | uif->desc.bAlternateSetting != isoc) | ||
| 908 | break; | ||
| 909 | size = le16_to_cpu(ep->desc.wMaxPacketSize); | ||
| 910 | |||
| 911 | isoc_alts = uif->desc.bAlternateSetting; | ||
| 912 | |||
| 913 | if (ep->desc.bEndpointAddress & USB_DIR_IN) | ||
| 914 | isoc_in_ep = ep; | ||
| 915 | else | ||
| 916 | isoc_out_ep = ep; | ||
| 917 | break; | ||
| 918 | } | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | if (!isoc_in_ep || !isoc_out_ep) | ||
| 923 | BT_DBG("Isoc endpoints not found"); | ||
| 924 | else { | ||
| 925 | BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); | ||
| 926 | if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0) | ||
| 927 | BT_ERR("Can't claim isoc interface"); | ||
| 928 | else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { | ||
| 929 | BT_ERR("Can't set isoc interface settings"); | ||
| 930 | husb->isoc_iface = isoc_iface; | ||
| 931 | usb_driver_release_interface(&hci_usb_driver, isoc_iface); | ||
| 932 | husb->isoc_iface = NULL; | ||
| 933 | } else { | ||
| 934 | husb->isoc_iface = isoc_iface; | ||
| 935 | husb->isoc_in_ep = isoc_in_ep; | ||
| 936 | husb->isoc_out_ep = isoc_out_ep; | ||
| 937 | } | ||
| 938 | } | ||
| 939 | } | ||
| 940 | #endif | ||
| 941 | |||
| 942 | rwlock_init(&husb->completion_lock); | ||
| 943 | |||
| 944 | for (i = 0; i < 4; i++) { | ||
| 945 | skb_queue_head_init(&husb->transmit_q[i]); | ||
| 946 | _urb_queue_init(&husb->pending_q[i]); | ||
| 947 | _urb_queue_init(&husb->completed_q[i]); | ||
| 948 | } | ||
| 949 | |||
| 950 | /* Initialize and register HCI device */ | ||
| 951 | hdev = hci_alloc_dev(); | ||
| 952 | if (!hdev) { | ||
| 953 | BT_ERR("Can't allocate HCI device"); | ||
| 954 | goto probe_error; | ||
| 955 | } | ||
| 956 | |||
| 957 | husb->hdev = hdev; | ||
| 958 | |||
| 959 | hdev->type = HCI_USB; | ||
| 960 | hdev->driver_data = husb; | ||
| 961 | SET_HCIDEV_DEV(hdev, &intf->dev); | ||
| 962 | |||
| 963 | hdev->open = hci_usb_open; | ||
| 964 | hdev->close = hci_usb_close; | ||
| 965 | hdev->flush = hci_usb_flush; | ||
| 966 | hdev->send = hci_usb_send_frame; | ||
| 967 | hdev->destruct = hci_usb_destruct; | ||
| 968 | hdev->notify = hci_usb_notify; | ||
| 969 | |||
| 970 | hdev->owner = THIS_MODULE; | ||
| 971 | |||
| 972 | if (reset || id->driver_info & HCI_RESET) | ||
| 973 | set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); | ||
| 974 | |||
| 975 | if (id->driver_info & HCI_SNIFFER) { | ||
| 976 | if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) | ||
| 977 | set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); | ||
| 978 | } | ||
| 979 | |||
| 980 | if (id->driver_info & HCI_BCM92035) { | ||
| 981 | unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 }; | ||
| 982 | struct sk_buff *skb; | ||
| 983 | |||
| 984 | skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); | ||
| 985 | if (skb) { | ||
| 986 | memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); | ||
| 987 | skb_queue_tail(&hdev->driver_init, skb); | ||
| 988 | } | ||
| 989 | } | ||
| 990 | |||
| 991 | if (hci_register_dev(hdev) < 0) { | ||
| 992 | BT_ERR("Can't register HCI device"); | ||
| 993 | hci_free_dev(hdev); | ||
| 994 | goto probe_error; | ||
| 995 | } | ||
| 996 | |||
| 997 | usb_set_intfdata(intf, husb); | ||
| 998 | return 0; | ||
| 999 | |||
| 1000 | probe_error: | ||
| 1001 | if (husb->isoc_iface) | ||
| 1002 | usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); | ||
| 1003 | kfree(husb); | ||
| 1004 | |||
| 1005 | done: | ||
| 1006 | return -EIO; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static void hci_usb_disconnect(struct usb_interface *intf) | ||
| 1010 | { | ||
| 1011 | struct hci_usb *husb = usb_get_intfdata(intf); | ||
| 1012 | struct hci_dev *hdev; | ||
| 1013 | |||
| 1014 | if (!husb || intf == husb->isoc_iface) | ||
| 1015 | return; | ||
| 1016 | |||
| 1017 | usb_set_intfdata(intf, NULL); | ||
| 1018 | hdev = husb->hdev; | ||
| 1019 | |||
| 1020 | BT_DBG("%s", hdev->name); | ||
| 1021 | |||
| 1022 | hci_usb_close(hdev); | ||
| 1023 | |||
| 1024 | if (husb->isoc_iface) | ||
| 1025 | usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); | ||
| 1026 | |||
| 1027 | if (hci_unregister_dev(hdev) < 0) | ||
| 1028 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 1029 | |||
| 1030 | hci_free_dev(hdev); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static struct usb_driver hci_usb_driver = { | ||
| 1034 | .owner = THIS_MODULE, | ||
| 1035 | .name = "hci_usb", | ||
| 1036 | .probe = hci_usb_probe, | ||
| 1037 | .disconnect = hci_usb_disconnect, | ||
| 1038 | .id_table = bluetooth_ids, | ||
| 1039 | }; | ||
| 1040 | |||
| 1041 | static int __init hci_usb_init(void) | ||
| 1042 | { | ||
| 1043 | int err; | ||
| 1044 | |||
| 1045 | BT_INFO("HCI USB driver ver %s", VERSION); | ||
| 1046 | |||
| 1047 | if ((err = usb_register(&hci_usb_driver)) < 0) | ||
| 1048 | BT_ERR("Failed to register HCI USB driver"); | ||
| 1049 | |||
| 1050 | return err; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static void __exit hci_usb_exit(void) | ||
| 1054 | { | ||
| 1055 | usb_deregister(&hci_usb_driver); | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | module_init(hci_usb_init); | ||
| 1059 | module_exit(hci_usb_exit); | ||
| 1060 | |||
| 1061 | module_param(ignore, bool, 0644); | ||
| 1062 | MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); | ||
| 1063 | |||
| 1064 | module_param(reset, bool, 0644); | ||
| 1065 | MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); | ||
| 1066 | |||
| 1067 | #ifdef CONFIG_BT_HCIUSB_SCO | ||
| 1068 | module_param(isoc, int, 0644); | ||
| 1069 | MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support"); | ||
| 1070 | #endif | ||
| 1071 | |||
| 1072 | MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); | ||
| 1073 | MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); | ||
| 1074 | MODULE_VERSION(VERSION); | ||
| 1075 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h new file mode 100644 index 000000000000..29936b43d4f8 --- /dev/null +++ b/drivers/bluetooth/hci_usb.h | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | /* | ||
| 2 | HCI USB driver for Linux Bluetooth protocol stack (BlueZ) | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 5 | |||
| 6 | Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 7 | |||
| 8 | This program is free software; you can redistribute it and/or modify | ||
| 9 | it under the terms of the GNU General Public License version 2 as | ||
| 10 | published by the Free Software Foundation; | ||
| 11 | |||
| 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 13 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 15 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 16 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 17 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 18 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 19 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 20 | |||
| 21 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 22 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 23 | SOFTWARE IS DISCLAIMED. | ||
| 24 | */ | ||
| 25 | |||
| 26 | /* Class, SubClass, and Protocol codes that describe a Bluetooth device */ | ||
| 27 | #define HCI_DEV_CLASS 0xe0 /* Wireless class */ | ||
| 28 | #define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ | ||
| 29 | #define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ | ||
| 30 | |||
| 31 | #define HCI_IGNORE 0x01 | ||
| 32 | #define HCI_RESET 0x02 | ||
| 33 | #define HCI_DIGIANSWER 0x04 | ||
| 34 | #define HCI_SNIFFER 0x08 | ||
| 35 | #define HCI_BROKEN_ISOC 0x10 | ||
| 36 | #define HCI_BCM92035 0x20 | ||
| 37 | |||
| 38 | #define HCI_MAX_IFACE_NUM 3 | ||
| 39 | |||
| 40 | #define HCI_MAX_BULK_TX 4 | ||
| 41 | #define HCI_MAX_BULK_RX 1 | ||
| 42 | |||
| 43 | #define HCI_MAX_ISOC_RX 2 | ||
| 44 | #define HCI_MAX_ISOC_TX 2 | ||
| 45 | |||
| 46 | #define HCI_MAX_ISOC_FRAMES 10 | ||
| 47 | |||
| 48 | struct _urb_queue { | ||
| 49 | struct list_head head; | ||
| 50 | spinlock_t lock; | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct _urb { | ||
| 54 | struct list_head list; | ||
| 55 | struct _urb_queue *queue; | ||
| 56 | int type; | ||
| 57 | void *priv; | ||
| 58 | struct urb urb; | ||
| 59 | }; | ||
| 60 | |||
| 61 | static inline void _urb_free(struct _urb *_urb) | ||
| 62 | { | ||
| 63 | kfree(_urb); | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline void _urb_queue_init(struct _urb_queue *q) | ||
| 67 | { | ||
| 68 | INIT_LIST_HEAD(&q->head); | ||
| 69 | spin_lock_init(&q->lock); | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) | ||
| 73 | { | ||
| 74 | unsigned long flags; | ||
| 75 | spin_lock_irqsave(&q->lock, flags); | ||
| 76 | list_add(&_urb->list, &q->head); _urb->queue = q; | ||
| 77 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) | ||
| 81 | { | ||
| 82 | unsigned long flags; | ||
| 83 | spin_lock_irqsave(&q->lock, flags); | ||
| 84 | list_add_tail(&_urb->list, &q->head); _urb->queue = q; | ||
| 85 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline void _urb_unlink(struct _urb *_urb) | ||
| 89 | { | ||
| 90 | struct _urb_queue *q = _urb->queue; | ||
| 91 | unsigned long flags; | ||
| 92 | if (q) { | ||
| 93 | spin_lock_irqsave(&q->lock, flags); | ||
| 94 | list_del(&_urb->list); _urb->queue = NULL; | ||
| 95 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | struct hci_usb { | ||
| 100 | struct hci_dev *hdev; | ||
| 101 | |||
| 102 | unsigned long state; | ||
| 103 | |||
| 104 | struct usb_device *udev; | ||
| 105 | |||
| 106 | struct usb_host_endpoint *bulk_in_ep; | ||
| 107 | struct usb_host_endpoint *bulk_out_ep; | ||
| 108 | struct usb_host_endpoint *intr_in_ep; | ||
| 109 | |||
| 110 | struct usb_interface *isoc_iface; | ||
| 111 | struct usb_host_endpoint *isoc_out_ep; | ||
| 112 | struct usb_host_endpoint *isoc_in_ep; | ||
| 113 | |||
| 114 | __u8 ctrl_req; | ||
| 115 | |||
| 116 | struct sk_buff_head transmit_q[4]; | ||
| 117 | struct sk_buff *reassembly[4]; /* Reassembly buffers */ | ||
| 118 | |||
| 119 | rwlock_t completion_lock; | ||
| 120 | |||
| 121 | atomic_t pending_tx[4]; /* Number of pending requests */ | ||
| 122 | struct _urb_queue pending_q[4]; /* Pending requests */ | ||
| 123 | struct _urb_queue completed_q[4]; /* Completed requests */ | ||
| 124 | }; | ||
| 125 | |||
| 126 | /* States */ | ||
| 127 | #define HCI_USB_TX_PROCESS 1 | ||
| 128 | #define HCI_USB_TX_WAKEUP 2 | ||
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c new file mode 100644 index 000000000000..3256192dcde8 --- /dev/null +++ b/drivers/bluetooth/hci_vhci.c | |||
| @@ -0,0 +1,364 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Bluetooth HCI virtual device driver. | ||
| 27 | * | ||
| 28 | * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ | ||
| 29 | */ | ||
| 30 | #define VERSION "1.1" | ||
| 31 | |||
| 32 | #include <linux/config.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | |||
| 35 | #include <linux/errno.h> | ||
| 36 | #include <linux/kernel.h> | ||
| 37 | #include <linux/major.h> | ||
| 38 | #include <linux/sched.h> | ||
| 39 | #include <linux/slab.h> | ||
| 40 | #include <linux/poll.h> | ||
| 41 | #include <linux/fcntl.h> | ||
| 42 | #include <linux/init.h> | ||
| 43 | #include <linux/random.h> | ||
| 44 | |||
| 45 | #include <linux/skbuff.h> | ||
| 46 | #include <linux/miscdevice.h> | ||
| 47 | |||
| 48 | #include <asm/system.h> | ||
| 49 | #include <asm/uaccess.h> | ||
| 50 | |||
| 51 | #include <net/bluetooth/bluetooth.h> | ||
| 52 | #include <net/bluetooth/hci_core.h> | ||
| 53 | #include "hci_vhci.h" | ||
| 54 | |||
| 55 | /* HCI device part */ | ||
| 56 | |||
| 57 | static int hci_vhci_open(struct hci_dev *hdev) | ||
| 58 | { | ||
| 59 | set_bit(HCI_RUNNING, &hdev->flags); | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int hci_vhci_flush(struct hci_dev *hdev) | ||
| 64 | { | ||
| 65 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; | ||
| 66 | skb_queue_purge(&hci_vhci->readq); | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | static int hci_vhci_close(struct hci_dev *hdev) | ||
| 71 | { | ||
| 72 | if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) | ||
| 73 | return 0; | ||
| 74 | |||
| 75 | hci_vhci_flush(hdev); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static void hci_vhci_destruct(struct hci_dev *hdev) | ||
| 80 | { | ||
| 81 | struct hci_vhci_struct *vhci; | ||
| 82 | |||
| 83 | if (!hdev) return; | ||
| 84 | |||
| 85 | vhci = (struct hci_vhci_struct *) hdev->driver_data; | ||
| 86 | kfree(vhci); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int hci_vhci_send_frame(struct sk_buff *skb) | ||
| 90 | { | ||
| 91 | struct hci_dev* hdev = (struct hci_dev *) skb->dev; | ||
| 92 | struct hci_vhci_struct *hci_vhci; | ||
| 93 | |||
| 94 | if (!hdev) { | ||
| 95 | BT_ERR("Frame for uknown device (hdev=NULL)"); | ||
| 96 | return -ENODEV; | ||
| 97 | } | ||
| 98 | |||
| 99 | if (!test_bit(HCI_RUNNING, &hdev->flags)) | ||
| 100 | return -EBUSY; | ||
| 101 | |||
| 102 | hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; | ||
| 103 | |||
| 104 | memcpy(skb_push(skb, 1), &skb->pkt_type, 1); | ||
| 105 | skb_queue_tail(&hci_vhci->readq, skb); | ||
| 106 | |||
| 107 | if (hci_vhci->flags & VHCI_FASYNC) | ||
| 108 | kill_fasync(&hci_vhci->fasync, SIGIO, POLL_IN); | ||
| 109 | wake_up_interruptible(&hci_vhci->read_wait); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* Character device part */ | ||
| 115 | |||
| 116 | /* Poll */ | ||
| 117 | static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait) | ||
| 118 | { | ||
| 119 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; | ||
| 120 | |||
| 121 | poll_wait(file, &hci_vhci->read_wait, wait); | ||
| 122 | |||
| 123 | if (skb_queue_len(&hci_vhci->readq)) | ||
| 124 | return POLLIN | POLLRDNORM; | ||
| 125 | |||
| 126 | return POLLOUT | POLLWRNORM; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Get packet from user space buffer(already verified) */ | ||
| 130 | static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const char __user *buf, size_t count) | ||
| 131 | { | ||
| 132 | struct sk_buff *skb; | ||
| 133 | |||
| 134 | if (count > HCI_MAX_FRAME_SIZE) | ||
| 135 | return -EINVAL; | ||
| 136 | |||
| 137 | if (!(skb = bt_skb_alloc(count, GFP_KERNEL))) | ||
| 138 | return -ENOMEM; | ||
| 139 | |||
| 140 | if (copy_from_user(skb_put(skb, count), buf, count)) { | ||
| 141 | kfree_skb(skb); | ||
| 142 | return -EFAULT; | ||
| 143 | } | ||
| 144 | |||
| 145 | skb->dev = (void *) hci_vhci->hdev; | ||
| 146 | skb->pkt_type = *((__u8 *) skb->data); | ||
| 147 | skb_pull(skb, 1); | ||
| 148 | |||
| 149 | hci_recv_frame(skb); | ||
| 150 | |||
| 151 | return count; | ||
| 152 | } | ||
| 153 | |||
| 154 | /* Write */ | ||
| 155 | static ssize_t hci_vhci_chr_write(struct file * file, const char __user * buf, | ||
| 156 | size_t count, loff_t *pos) | ||
| 157 | { | ||
| 158 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; | ||
| 159 | |||
| 160 | if (!access_ok(VERIFY_READ, buf, count)) | ||
| 161 | return -EFAULT; | ||
| 162 | |||
| 163 | return hci_vhci_get_user(hci_vhci, buf, count); | ||
| 164 | } | ||
| 165 | |||
| 166 | /* Put packet to user space buffer(already verified) */ | ||
| 167 | static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci, | ||
| 168 | struct sk_buff *skb, char __user *buf, | ||
| 169 | int count) | ||
| 170 | { | ||
| 171 | int len = count, total = 0; | ||
| 172 | char __user *ptr = buf; | ||
| 173 | |||
| 174 | len = min_t(unsigned int, skb->len, len); | ||
| 175 | if (copy_to_user(ptr, skb->data, len)) | ||
| 176 | return -EFAULT; | ||
| 177 | total += len; | ||
| 178 | |||
| 179 | hci_vhci->hdev->stat.byte_tx += len; | ||
| 180 | switch (skb->pkt_type) { | ||
| 181 | case HCI_COMMAND_PKT: | ||
| 182 | hci_vhci->hdev->stat.cmd_tx++; | ||
| 183 | break; | ||
| 184 | |||
| 185 | case HCI_ACLDATA_PKT: | ||
| 186 | hci_vhci->hdev->stat.acl_tx++; | ||
| 187 | break; | ||
| 188 | |||
| 189 | case HCI_SCODATA_PKT: | ||
| 190 | hci_vhci->hdev->stat.cmd_tx++; | ||
| 191 | break; | ||
| 192 | }; | ||
| 193 | |||
| 194 | return total; | ||
| 195 | } | ||
| 196 | |||
| 197 | /* Read */ | ||
| 198 | static ssize_t hci_vhci_chr_read(struct file * file, char __user * buf, size_t count, loff_t *pos) | ||
| 199 | { | ||
| 200 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; | ||
| 201 | DECLARE_WAITQUEUE(wait, current); | ||
| 202 | struct sk_buff *skb; | ||
| 203 | ssize_t ret = 0; | ||
| 204 | |||
| 205 | add_wait_queue(&hci_vhci->read_wait, &wait); | ||
| 206 | while (count) { | ||
| 207 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 208 | |||
| 209 | /* Read frames from device queue */ | ||
| 210 | if (!(skb = skb_dequeue(&hci_vhci->readq))) { | ||
| 211 | if (file->f_flags & O_NONBLOCK) { | ||
| 212 | ret = -EAGAIN; | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | if (signal_pending(current)) { | ||
| 216 | ret = -ERESTARTSYS; | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* Nothing to read, let's sleep */ | ||
| 221 | schedule(); | ||
| 222 | continue; | ||
| 223 | } | ||
| 224 | |||
| 225 | if (access_ok(VERIFY_WRITE, buf, count)) | ||
| 226 | ret = hci_vhci_put_user(hci_vhci, skb, buf, count); | ||
| 227 | else | ||
| 228 | ret = -EFAULT; | ||
| 229 | |||
| 230 | kfree_skb(skb); | ||
| 231 | break; | ||
| 232 | } | ||
| 233 | set_current_state(TASK_RUNNING); | ||
| 234 | remove_wait_queue(&hci_vhci->read_wait, &wait); | ||
| 235 | |||
| 236 | return ret; | ||
| 237 | } | ||
| 238 | |||
| 239 | static loff_t hci_vhci_chr_lseek(struct file * file, loff_t offset, int origin) | ||
| 240 | { | ||
| 241 | return -ESPIPE; | ||
| 242 | } | ||
| 243 | |||
| 244 | static int hci_vhci_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
| 245 | { | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | |||
| 249 | static int hci_vhci_chr_fasync(int fd, struct file *file, int on) | ||
| 250 | { | ||
| 251 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; | ||
| 252 | int ret; | ||
| 253 | |||
| 254 | if ((ret = fasync_helper(fd, file, on, &hci_vhci->fasync)) < 0) | ||
| 255 | return ret; | ||
| 256 | |||
| 257 | if (on) | ||
| 258 | hci_vhci->flags |= VHCI_FASYNC; | ||
| 259 | else | ||
| 260 | hci_vhci->flags &= ~VHCI_FASYNC; | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int hci_vhci_chr_open(struct inode *inode, struct file * file) | ||
| 266 | { | ||
| 267 | struct hci_vhci_struct *hci_vhci = NULL; | ||
| 268 | struct hci_dev *hdev; | ||
| 269 | |||
| 270 | if (!(hci_vhci = kmalloc(sizeof(struct hci_vhci_struct), GFP_KERNEL))) | ||
| 271 | return -ENOMEM; | ||
| 272 | |||
| 273 | memset(hci_vhci, 0, sizeof(struct hci_vhci_struct)); | ||
| 274 | |||
| 275 | skb_queue_head_init(&hci_vhci->readq); | ||
| 276 | init_waitqueue_head(&hci_vhci->read_wait); | ||
| 277 | |||
| 278 | /* Initialize and register HCI device */ | ||
| 279 | hdev = hci_alloc_dev(); | ||
| 280 | if (!hdev) { | ||
| 281 | kfree(hci_vhci); | ||
| 282 | return -ENOMEM; | ||
| 283 | } | ||
| 284 | |||
| 285 | hci_vhci->hdev = hdev; | ||
| 286 | |||
| 287 | hdev->type = HCI_VHCI; | ||
| 288 | hdev->driver_data = hci_vhci; | ||
| 289 | |||
| 290 | hdev->open = hci_vhci_open; | ||
| 291 | hdev->close = hci_vhci_close; | ||
| 292 | hdev->flush = hci_vhci_flush; | ||
| 293 | hdev->send = hci_vhci_send_frame; | ||
| 294 | hdev->destruct = hci_vhci_destruct; | ||
| 295 | |||
| 296 | hdev->owner = THIS_MODULE; | ||
| 297 | |||
| 298 | if (hci_register_dev(hdev) < 0) { | ||
| 299 | kfree(hci_vhci); | ||
| 300 | hci_free_dev(hdev); | ||
| 301 | return -EBUSY; | ||
| 302 | } | ||
| 303 | |||
| 304 | file->private_data = hci_vhci; | ||
| 305 | return nonseekable_open(inode, file); | ||
| 306 | } | ||
| 307 | |||
| 308 | static int hci_vhci_chr_close(struct inode *inode, struct file *file) | ||
| 309 | { | ||
| 310 | struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; | ||
| 311 | struct hci_dev *hdev = hci_vhci->hdev; | ||
| 312 | |||
| 313 | if (hci_unregister_dev(hdev) < 0) { | ||
| 314 | BT_ERR("Can't unregister HCI device %s", hdev->name); | ||
| 315 | } | ||
| 316 | |||
| 317 | hci_free_dev(hdev); | ||
| 318 | |||
| 319 | file->private_data = NULL; | ||
| 320 | return 0; | ||
| 321 | } | ||
| 322 | |||
| 323 | static struct file_operations hci_vhci_fops = { | ||
| 324 | .owner = THIS_MODULE, | ||
| 325 | .llseek = hci_vhci_chr_lseek, | ||
| 326 | .read = hci_vhci_chr_read, | ||
| 327 | .write = hci_vhci_chr_write, | ||
| 328 | .poll = hci_vhci_chr_poll, | ||
| 329 | .ioctl = hci_vhci_chr_ioctl, | ||
| 330 | .open = hci_vhci_chr_open, | ||
| 331 | .release = hci_vhci_chr_close, | ||
| 332 | .fasync = hci_vhci_chr_fasync | ||
| 333 | }; | ||
| 334 | |||
| 335 | static struct miscdevice hci_vhci_miscdev= | ||
| 336 | { | ||
| 337 | VHCI_MINOR, | ||
| 338 | "hci_vhci", | ||
| 339 | &hci_vhci_fops | ||
| 340 | }; | ||
| 341 | |||
| 342 | static int __init hci_vhci_init(void) | ||
| 343 | { | ||
| 344 | BT_INFO("VHCI driver ver %s", VERSION); | ||
| 345 | |||
| 346 | if (misc_register(&hci_vhci_miscdev)) { | ||
| 347 | BT_ERR("Can't register misc device %d\n", VHCI_MINOR); | ||
| 348 | return -EIO; | ||
| 349 | } | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void hci_vhci_cleanup(void) | ||
| 355 | { | ||
| 356 | misc_deregister(&hci_vhci_miscdev); | ||
| 357 | } | ||
| 358 | |||
| 359 | module_init(hci_vhci_init); | ||
| 360 | module_exit(hci_vhci_cleanup); | ||
| 361 | |||
| 362 | MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); | ||
| 363 | MODULE_DESCRIPTION("Bluetooth VHCI driver ver " VERSION); | ||
| 364 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/bluetooth/hci_vhci.h b/drivers/bluetooth/hci_vhci.h new file mode 100644 index 000000000000..53b11f9ef76d --- /dev/null +++ b/drivers/bluetooth/hci_vhci.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | BlueZ - Bluetooth protocol stack for Linux | ||
| 3 | Copyright (C) 2000-2001 Qualcomm Incorporated | ||
| 4 | |||
| 5 | Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> | ||
| 6 | |||
| 7 | This program is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License version 2 as | ||
| 9 | published by the Free Software Foundation; | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
| 12 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. | ||
| 14 | IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY | ||
| 15 | CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES | ||
| 16 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 17 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 18 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 19 | |||
| 20 | ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, | ||
| 21 | COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS | ||
| 22 | SOFTWARE IS DISCLAIMED. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* | ||
| 26 | * $Id: hci_vhci.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #ifndef __HCI_VHCI_H | ||
| 30 | #define __HCI_VHCI_H | ||
| 31 | |||
| 32 | #ifdef __KERNEL__ | ||
| 33 | |||
| 34 | struct hci_vhci_struct { | ||
| 35 | struct hci_dev *hdev; | ||
| 36 | __u32 flags; | ||
| 37 | wait_queue_head_t read_wait; | ||
| 38 | struct sk_buff_head readq; | ||
| 39 | struct fasync_struct *fasync; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* VHCI device flags */ | ||
| 43 | #define VHCI_FASYNC 0x0010 | ||
| 44 | |||
| 45 | #endif /* __KERNEL__ */ | ||
| 46 | |||
| 47 | #define VHCI_DEV "/dev/vhci" | ||
| 48 | #define VHCI_MINOR 250 | ||
| 49 | |||
| 50 | #endif /* __HCI_VHCI_H */ | ||
