From: "Christophe Leroy (CS GROUP)" <chleroy@kernel.org>
To: Ethan Nelson-Moore <enelsonmoore@gmail.com>,
linux-mips@vger.kernel.org, linux-bluetooth@vger.kernel.org
Cc: "Dominik Brodowski" <linux@dominikbrodowski.net>,
"Ondrej Zary" <linux@rainbow-software.org>,
"Russell King" <linux@armlinux.org.uk>,
"Huacai Chen" <chenhuacai@kernel.org>,
"WANG Xuerui" <kernel@xen0n.name>,
"Thomas Bogendoerfer" <tsbogend@alpha.franken.de>,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
"Michael Ellerman" <mpe@ellerman.id.au>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Marcel Holtmann" <marcel@holtmann.org>,
"Luiz Augusto von Dentz" <luiz.dentz@gmail.com>,
"Eric Biggers" <ebiggers@kernel.org>,
"Ard Biesheuvel" <ardb@kernel.org>,
"Herbert Xu" <herbert@gondor.apana.org.au>,
"Martin K. Petersen" <martin.petersen@oracle.com>,
"Theodore Ts'o" <tytso@mit.edu>,
"André Draszik" <andre.draszik@linaro.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Johannes Weiner" <hannes@cmpxchg.org>,
"Yosry Ahmed" <yosry.ahmed@linux.dev>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paul Moore" <paul@paul-moore.com>,
"Simon Horman" <horms@kernel.org>,
"Casey Schaufler" <casey@schaufler-ca.com>,
"Kuniyuki Iwashima" <kuniyu@google.com>
Subject: Re: [RFC PATCH] bluetooth: remove all PCMCIA drivers
Date: Wed, 11 Feb 2026 21:40:34 +0100 [thread overview]
Message-ID: <9085df16-4de4-49d6-9b9b-ba27367619ee@kernel.org> (raw)
In-Reply-To: <20260211082246.41148-1-enelsonmoore@gmail.com>
Le 11/02/2026 à 09:22, Ethan Nelson-Moore a écrit :
> PCMCIA is almost completely obsolete (the last computers supporting it
> natively were from ~2009), and the general consensus [1] seems to be
> that support for it should be gradually removed from the kernel.
>
> In 2023, an initial step of removing all the PCMCIA char drivers was
> taken in commit 9b12f050c76f ("char: pcmcia: remove all the drivers"),
> and that has not been reverted, so it seems logical to continue this
> process by removing more low-hanging fruit.
>
> These three Bluetooth drivers have had no meaningful changes since
> their status was discussed in 2022 [2], and are unlikely to have any
> remaining users. The latest functional change to any of them was a
> patch to bluecard_cs to fix LED blinking behavior in 2017. The other
> two drivers have not had any meaningful changes made since 2007. Remove
> them.
>
> Note that even with these drivers removed, it is still possible to use
> other PCMCIA Bluetooth cards that present themselves as a standard
> serial port via serial_cs and hciattach while the serial_cs driver is
> still present.
>
> [1] https://lore.kernel.org/all/c5b39544-a4fb-4796-a046-0b9be9853787@app.fastmail.com/
> [2] https://lore.kernel.org/all/Y07d7rMvd5++85BJ@owl.dominikbrodowski.net/
>
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> ---
> arch/arm/configs/pxa_defconfig | 3 -
> arch/arm/configs/spitz_defconfig | 3 -
> arch/loongarch/configs/loongson32_defconfig | 3 -
> arch/loongarch/configs/loongson64_defconfig | 3 -
> arch/mips/configs/mtx1_defconfig | 3 -
> arch/powerpc/configs/ppc6xx_defconfig | 3 -
Acked-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org> # powerpc/32
> drivers/bluetooth/Kconfig | 40 -
> drivers/bluetooth/Makefile | 3 -
> drivers/bluetooth/bluecard_cs.c | 908 --------------------
> drivers/bluetooth/bt3c_cs.c | 749 ----------------
> drivers/bluetooth/dtl1_cs.c | 614 -------------
> 11 files changed, 2332 deletions(-)
> delete mode 100644 drivers/bluetooth/bluecard_cs.c
> delete mode 100644 drivers/bluetooth/bt3c_cs.c
> delete mode 100644 drivers/bluetooth/dtl1_cs.c
>
> diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig
> index eacd08fd87ad..ec06f41b9df0 100644
> --- a/arch/arm/configs/pxa_defconfig
> +++ b/arch/arm/configs/pxa_defconfig
> @@ -77,9 +77,6 @@ CONFIG_BT_HCIUART_BCSP=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIBTUART=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_BT_MRVL=m
> diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig
> index c130af6d44d4..a071f579b87d 100644
> --- a/arch/arm/configs/spitz_defconfig
> +++ b/arch/arm/configs/spitz_defconfig
> @@ -62,9 +62,6 @@ CONFIG_BT_HCIUART_BCSP=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIBTUART=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_PCCARD=y
> diff --git a/arch/loongarch/configs/loongson32_defconfig b/arch/loongarch/configs/loongson32_defconfig
> index 276b1577e0be..62e16600a987 100644
> --- a/arch/loongarch/configs/loongson32_defconfig
> +++ b/arch/loongarch/configs/loongson32_defconfig
> @@ -383,9 +383,6 @@ CONFIG_BT_HCIUART_AG6XX=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_BT_MRVL=m
> CONFIG_BT_ATH3K=m
> diff --git a/arch/loongarch/configs/loongson64_defconfig b/arch/loongarch/configs/loongson64_defconfig
> index a14db1a95e7e..0124be356b8c 100644
> --- a/arch/loongarch/configs/loongson64_defconfig
> +++ b/arch/loongarch/configs/loongson64_defconfig
> @@ -399,9 +399,6 @@ CONFIG_BT_HCIUART_AG6XX=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_BT_MRVL=m
> CONFIG_BT_ATH3K=m
> diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
> index c58d1a61d528..8ed504f80530 100644
> --- a/arch/mips/configs/mtx1_defconfig
> +++ b/arch/mips/configs/mtx1_defconfig
> @@ -200,9 +200,6 @@ CONFIG_BT_HCIUART_BCSP=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_CONNECTOR=m
> CONFIG_MTD=y
> diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
> index 787d707f64a4..86812dbb4318 100644
> --- a/arch/powerpc/configs/ppc6xx_defconfig
> +++ b/arch/powerpc/configs/ppc6xx_defconfig
> @@ -287,9 +287,6 @@ CONFIG_BT_HCIUART_BCSP=y
> CONFIG_BT_HCIBCM203X=m
> CONFIG_BT_HCIBPA10X=m
> CONFIG_BT_HCIBFUSB=m
> -CONFIG_BT_HCIDTL1=m
> -CONFIG_BT_HCIBT3C=m
> -CONFIG_BT_HCIBLUECARD=m
> CONFIG_BT_HCIVHCI=m
> CONFIG_CFG80211=m
> CONFIG_MAC80211=m
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index c5d45cf91f88..c94e8833ac8e 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -337,46 +337,6 @@ config BT_HCIBFUSB
> Say Y here to compile support for HCI BFUSB devices into the
> kernel or say M to compile it as module (bfusb).
>
> -config BT_HCIDTL1
> - tristate "HCI DTL1 (PC Card) driver"
> - depends on PCMCIA && HAS_IOPORT
> - help
> - Bluetooth HCI DTL1 (PC Card) driver.
> - This driver provides support for Bluetooth PCMCIA devices with
> - Nokia DTL1 interface:
> - Nokia Bluetooth Card
> - Socket Bluetooth CF Card
> -
> - Say Y here to compile support for HCI DTL1 devices into the
> - kernel or say M to compile it as module (dtl1_cs).
> -
> -config BT_HCIBT3C
> - tristate "HCI BT3C (PC Card) driver"
> - depends on PCMCIA && HAS_IOPORT
> - select FW_LOADER
> - help
> - Bluetooth HCI BT3C (PC Card) driver.
> - This driver provides support for Bluetooth PCMCIA devices with
> - 3Com BT3C interface:
> - 3Com Bluetooth Card (3CRWB6096)
> - HP Bluetooth Card
> -
> - Say Y here to compile support for HCI BT3C devices into the
> - kernel or say M to compile it as module (bt3c_cs).
> -
> -config BT_HCIBLUECARD
> - tristate "HCI BlueCard (PC Card) driver"
> - depends on PCMCIA && HAS_IOPORT
> - help
> - Bluetooth HCI BlueCard (PC Card) driver.
> - This driver provides support for Bluetooth PCMCIA devices with
> - Anycom BlueCard interface:
> - Anycom Bluetooth PC Card
> - Anycom Bluetooth CF Card
> -
> - Say Y here to compile support for HCI BlueCard devices into the
> - kernel or say M to compile it as module (bluecard_cs).
> -
> config BT_HCIVHCI
> tristate "HCI VHCI (Virtual HCI device) driver"
> select WANT_DEV_COREDUMP
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 81856512ddd0..bafc26250b63 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -9,9 +9,6 @@ obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o
> obj-$(CONFIG_BT_HCIBCM4377) += hci_bcm4377.o
> obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o
> obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
> -obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
> -obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
> -obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
>
> obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
> obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
> diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
> deleted file mode 100644
> index 1e3a56e9b139..000000000000
> --- a/drivers/bluetooth/bluecard_cs.c
> +++ /dev/null
> @@ -1,908 +0,0 @@
> -/*
> - *
> - * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
> - *
> - * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
> - *
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation;
> - *
> - * Software distributed under the License is distributed on an "AS
> - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
> - * implied. See the License for the specific language governing
> - * rights and limitations under the License.
> - *
> - * The initial developer of the original code is David A. Hinds
> - * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
> - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
> - *
> - */
> -
> -#include <linux/module.h>
> -
> -#include <linux/kernel.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
> -#include <linux/sched.h>
> -#include <linux/delay.h>
> -#include <linux/timer.h>
> -#include <linux/errno.h>
> -#include <linux/ptrace.h>
> -#include <linux/ioport.h>
> -#include <linux/spinlock.h>
> -#include <linux/moduleparam.h>
> -#include <linux/wait.h>
> -
> -#include <linux/skbuff.h>
> -#include <linux/io.h>
> -
> -#include <pcmcia/cistpl.h>
> -#include <pcmcia/ciscode.h>
> -#include <pcmcia/ds.h>
> -#include <pcmcia/cisreg.h>
> -
> -#include <net/bluetooth/bluetooth.h>
> -#include <net/bluetooth/hci_core.h>
> -
> -
> -
> -/* ======================== Module parameters ======================== */
> -
> -
> -MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
> -MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)");
> -MODULE_LICENSE("GPL");
> -
> -
> -
> -/* ======================== Local structures ======================== */
> -
> -
> -struct bluecard_info {
> - struct pcmcia_device *p_dev;
> -
> - struct hci_dev *hdev;
> -
> - spinlock_t lock; /* For serializing operations */
> - struct timer_list timer; /* For LED control */
> -
> - struct sk_buff_head txq;
> - unsigned long tx_state;
> -
> - unsigned long rx_state;
> - unsigned long rx_count;
> - struct sk_buff *rx_skb;
> -
> - unsigned char ctrl_reg;
> - unsigned long hw_state; /* Status of the hardware and LED control */
> -};
> -
> -
> -static int bluecard_config(struct pcmcia_device *link);
> -static void bluecard_release(struct pcmcia_device *link);
> -
> -static void bluecard_detach(struct pcmcia_device *p_dev);
> -
> -
> -/* Default baud rate: 57600, 115200, 230400 or 460800 */
> -#define DEFAULT_BAUD_RATE 230400
> -
> -
> -/* Hardware states */
> -#define CARD_READY 1
> -#define CARD_ACTIVITY 2
> -#define CARD_HAS_PCCARD_ID 4
> -#define CARD_HAS_POWER_LED 5
> -#define CARD_HAS_ACTIVITY_LED 6
> -
> -/* Transmit states */
> -#define XMIT_SENDING 1
> -#define XMIT_WAKEUP 2
> -#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */
> -#define XMIT_BUF_ONE_READY 6
> -#define XMIT_BUF_TWO_READY 7
> -#define XMIT_SENDING_READY 8
> -
> -/* Receiver states */
> -#define RECV_WAIT_PACKET_TYPE 0
> -#define RECV_WAIT_EVENT_HEADER 1
> -#define RECV_WAIT_ACL_HEADER 2
> -#define RECV_WAIT_SCO_HEADER 3
> -#define RECV_WAIT_DATA 4
> -
> -/* Special packet types */
> -#define PKT_BAUD_RATE_57600 0x80
> -#define PKT_BAUD_RATE_115200 0x81
> -#define PKT_BAUD_RATE_230400 0x82
> -#define PKT_BAUD_RATE_460800 0x83
> -
> -
> -/* These are the register offsets */
> -#define REG_COMMAND 0x20
> -#define REG_INTERRUPT 0x21
> -#define REG_CONTROL 0x22
> -#define REG_RX_CONTROL 0x24
> -#define REG_CARD_RESET 0x30
> -#define REG_LED_CTRL 0x30
> -
> -/* REG_COMMAND */
> -#define REG_COMMAND_TX_BUF_ONE 0x01
> -#define REG_COMMAND_TX_BUF_TWO 0x02
> -#define REG_COMMAND_RX_BUF_ONE 0x04
> -#define REG_COMMAND_RX_BUF_TWO 0x08
> -#define REG_COMMAND_RX_WIN_ONE 0x00
> -#define REG_COMMAND_RX_WIN_TWO 0x10
> -
> -/* REG_CONTROL */
> -#define REG_CONTROL_BAUD_RATE_57600 0x00
> -#define REG_CONTROL_BAUD_RATE_115200 0x01
> -#define REG_CONTROL_BAUD_RATE_230400 0x02
> -#define REG_CONTROL_BAUD_RATE_460800 0x03
> -#define REG_CONTROL_RTS 0x04
> -#define REG_CONTROL_BT_ON 0x08
> -#define REG_CONTROL_BT_RESET 0x10
> -#define REG_CONTROL_BT_RES_PU 0x20
> -#define REG_CONTROL_INTERRUPT 0x40
> -#define REG_CONTROL_CARD_RESET 0x80
> -
> -/* REG_RX_CONTROL */
> -#define RTS_LEVEL_SHIFT_BITS 0x02
> -
> -
> -
> -/* ======================== LED handling routines ======================== */
> -
> -
> -static void bluecard_activity_led_timeout(struct timer_list *t)
> -{
> - struct bluecard_info *info = timer_container_of(info, t, timer);
> - unsigned int iobase = info->p_dev->resource[0]->start;
> -
> - if (test_bit(CARD_ACTIVITY, &(info->hw_state))) {
> - /* leave LED in inactive state for HZ/10 for blink effect */
> - clear_bit(CARD_ACTIVITY, &(info->hw_state));
> - mod_timer(&(info->timer), jiffies + HZ / 10);
> - }
> -
> - /* Disable activity LED, enable power LED */
> - outb(0x08 | 0x20, iobase + 0x30);
> -}
> -
> -
> -static void bluecard_enable_activity_led(struct bluecard_info *info)
> -{
> - unsigned int iobase = info->p_dev->resource[0]->start;
> -
> - /* don't disturb running blink timer */
> - if (timer_pending(&(info->timer)))
> - return;
> -
> - set_bit(CARD_ACTIVITY, &(info->hw_state));
> -
> - if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
> - /* Enable activity LED, keep power LED enabled */
> - outb(0x18 | 0x60, iobase + 0x30);
> - } else {
> - /* Disable power LED */
> - outb(0x00, iobase + 0x30);
> - }
> -
> - /* Stop the LED after HZ/10 */
> - mod_timer(&(info->timer), jiffies + HZ / 10);
> -}
> -
> -
> -
> -/* ======================== Interrupt handling ======================== */
> -
> -
> -static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
> -{
> - int i, actual;
> -
> - actual = (len > 15) ? 15 : len;
> -
> - outb_p(actual, iobase + offset);
> -
> - for (i = 0; i < actual; i++)
> - outb_p(buf[i], iobase + offset + i + 1);
> -
> - return actual;
> -}
> -
> -
> -static void bluecard_write_wakeup(struct bluecard_info *info)
> -{
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
> - return;
> -
> - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
> - set_bit(XMIT_WAKEUP, &(info->tx_state));
> - return;
> - }
> -
> - do {
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - unsigned int offset;
> - unsigned char command;
> - unsigned long ready_bit;
> - register struct sk_buff *skb;
> - int len;
> -
> - clear_bit(XMIT_WAKEUP, &(info->tx_state));
> -
> - if (!pcmcia_dev_present(info->p_dev))
> - return;
> -
> - if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
> - if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
> - break;
> - offset = 0x10;
> - command = REG_COMMAND_TX_BUF_TWO;
> - ready_bit = XMIT_BUF_TWO_READY;
> - } else {
> - if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
> - break;
> - offset = 0x00;
> - command = REG_COMMAND_TX_BUF_ONE;
> - ready_bit = XMIT_BUF_ONE_READY;
> - }
> -
> - skb = skb_dequeue(&(info->txq));
> - if (!skb)
> - break;
> -
> - if (hci_skb_pkt_type(skb) & 0x80) {
> - /* Disable RTS */
> - info->ctrl_reg |= REG_CONTROL_RTS;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> - }
> -
> - /* Activate LED */
> - bluecard_enable_activity_led(info);
> -
> - /* Send frame */
> - len = bluecard_write(iobase, offset, skb->data, skb->len);
> -
> - /* Tell the FPGA to send the data */
> - outb_p(command, iobase + REG_COMMAND);
> -
> - /* Mark the buffer as dirty */
> - clear_bit(ready_bit, &(info->tx_state));
> -
> - if (hci_skb_pkt_type(skb) & 0x80) {
> - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
> - DEFINE_WAIT(wait);
> -
> - unsigned char baud_reg;
> -
> - switch (hci_skb_pkt_type(skb)) {
> - case PKT_BAUD_RATE_460800:
> - baud_reg = REG_CONTROL_BAUD_RATE_460800;
> - break;
> - case PKT_BAUD_RATE_230400:
> - baud_reg = REG_CONTROL_BAUD_RATE_230400;
> - break;
> - case PKT_BAUD_RATE_115200:
> - baud_reg = REG_CONTROL_BAUD_RATE_115200;
> - break;
> - case PKT_BAUD_RATE_57600:
> - default:
> - baud_reg = REG_CONTROL_BAUD_RATE_57600;
> - break;
> - }
> -
> - /* Wait until the command reaches the baseband */
> - mdelay(100);
> -
> - /* Set baud on baseband */
> - info->ctrl_reg &= ~0x03;
> - info->ctrl_reg |= baud_reg;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Enable RTS */
> - info->ctrl_reg &= ~REG_CONTROL_RTS;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Wait before the next HCI packet can be send */
> - mdelay(1000);
> - }
> -
> - if (len == skb->len) {
> - kfree_skb(skb);
> - } else {
> - skb_pull(skb, len);
> - skb_queue_head(&(info->txq), skb);
> - }
> -
> - info->hdev->stat.byte_tx += len;
> -
> - /* Change buffer */
> - change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
> -
> - } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
> -
> - clear_bit(XMIT_SENDING, &(info->tx_state));
> -}
> -
> -
> -static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
> -{
> - int i, n, len;
> -
> - outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
> -
> - len = inb(iobase + offset);
> - n = 0;
> - i = 1;
> -
> - while (n < len) {
> -
> - if (i == 16) {
> - outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
> - i = 0;
> - }
> -
> - buf[n] = inb(iobase + offset + i);
> -
> - n++;
> - i++;
> -
> - }
> -
> - return len;
> -}
> -
> -
> -static void bluecard_receive(struct bluecard_info *info,
> - unsigned int offset)
> -{
> - unsigned int iobase;
> - unsigned char buf[31];
> - int i, len;
> -
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
> - bluecard_enable_activity_led(info);
> -
> - len = bluecard_read(iobase, offset, buf, sizeof(buf));
> -
> - for (i = 0; i < len; i++) {
> -
> - /* Allocate packet */
> - if (!info->rx_skb) {
> - info->rx_state = RECV_WAIT_PACKET_TYPE;
> - info->rx_count = 0;
> - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> - if (!info->rx_skb) {
> - BT_ERR("Can't allocate mem for new packet");
> - return;
> - }
> - }
> -
> - if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
> -
> - hci_skb_pkt_type(info->rx_skb) = buf[i];
> -
> - switch (hci_skb_pkt_type(info->rx_skb)) {
> -
> - case 0x00:
> - /* init packet */
> - if (offset != 0x00) {
> - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
> - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
> - set_bit(XMIT_SENDING_READY, &(info->tx_state));
> - bluecard_write_wakeup(info);
> - }
> -
> - kfree_skb(info->rx_skb);
> - info->rx_skb = NULL;
> - break;
> -
> - case HCI_EVENT_PKT:
> - info->rx_state = RECV_WAIT_EVENT_HEADER;
> - info->rx_count = HCI_EVENT_HDR_SIZE;
> - break;
> -
> - case HCI_ACLDATA_PKT:
> - info->rx_state = RECV_WAIT_ACL_HEADER;
> - info->rx_count = HCI_ACL_HDR_SIZE;
> - break;
> -
> - case HCI_SCODATA_PKT:
> - info->rx_state = RECV_WAIT_SCO_HEADER;
> - info->rx_count = HCI_SCO_HDR_SIZE;
> - break;
> -
> - default:
> - /* unknown packet */
> - BT_ERR("Unknown HCI packet with type 0x%02x received",
> - hci_skb_pkt_type(info->rx_skb));
> - info->hdev->stat.err_rx++;
> -
> - kfree_skb(info->rx_skb);
> - info->rx_skb = NULL;
> - break;
> -
> - }
> -
> - } else {
> -
> - skb_put_u8(info->rx_skb, buf[i]);
> - info->rx_count--;
> -
> - if (info->rx_count == 0) {
> -
> - int dlen;
> - struct hci_event_hdr *eh;
> - struct hci_acl_hdr *ah;
> - struct hci_sco_hdr *sh;
> -
> - switch (info->rx_state) {
> -
> - case RECV_WAIT_EVENT_HEADER:
> - eh = hci_event_hdr(info->rx_skb);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = eh->plen;
> - break;
> -
> - case RECV_WAIT_ACL_HEADER:
> - ah = hci_acl_hdr(info->rx_skb);
> - dlen = __le16_to_cpu(ah->dlen);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = dlen;
> - break;
> -
> - case RECV_WAIT_SCO_HEADER:
> - sh = hci_sco_hdr(info->rx_skb);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = sh->dlen;
> - break;
> -
> - case RECV_WAIT_DATA:
> - hci_recv_frame(info->hdev, info->rx_skb);
> - info->rx_skb = NULL;
> - break;
> -
> - }
> -
> - }
> -
> - }
> -
> -
> - }
> -
> - info->hdev->stat.byte_rx += len;
> -}
> -
> -
> -static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
> -{
> - struct bluecard_info *info = dev_inst;
> - unsigned int iobase;
> - unsigned char reg;
> -
> - if (!info || !info->hdev)
> - /* our irq handler is shared */
> - return IRQ_NONE;
> -
> - if (!test_bit(CARD_READY, &(info->hw_state)))
> - return IRQ_HANDLED;
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - spin_lock(&(info->lock));
> -
> - /* Disable interrupt */
> - info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - reg = inb(iobase + REG_INTERRUPT);
> -
> - if ((reg != 0x00) && (reg != 0xff)) {
> -
> - if (reg & 0x04) {
> - bluecard_receive(info, 0x00);
> - outb(0x04, iobase + REG_INTERRUPT);
> - outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
> - }
> -
> - if (reg & 0x08) {
> - bluecard_receive(info, 0x10);
> - outb(0x08, iobase + REG_INTERRUPT);
> - outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
> - }
> -
> - if (reg & 0x01) {
> - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
> - outb(0x01, iobase + REG_INTERRUPT);
> - bluecard_write_wakeup(info);
> - }
> -
> - if (reg & 0x02) {
> - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
> - outb(0x02, iobase + REG_INTERRUPT);
> - bluecard_write_wakeup(info);
> - }
> -
> - }
> -
> - /* Enable interrupt */
> - info->ctrl_reg |= REG_CONTROL_INTERRUPT;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - spin_unlock(&(info->lock));
> -
> - return IRQ_HANDLED;
> -}
> -
> -
> -
> -/* ======================== Device specific HCI commands ======================== */
> -
> -
> -static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
> -{
> - struct bluecard_info *info = hci_get_drvdata(hdev);
> - struct sk_buff *skb;
> -
> - /* Ericsson baud rate command */
> - unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
> -
> - skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_KERNEL);
> - if (!skb) {
> - BT_ERR("Can't allocate mem for new packet");
> - return -1;
> - }
> -
> - switch (baud) {
> - case 460800:
> - cmd[4] = 0x00;
> - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_460800;
> - break;
> - case 230400:
> - cmd[4] = 0x01;
> - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_230400;
> - break;
> - case 115200:
> - cmd[4] = 0x02;
> - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_115200;
> - break;
> - case 57600:
> - default:
> - cmd[4] = 0x03;
> - hci_skb_pkt_type(skb) = PKT_BAUD_RATE_57600;
> - break;
> - }
> -
> - skb_put_data(skb, cmd, sizeof(cmd));
> -
> - skb_queue_tail(&(info->txq), skb);
> -
> - bluecard_write_wakeup(info);
> -
> - return 0;
> -}
> -
> -
> -
> -/* ======================== HCI interface ======================== */
> -
> -
> -static int bluecard_hci_flush(struct hci_dev *hdev)
> -{
> - struct bluecard_info *info = hci_get_drvdata(hdev);
> -
> - /* Drop TX queue */
> - skb_queue_purge(&(info->txq));
> -
> - return 0;
> -}
> -
> -
> -static int bluecard_hci_open(struct hci_dev *hdev)
> -{
> - struct bluecard_info *info = hci_get_drvdata(hdev);
> - unsigned int iobase = info->p_dev->resource[0]->start;
> -
> - if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
> - bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
> -
> - /* Enable power LED */
> - outb(0x08 | 0x20, iobase + 0x30);
> -
> - return 0;
> -}
> -
> -
> -static int bluecard_hci_close(struct hci_dev *hdev)
> -{
> - struct bluecard_info *info = hci_get_drvdata(hdev);
> - unsigned int iobase = info->p_dev->resource[0]->start;
> -
> - bluecard_hci_flush(hdev);
> -
> - /* Stop LED timer */
> - timer_delete_sync(&(info->timer));
> -
> - /* Disable power LED */
> - outb(0x00, iobase + 0x30);
> -
> - return 0;
> -}
> -
> -
> -static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> -{
> - struct bluecard_info *info = hci_get_drvdata(hdev);
> -
> - switch (hci_skb_pkt_type(skb)) {
> - case HCI_COMMAND_PKT:
> - hdev->stat.cmd_tx++;
> - break;
> - case HCI_ACLDATA_PKT:
> - hdev->stat.acl_tx++;
> - break;
> - case HCI_SCODATA_PKT:
> - hdev->stat.sco_tx++;
> - break;
> - }
> -
> - /* Prepend skb with frame type */
> - memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
> - skb_queue_tail(&(info->txq), skb);
> -
> - bluecard_write_wakeup(info);
> -
> - return 0;
> -}
> -
> -
> -
> -/* ======================== Card services HCI interaction ======================== */
> -
> -
> -static int bluecard_open(struct bluecard_info *info)
> -{
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - struct hci_dev *hdev;
> - unsigned char id;
> -
> - spin_lock_init(&(info->lock));
> -
> - timer_setup(&info->timer, bluecard_activity_led_timeout, 0);
> -
> - skb_queue_head_init(&(info->txq));
> -
> - info->rx_state = RECV_WAIT_PACKET_TYPE;
> - info->rx_count = 0;
> - info->rx_skb = NULL;
> -
> - /* Initialize HCI device */
> - hdev = hci_alloc_dev();
> - if (!hdev) {
> - BT_ERR("Can't allocate HCI device");
> - return -ENOMEM;
> - }
> -
> - info->hdev = hdev;
> -
> - hdev->bus = HCI_PCCARD;
> - hci_set_drvdata(hdev, info);
> - SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
> -
> - hdev->open = bluecard_hci_open;
> - hdev->close = bluecard_hci_close;
> - hdev->flush = bluecard_hci_flush;
> - hdev->send = bluecard_hci_send_frame;
> -
> - id = inb(iobase + 0x30);
> -
> - if ((id & 0x0f) == 0x02)
> - set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
> -
> - if (id & 0x10)
> - set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
> -
> - if (id & 0x20)
> - set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
> -
> - /* Reset card */
> - info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Turn FPGA off */
> - outb(0x80, iobase + 0x30);
> -
> - /* Wait some time */
> - msleep(10);
> -
> - /* Turn FPGA on */
> - outb(0x00, iobase + 0x30);
> -
> - /* Activate card */
> - info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Enable interrupt */
> - outb(0xff, iobase + REG_INTERRUPT);
> - info->ctrl_reg |= REG_CONTROL_INTERRUPT;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - if ((id & 0x0f) == 0x03) {
> - /* Disable RTS */
> - info->ctrl_reg |= REG_CONTROL_RTS;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Set baud rate */
> - info->ctrl_reg |= 0x03;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Enable RTS */
> - info->ctrl_reg &= ~REG_CONTROL_RTS;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
> - set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
> - set_bit(XMIT_SENDING_READY, &(info->tx_state));
> - }
> -
> - /* Start the RX buffers */
> - outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
> - outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
> -
> - /* Signal that the hardware is ready */
> - set_bit(CARD_READY, &(info->hw_state));
> -
> - /* Drop TX queue */
> - skb_queue_purge(&(info->txq));
> -
> - /* Control the point at which RTS is enabled */
> - outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
> -
> - /* Timeout before it is safe to send the first HCI packet */
> - msleep(1250);
> -
> - /* Register HCI device */
> - if (hci_register_dev(hdev) < 0) {
> - BT_ERR("Can't register HCI device");
> - info->hdev = NULL;
> - hci_free_dev(hdev);
> - return -ENODEV;
> - }
> -
> - return 0;
> -}
> -
> -
> -static int bluecard_close(struct bluecard_info *info)
> -{
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - struct hci_dev *hdev = info->hdev;
> -
> - if (!hdev)
> - return -ENODEV;
> -
> - bluecard_hci_close(hdev);
> -
> - clear_bit(CARD_READY, &(info->hw_state));
> -
> - /* Reset card */
> - info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
> - outb(info->ctrl_reg, iobase + REG_CONTROL);
> -
> - /* Turn FPGA off */
> - outb(0x80, iobase + 0x30);
> -
> - hci_unregister_dev(hdev);
> - hci_free_dev(hdev);
> -
> - return 0;
> -}
> -
> -static int bluecard_probe(struct pcmcia_device *link)
> -{
> - struct bluecard_info *info;
> -
> - /* Create new info device */
> - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
> - if (!info)
> - return -ENOMEM;
> -
> - info->p_dev = link;
> - link->priv = info;
> -
> - link->config_flags |= CONF_ENABLE_IRQ;
> -
> - return bluecard_config(link);
> -}
> -
> -
> -static void bluecard_detach(struct pcmcia_device *link)
> -{
> - bluecard_release(link);
> -}
> -
> -
> -static int bluecard_config(struct pcmcia_device *link)
> -{
> - struct bluecard_info *info = link->priv;
> - int i, n;
> -
> - link->config_index = 0x20;
> -
> - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
> - link->resource[0]->end = 64;
> - link->io_lines = 6;
> -
> - for (n = 0; n < 0x400; n += 0x40) {
> - link->resource[0]->start = n ^ 0x300;
> - i = pcmcia_request_io(link);
> - if (i == 0)
> - break;
> - }
> -
> - if (i != 0)
> - goto failed;
> -
> - i = pcmcia_request_irq(link, bluecard_interrupt);
> - if (i != 0)
> - goto failed;
> -
> - i = pcmcia_enable_device(link);
> - if (i != 0)
> - goto failed;
> -
> - if (bluecard_open(info) != 0)
> - goto failed;
> -
> - return 0;
> -
> -failed:
> - bluecard_release(link);
> - return -ENODEV;
> -}
> -
> -
> -static void bluecard_release(struct pcmcia_device *link)
> -{
> - struct bluecard_info *info = link->priv;
> -
> - bluecard_close(info);
> -
> - timer_delete_sync(&(info->timer));
> -
> - pcmcia_disable_device(link);
> -}
> -
> -static const struct pcmcia_device_id bluecard_ids[] = {
> - PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
> - PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
> - PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
> - PCMCIA_DEVICE_NULL
> -};
> -MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
> -
> -static struct pcmcia_driver bluecard_driver = {
> - .owner = THIS_MODULE,
> - .name = "bluecard_cs",
> - .probe = bluecard_probe,
> - .remove = bluecard_detach,
> - .id_table = bluecard_ids,
> -};
> -module_pcmcia_driver(bluecard_driver);
> diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
> deleted file mode 100644
> index 54713833951a..000000000000
> --- a/drivers/bluetooth/bt3c_cs.c
> +++ /dev/null
> @@ -1,749 +0,0 @@
> -/*
> - *
> - * Driver for the 3Com Bluetooth PCMCIA card
> - *
> - * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
> - * Jose Orlando Pereira <jop@di.uminho.pt>
> - *
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation;
> - *
> - * Software distributed under the License is distributed on an "AS
> - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
> - * implied. See the License for the specific language governing
> - * rights and limitations under the License.
> - *
> - * The initial developer of the original code is David A. Hinds
> - * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
> - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
> - *
> - */
> -
> -#include <linux/module.h>
> -
> -#include <linux/kernel.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
> -#include <linux/delay.h>
> -#include <linux/errno.h>
> -#include <linux/ptrace.h>
> -#include <linux/ioport.h>
> -#include <linux/spinlock.h>
> -#include <linux/moduleparam.h>
> -
> -#include <linux/skbuff.h>
> -#include <linux/string.h>
> -#include <linux/serial.h>
> -#include <linux/serial_reg.h>
> -#include <linux/bitops.h>
> -#include <asm/io.h>
> -
> -#include <linux/device.h>
> -#include <linux/firmware.h>
> -
> -#include <pcmcia/cistpl.h>
> -#include <pcmcia/ciscode.h>
> -#include <pcmcia/ds.h>
> -#include <pcmcia/cisreg.h>
> -
> -#include <net/bluetooth/bluetooth.h>
> -#include <net/bluetooth/hci_core.h>
> -
> -
> -
> -/* ======================== Module parameters ======================== */
> -
> -
> -MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
> -MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
> -MODULE_LICENSE("GPL");
> -MODULE_FIRMWARE("BT3CPCC.bin");
> -
> -
> -
> -/* ======================== Local structures ======================== */
> -
> -
> -struct bt3c_info {
> - struct pcmcia_device *p_dev;
> -
> - struct hci_dev *hdev;
> -
> - spinlock_t lock; /* For serializing operations */
> -
> - struct sk_buff_head txq;
> - unsigned long tx_state;
> -
> - unsigned long rx_state;
> - unsigned long rx_count;
> - struct sk_buff *rx_skb;
> -};
> -
> -
> -static int bt3c_config(struct pcmcia_device *link);
> -static void bt3c_release(struct pcmcia_device *link);
> -
> -static void bt3c_detach(struct pcmcia_device *p_dev);
> -
> -
> -/* Transmit states */
> -#define XMIT_SENDING 1
> -#define XMIT_WAKEUP 2
> -#define XMIT_WAITING 8
> -
> -/* Receiver states */
> -#define RECV_WAIT_PACKET_TYPE 0
> -#define RECV_WAIT_EVENT_HEADER 1
> -#define RECV_WAIT_ACL_HEADER 2
> -#define RECV_WAIT_SCO_HEADER 3
> -#define RECV_WAIT_DATA 4
> -
> -
> -
> -/* ======================== Special I/O functions ======================== */
> -
> -
> -#define DATA_L 0
> -#define DATA_H 1
> -#define ADDR_L 2
> -#define ADDR_H 3
> -#define CONTROL 4
> -
> -
> -static inline void bt3c_address(unsigned int iobase, unsigned short addr)
> -{
> - outb(addr & 0xff, iobase + ADDR_L);
> - outb((addr >> 8) & 0xff, iobase + ADDR_H);
> -}
> -
> -
> -static inline void bt3c_put(unsigned int iobase, unsigned short value)
> -{
> - outb(value & 0xff, iobase + DATA_L);
> - outb((value >> 8) & 0xff, iobase + DATA_H);
> -}
> -
> -
> -static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
> -{
> - bt3c_address(iobase, addr);
> - bt3c_put(iobase, value);
> -}
> -
> -
> -static inline unsigned short bt3c_get(unsigned int iobase)
> -{
> - unsigned short value = inb(iobase + DATA_L);
> -
> - value |= inb(iobase + DATA_H) << 8;
> -
> - return value;
> -}
> -
> -
> -static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
> -{
> - bt3c_address(iobase, addr);
> -
> - return bt3c_get(iobase);
> -}
> -
> -
> -
> -/* ======================== Interrupt handling ======================== */
> -
> -
> -static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
> -{
> - int actual = 0;
> -
> - bt3c_address(iobase, 0x7080);
> -
> - /* Fill FIFO with current frame */
> - while (actual < len) {
> - /* Transmit next byte */
> - bt3c_put(iobase, buf[actual]);
> - actual++;
> - }
> -
> - bt3c_io_write(iobase, 0x7005, actual);
> -
> - return actual;
> -}
> -
> -
> -static void bt3c_write_wakeup(struct bt3c_info *info)
> -{
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
> - return;
> -
> - do {
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - register struct sk_buff *skb;
> - int len;
> -
> - if (!pcmcia_dev_present(info->p_dev))
> - break;
> -
> - skb = skb_dequeue(&(info->txq));
> - if (!skb) {
> - clear_bit(XMIT_SENDING, &(info->tx_state));
> - break;
> - }
> -
> - /* Send frame */
> - len = bt3c_write(iobase, 256, skb->data, skb->len);
> -
> - if (len != skb->len)
> - BT_ERR("Very strange");
> -
> - kfree_skb(skb);
> -
> - info->hdev->stat.byte_tx += len;
> -
> - } while (0);
> -}
> -
> -
> -static void bt3c_receive(struct bt3c_info *info)
> -{
> - unsigned int iobase;
> - int size = 0, avail;
> -
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - avail = bt3c_read(iobase, 0x7006);
> -
> - bt3c_address(iobase, 0x7480);
> - while (size < avail) {
> - size++;
> - info->hdev->stat.byte_rx++;
> -
> - /* Allocate packet */
> - if (!info->rx_skb) {
> - info->rx_state = RECV_WAIT_PACKET_TYPE;
> - info->rx_count = 0;
> - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> - if (!info->rx_skb) {
> - BT_ERR("Can't allocate mem for new packet");
> - return;
> - }
> - }
> -
> -
> - if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
> -
> - hci_skb_pkt_type(info->rx_skb) = inb(iobase + DATA_L);
> - inb(iobase + DATA_H);
> -
> - switch (hci_skb_pkt_type(info->rx_skb)) {
> -
> - case HCI_EVENT_PKT:
> - info->rx_state = RECV_WAIT_EVENT_HEADER;
> - info->rx_count = HCI_EVENT_HDR_SIZE;
> - break;
> -
> - case HCI_ACLDATA_PKT:
> - info->rx_state = RECV_WAIT_ACL_HEADER;
> - info->rx_count = HCI_ACL_HDR_SIZE;
> - break;
> -
> - case HCI_SCODATA_PKT:
> - info->rx_state = RECV_WAIT_SCO_HEADER;
> - info->rx_count = HCI_SCO_HDR_SIZE;
> - break;
> -
> - default:
> - /* Unknown packet */
> - BT_ERR("Unknown HCI packet with type 0x%02x received",
> - hci_skb_pkt_type(info->rx_skb));
> - info->hdev->stat.err_rx++;
> -
> - kfree_skb(info->rx_skb);
> - info->rx_skb = NULL;
> - break;
> -
> - }
> -
> - } else {
> -
> - __u8 x = inb(iobase + DATA_L);
> -
> - skb_put_u8(info->rx_skb, x);
> - inb(iobase + DATA_H);
> - info->rx_count--;
> -
> - if (info->rx_count == 0) {
> -
> - int dlen;
> - struct hci_event_hdr *eh;
> - struct hci_acl_hdr *ah;
> - struct hci_sco_hdr *sh;
> -
> - switch (info->rx_state) {
> -
> - case RECV_WAIT_EVENT_HEADER:
> - eh = hci_event_hdr(info->rx_skb);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = eh->plen;
> - break;
> -
> - case RECV_WAIT_ACL_HEADER:
> - ah = hci_acl_hdr(info->rx_skb);
> - dlen = __le16_to_cpu(ah->dlen);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = dlen;
> - break;
> -
> - case RECV_WAIT_SCO_HEADER:
> - sh = hci_sco_hdr(info->rx_skb);
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = sh->dlen;
> - break;
> -
> - case RECV_WAIT_DATA:
> - hci_recv_frame(info->hdev, info->rx_skb);
> - info->rx_skb = NULL;
> - break;
> -
> - }
> -
> - }
> -
> - }
> -
> - }
> -
> - bt3c_io_write(iobase, 0x7006, 0x0000);
> -}
> -
> -
> -static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
> -{
> - struct bt3c_info *info = dev_inst;
> - unsigned int iobase;
> - int iir;
> - irqreturn_t r = IRQ_NONE;
> -
> - if (!info || !info->hdev)
> - /* our irq handler is shared */
> - return IRQ_NONE;
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - spin_lock(&(info->lock));
> -
> - iir = inb(iobase + CONTROL);
> - if (iir & 0x80) {
> - int stat = bt3c_read(iobase, 0x7001);
> -
> - if ((stat & 0xff) == 0x7f) {
> - BT_ERR("Very strange (stat=0x%04x)", stat);
> - } else if ((stat & 0xff) != 0xff) {
> - if (stat & 0x0020) {
> - int status = bt3c_read(iobase, 0x7002) & 0x10;
> - bt_dev_info(info->hdev, "Antenna %s",
> - status ? "out" : "in");
> - }
> - if (stat & 0x0001)
> - bt3c_receive(info);
> - if (stat & 0x0002) {
> - clear_bit(XMIT_SENDING, &(info->tx_state));
> - bt3c_write_wakeup(info);
> - }
> -
> - bt3c_io_write(iobase, 0x7001, 0x0000);
> -
> - outb(iir, iobase + CONTROL);
> - }
> - r = IRQ_HANDLED;
> - }
> -
> - spin_unlock(&(info->lock));
> -
> - return r;
> -}
> -
> -
> -
> -/* ======================== HCI interface ======================== */
> -
> -
> -static int bt3c_hci_flush(struct hci_dev *hdev)
> -{
> - struct bt3c_info *info = hci_get_drvdata(hdev);
> -
> - /* Drop TX queue */
> - skb_queue_purge(&(info->txq));
> -
> - return 0;
> -}
> -
> -
> -static int bt3c_hci_open(struct hci_dev *hdev)
> -{
> - return 0;
> -}
> -
> -
> -static int bt3c_hci_close(struct hci_dev *hdev)
> -{
> - bt3c_hci_flush(hdev);
> -
> - return 0;
> -}
> -
> -
> -static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> -{
> - struct bt3c_info *info = hci_get_drvdata(hdev);
> - unsigned long flags;
> -
> - switch (hci_skb_pkt_type(skb)) {
> - case HCI_COMMAND_PKT:
> - hdev->stat.cmd_tx++;
> - break;
> - case HCI_ACLDATA_PKT:
> - hdev->stat.acl_tx++;
> - break;
> - case HCI_SCODATA_PKT:
> - hdev->stat.sco_tx++;
> - break;
> - }
> -
> - /* Prepend skb with frame type */
> - memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
> - skb_queue_tail(&(info->txq), skb);
> -
> - spin_lock_irqsave(&(info->lock), flags);
> -
> - bt3c_write_wakeup(info);
> -
> - spin_unlock_irqrestore(&(info->lock), flags);
> -
> - return 0;
> -}
> -
> -
> -
> -/* ======================== Card services HCI interaction ======================== */
> -
> -
> -static int bt3c_load_firmware(struct bt3c_info *info,
> - const unsigned char *firmware,
> - int count)
> -{
> - char *ptr = (char *) firmware;
> - char b[9];
> - unsigned int iobase, tmp, tn;
> - unsigned long size, addr, fcs;
> - int i, err = 0;
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - /* Reset */
> - bt3c_io_write(iobase, 0x8040, 0x0404);
> - bt3c_io_write(iobase, 0x8040, 0x0400);
> -
> - udelay(1);
> -
> - bt3c_io_write(iobase, 0x8040, 0x0404);
> -
> - udelay(17);
> -
> - /* Load */
> - while (count) {
> - if (ptr[0] != 'S') {
> - BT_ERR("Bad address in firmware");
> - err = -EFAULT;
> - goto error;
> - }
> -
> - memset(b, 0, sizeof(b));
> - memcpy(b, ptr + 2, 2);
> - if (kstrtoul(b, 16, &size) < 0)
> - return -EINVAL;
> -
> - memset(b, 0, sizeof(b));
> - memcpy(b, ptr + 4, 8);
> - if (kstrtoul(b, 16, &addr) < 0)
> - return -EINVAL;
> -
> - memset(b, 0, sizeof(b));
> - memcpy(b, ptr + (size * 2) + 2, 2);
> - if (kstrtoul(b, 16, &fcs) < 0)
> - return -EINVAL;
> -
> - memset(b, 0, sizeof(b));
> - for (tmp = 0, i = 0; i < size; i++) {
> - memcpy(b, ptr + (i * 2) + 2, 2);
> - if (kstrtouint(b, 16, &tn))
> - return -EINVAL;
> - tmp += tn;
> - }
> -
> - if (((tmp + fcs) & 0xff) != 0xff) {
> - BT_ERR("Checksum error in firmware");
> - err = -EILSEQ;
> - goto error;
> - }
> -
> - if (ptr[1] == '3') {
> - bt3c_address(iobase, addr);
> -
> - memset(b, 0, sizeof(b));
> - for (i = 0; i < (size - 4) / 2; i++) {
> - memcpy(b, ptr + (i * 4) + 12, 4);
> - if (kstrtouint(b, 16, &tmp))
> - return -EINVAL;
> - bt3c_put(iobase, tmp);
> - }
> - }
> -
> - ptr += (size * 2) + 6;
> - count -= (size * 2) + 6;
> - }
> -
> - udelay(17);
> -
> - /* Boot */
> - bt3c_address(iobase, 0x3000);
> - outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
> -
> -error:
> - udelay(17);
> -
> - /* Clear */
> - bt3c_io_write(iobase, 0x7006, 0x0000);
> - bt3c_io_write(iobase, 0x7005, 0x0000);
> - bt3c_io_write(iobase, 0x7001, 0x0000);
> -
> - return err;
> -}
> -
> -
> -static int bt3c_open(struct bt3c_info *info)
> -{
> - const struct firmware *firmware;
> - struct hci_dev *hdev;
> - int err;
> -
> - spin_lock_init(&(info->lock));
> -
> - skb_queue_head_init(&(info->txq));
> -
> - info->rx_state = RECV_WAIT_PACKET_TYPE;
> - info->rx_count = 0;
> - info->rx_skb = NULL;
> -
> - /* Initialize HCI device */
> - hdev = hci_alloc_dev();
> - if (!hdev) {
> - BT_ERR("Can't allocate HCI device");
> - return -ENOMEM;
> - }
> -
> - info->hdev = hdev;
> -
> - hdev->bus = HCI_PCCARD;
> - hci_set_drvdata(hdev, info);
> - SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
> -
> - hdev->open = bt3c_hci_open;
> - hdev->close = bt3c_hci_close;
> - hdev->flush = bt3c_hci_flush;
> - hdev->send = bt3c_hci_send_frame;
> -
> - /* Load firmware */
> - err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
> - if (err < 0) {
> - BT_ERR("Firmware request failed");
> - goto error;
> - }
> -
> - err = bt3c_load_firmware(info, firmware->data, firmware->size);
> -
> - release_firmware(firmware);
> -
> - if (err < 0) {
> - BT_ERR("Firmware loading failed");
> - goto error;
> - }
> -
> - /* Timeout before it is safe to send the first HCI packet */
> - msleep(1000);
> -
> - /* Register HCI device */
> - err = hci_register_dev(hdev);
> - if (err < 0) {
> - BT_ERR("Can't register HCI device");
> - goto error;
> - }
> -
> - return 0;
> -
> -error:
> - info->hdev = NULL;
> - hci_free_dev(hdev);
> - return err;
> -}
> -
> -
> -static int bt3c_close(struct bt3c_info *info)
> -{
> - struct hci_dev *hdev = info->hdev;
> -
> - if (!hdev)
> - return -ENODEV;
> -
> - bt3c_hci_close(hdev);
> -
> - hci_unregister_dev(hdev);
> - hci_free_dev(hdev);
> -
> - return 0;
> -}
> -
> -static int bt3c_probe(struct pcmcia_device *link)
> -{
> - struct bt3c_info *info;
> -
> - /* Create new info device */
> - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
> - if (!info)
> - return -ENOMEM;
> -
> - info->p_dev = link;
> - link->priv = info;
> -
> - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
> - CONF_AUTO_SET_IO;
> -
> - return bt3c_config(link);
> -}
> -
> -
> -static void bt3c_detach(struct pcmcia_device *link)
> -{
> - bt3c_release(link);
> -}
> -
> -static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
> -{
> - int *try = priv_data;
> -
> - if (!try)
> - p_dev->io_lines = 16;
> -
> - if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
> - return -EINVAL;
> -
> - p_dev->resource[0]->end = 8;
> - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
> - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
> -
> - return pcmcia_request_io(p_dev);
> -}
> -
> -static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
> - void *priv_data)
> -{
> - static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
> - int j;
> -
> - if (p_dev->io_lines > 3)
> - return -ENODEV;
> -
> - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
> - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
> - p_dev->resource[0]->end = 8;
> -
> - for (j = 0; j < 5; j++) {
> - p_dev->resource[0]->start = base[j];
> - p_dev->io_lines = base[j] ? 16 : 3;
> - if (!pcmcia_request_io(p_dev))
> - return 0;
> - }
> - return -ENODEV;
> -}
> -
> -static int bt3c_config(struct pcmcia_device *link)
> -{
> - struct bt3c_info *info = link->priv;
> - int i;
> - unsigned long try;
> -
> - /* First pass: look for a config entry that looks normal.
> - * Two tries: without IO aliases, then with aliases
> - */
> - for (try = 0; try < 2; try++)
> - if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
> - goto found_port;
> -
> - /* Second pass: try to find an entry that isn't picky about
> - * its base address, then try to grab any standard serial port
> - * address, and finally try to get any free port.
> - */
> - if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
> - goto found_port;
> -
> - BT_ERR("No usable port range found");
> - goto failed;
> -
> -found_port:
> - i = pcmcia_request_irq(link, &bt3c_interrupt);
> - if (i != 0)
> - goto failed;
> -
> - i = pcmcia_enable_device(link);
> - if (i != 0)
> - goto failed;
> -
> - if (bt3c_open(info) != 0)
> - goto failed;
> -
> - return 0;
> -
> -failed:
> - bt3c_release(link);
> - return -ENODEV;
> -}
> -
> -
> -static void bt3c_release(struct pcmcia_device *link)
> -{
> - struct bt3c_info *info = link->priv;
> -
> - bt3c_close(info);
> -
> - pcmcia_disable_device(link);
> -}
> -
> -
> -static const struct pcmcia_device_id bt3c_ids[] = {
> - PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
> - PCMCIA_DEVICE_NULL
> -};
> -MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
> -
> -static struct pcmcia_driver bt3c_driver = {
> - .owner = THIS_MODULE,
> - .name = "bt3c_cs",
> - .probe = bt3c_probe,
> - .remove = bt3c_detach,
> - .id_table = bt3c_ids,
> -};
> -module_pcmcia_driver(bt3c_driver);
> diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
> deleted file mode 100644
> index 2adfe4fade76..000000000000
> --- a/drivers/bluetooth/dtl1_cs.c
> +++ /dev/null
> @@ -1,614 +0,0 @@
> -/*
> - *
> - * A driver for Nokia Connectivity Card DTL-1 devices
> - *
> - * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
> - *
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License version 2 as
> - * published by the Free Software Foundation;
> - *
> - * Software distributed under the License is distributed on an "AS
> - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
> - * implied. See the License for the specific language governing
> - * rights and limitations under the License.
> - *
> - * The initial developer of the original code is David A. Hinds
> - * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
> - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
> - *
> - */
> -
> -#include <linux/module.h>
> -
> -#include <linux/kernel.h>
> -#include <linux/init.h>
> -#include <linux/slab.h>
> -#include <linux/types.h>
> -#include <linux/delay.h>
> -#include <linux/errno.h>
> -#include <linux/ptrace.h>
> -#include <linux/ioport.h>
> -#include <linux/spinlock.h>
> -#include <linux/moduleparam.h>
> -
> -#include <linux/skbuff.h>
> -#include <linux/string.h>
> -#include <linux/serial.h>
> -#include <linux/serial_reg.h>
> -#include <linux/bitops.h>
> -#include <asm/io.h>
> -
> -#include <pcmcia/cistpl.h>
> -#include <pcmcia/ciscode.h>
> -#include <pcmcia/ds.h>
> -#include <pcmcia/cisreg.h>
> -
> -#include <net/bluetooth/bluetooth.h>
> -#include <net/bluetooth/hci_core.h>
> -
> -
> -
> -/* ======================== Module parameters ======================== */
> -
> -
> -MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
> -MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
> -MODULE_LICENSE("GPL");
> -
> -
> -
> -/* ======================== Local structures ======================== */
> -
> -
> -struct dtl1_info {
> - struct pcmcia_device *p_dev;
> -
> - struct hci_dev *hdev;
> -
> - spinlock_t lock; /* For serializing operations */
> -
> - unsigned long flowmask; /* HCI flow mask */
> - int ri_latch;
> -
> - struct sk_buff_head txq;
> - unsigned long tx_state;
> -
> - unsigned long rx_state;
> - unsigned long rx_count;
> - struct sk_buff *rx_skb;
> -};
> -
> -
> -static int dtl1_config(struct pcmcia_device *link);
> -
> -
> -/* Transmit states */
> -#define XMIT_SENDING 1
> -#define XMIT_WAKEUP 2
> -#define XMIT_WAITING 8
> -
> -/* Receiver States */
> -#define RECV_WAIT_NSH 0
> -#define RECV_WAIT_DATA 1
> -
> -
> -struct nsh {
> - u8 type;
> - u8 zero;
> - u16 len;
> -} __packed; /* Nokia Specific Header */
> -
> -#define NSHL 4 /* Nokia Specific Header Length */
> -
> -
> -
> -/* ======================== Interrupt handling ======================== */
> -
> -
> -static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
> -{
> - int actual = 0;
> -
> - /* Tx FIFO should be empty */
> - if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
> - return 0;
> -
> - /* Fill FIFO with current frame */
> - while ((fifo_size-- > 0) && (actual < len)) {
> - /* Transmit next byte */
> - outb(buf[actual], iobase + UART_TX);
> - actual++;
> - }
> -
> - return actual;
> -}
> -
> -
> -static void dtl1_write_wakeup(struct dtl1_info *info)
> -{
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - if (test_bit(XMIT_WAITING, &(info->tx_state))) {
> - set_bit(XMIT_WAKEUP, &(info->tx_state));
> - return;
> - }
> -
> - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
> - set_bit(XMIT_WAKEUP, &(info->tx_state));
> - return;
> - }
> -
> - do {
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - register struct sk_buff *skb;
> - int len;
> -
> - clear_bit(XMIT_WAKEUP, &(info->tx_state));
> -
> - if (!pcmcia_dev_present(info->p_dev))
> - return;
> -
> - skb = skb_dequeue(&(info->txq));
> - if (!skb)
> - break;
> -
> - /* Send frame */
> - len = dtl1_write(iobase, 32, skb->data, skb->len);
> -
> - if (len == skb->len) {
> - set_bit(XMIT_WAITING, &(info->tx_state));
> - kfree_skb(skb);
> - } else {
> - skb_pull(skb, len);
> - skb_queue_head(&(info->txq), skb);
> - }
> -
> - info->hdev->stat.byte_tx += len;
> -
> - } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
> -
> - clear_bit(XMIT_SENDING, &(info->tx_state));
> -}
> -
> -
> -static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
> -{
> - u8 flowmask = *(u8 *)skb->data;
> - int i;
> -
> - printk(KERN_INFO "Bluetooth: Nokia control data =");
> - for (i = 0; i < skb->len; i++)
> - printk(" %02x", skb->data[i]);
> -
> - printk("\n");
> -
> - /* transition to active state */
> - if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
> - clear_bit(XMIT_WAITING, &(info->tx_state));
> - dtl1_write_wakeup(info);
> - }
> -
> - info->flowmask = flowmask;
> -
> - kfree_skb(skb);
> -}
> -
> -
> -static void dtl1_receive(struct dtl1_info *info)
> -{
> - unsigned int iobase;
> - struct nsh *nsh;
> - int boguscount = 0;
> -
> - if (!info) {
> - BT_ERR("Unknown device");
> - return;
> - }
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - do {
> - info->hdev->stat.byte_rx++;
> -
> - /* Allocate packet */
> - if (info->rx_skb == NULL) {
> - info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> - if (!info->rx_skb) {
> - BT_ERR("Can't allocate mem for new packet");
> - info->rx_state = RECV_WAIT_NSH;
> - info->rx_count = NSHL;
> - return;
> - }
> - }
> -
> - skb_put_u8(info->rx_skb, inb(iobase + UART_RX));
> - nsh = (struct nsh *)info->rx_skb->data;
> -
> - info->rx_count--;
> -
> - if (info->rx_count == 0) {
> -
> - switch (info->rx_state) {
> - case RECV_WAIT_NSH:
> - info->rx_state = RECV_WAIT_DATA;
> - info->rx_count = nsh->len + (nsh->len & 0x0001);
> - break;
> - case RECV_WAIT_DATA:
> - hci_skb_pkt_type(info->rx_skb) = nsh->type;
> -
> - /* remove PAD byte if it exists */
> - if (nsh->len & 0x0001) {
> - info->rx_skb->tail--;
> - info->rx_skb->len--;
> - }
> -
> - /* remove NSH */
> - skb_pull(info->rx_skb, NSHL);
> -
> - switch (hci_skb_pkt_type(info->rx_skb)) {
> - case 0x80:
> - /* control data for the Nokia Card */
> - dtl1_control(info, info->rx_skb);
> - break;
> - case 0x82:
> - case 0x83:
> - case 0x84:
> - /* send frame to the HCI layer */
> - hci_skb_pkt_type(info->rx_skb) &= 0x0f;
> - hci_recv_frame(info->hdev, info->rx_skb);
> - break;
> - default:
> - /* unknown packet */
> - BT_ERR("Unknown HCI packet with type 0x%02x received",
> - hci_skb_pkt_type(info->rx_skb));
> - kfree_skb(info->rx_skb);
> - break;
> - }
> -
> - info->rx_state = RECV_WAIT_NSH;
> - info->rx_count = NSHL;
> - info->rx_skb = NULL;
> - break;
> - }
> -
> - }
> -
> - /* Make sure we don't stay here too long */
> - if (boguscount++ > 32)
> - break;
> -
> - } while (inb(iobase + UART_LSR) & UART_LSR_DR);
> -}
> -
> -
> -static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
> -{
> - struct dtl1_info *info = dev_inst;
> - unsigned int iobase;
> - unsigned char msr;
> - int boguscount = 0;
> - int iir, lsr;
> - irqreturn_t r = IRQ_NONE;
> -
> - if (!info || !info->hdev)
> - /* our irq handler is shared */
> - return IRQ_NONE;
> -
> - iobase = info->p_dev->resource[0]->start;
> -
> - spin_lock(&(info->lock));
> -
> - iir = inb(iobase + UART_IIR) & UART_IIR_ID;
> - while (iir) {
> -
> - r = IRQ_HANDLED;
> - /* Clear interrupt */
> - lsr = inb(iobase + UART_LSR);
> -
> - switch (iir) {
> - case UART_IIR_RLSI:
> - BT_ERR("RLSI");
> - break;
> - case UART_IIR_RDI:
> - /* Receive interrupt */
> - dtl1_receive(info);
> - break;
> - case UART_IIR_THRI:
> - if (lsr & UART_LSR_THRE) {
> - /* Transmitter ready for data */
> - dtl1_write_wakeup(info);
> - }
> - break;
> - default:
> - BT_ERR("Unhandled IIR=%#x", iir);
> - break;
> - }
> -
> - /* Make sure we don't stay here too long */
> - if (boguscount++ > 100)
> - break;
> -
> - iir = inb(iobase + UART_IIR) & UART_IIR_ID;
> -
> - }
> -
> - msr = inb(iobase + UART_MSR);
> -
> - if (info->ri_latch ^ (msr & UART_MSR_RI)) {
> - info->ri_latch = msr & UART_MSR_RI;
> - clear_bit(XMIT_WAITING, &(info->tx_state));
> - dtl1_write_wakeup(info);
> - r = IRQ_HANDLED;
> - }
> -
> - spin_unlock(&(info->lock));
> -
> - return r;
> -}
> -
> -
> -
> -/* ======================== HCI interface ======================== */
> -
> -
> -static int dtl1_hci_open(struct hci_dev *hdev)
> -{
> - return 0;
> -}
> -
> -
> -static int dtl1_hci_flush(struct hci_dev *hdev)
> -{
> - struct dtl1_info *info = hci_get_drvdata(hdev);
> -
> - /* Drop TX queue */
> - skb_queue_purge(&(info->txq));
> -
> - return 0;
> -}
> -
> -
> -static int dtl1_hci_close(struct hci_dev *hdev)
> -{
> - dtl1_hci_flush(hdev);
> -
> - return 0;
> -}
> -
> -
> -static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> -{
> - struct dtl1_info *info = hci_get_drvdata(hdev);
> - struct sk_buff *s;
> - struct nsh nsh;
> -
> - switch (hci_skb_pkt_type(skb)) {
> - case HCI_COMMAND_PKT:
> - hdev->stat.cmd_tx++;
> - nsh.type = 0x81;
> - break;
> - case HCI_ACLDATA_PKT:
> - hdev->stat.acl_tx++;
> - nsh.type = 0x82;
> - break;
> - case HCI_SCODATA_PKT:
> - hdev->stat.sco_tx++;
> - nsh.type = 0x83;
> - break;
> - default:
> - return -EILSEQ;
> - }
> -
> - nsh.zero = 0;
> - nsh.len = skb->len;
> -
> - s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
> - if (!s)
> - return -ENOMEM;
> -
> - skb_reserve(s, NSHL);
> - skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
> - if (skb->len & 0x0001)
> - skb_put_u8(s, 0); /* PAD */
> -
> - /* Prepend skb with Nokia frame header and queue */
> - memcpy(skb_push(s, NSHL), &nsh, NSHL);
> - skb_queue_tail(&(info->txq), s);
> -
> - dtl1_write_wakeup(info);
> -
> - kfree_skb(skb);
> -
> - return 0;
> -}
> -
> -
> -
> -/* ======================== Card services HCI interaction ======================== */
> -
> -
> -static int dtl1_open(struct dtl1_info *info)
> -{
> - unsigned long flags;
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - struct hci_dev *hdev;
> -
> - spin_lock_init(&(info->lock));
> -
> - skb_queue_head_init(&(info->txq));
> -
> - info->rx_state = RECV_WAIT_NSH;
> - info->rx_count = NSHL;
> - info->rx_skb = NULL;
> -
> - set_bit(XMIT_WAITING, &(info->tx_state));
> -
> - /* Initialize HCI device */
> - hdev = hci_alloc_dev();
> - if (!hdev) {
> - BT_ERR("Can't allocate HCI device");
> - return -ENOMEM;
> - }
> -
> - info->hdev = hdev;
> -
> - hdev->bus = HCI_PCCARD;
> - hci_set_drvdata(hdev, info);
> - SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
> -
> - hdev->open = dtl1_hci_open;
> - hdev->close = dtl1_hci_close;
> - hdev->flush = dtl1_hci_flush;
> - hdev->send = dtl1_hci_send_frame;
> -
> - spin_lock_irqsave(&(info->lock), flags);
> -
> - /* Reset UART */
> - outb(0, iobase + UART_MCR);
> -
> - /* Turn off interrupts */
> - outb(0, iobase + UART_IER);
> -
> - /* Initialize UART */
> - outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */
> - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
> -
> - info->ri_latch = inb(info->p_dev->resource[0]->start + UART_MSR)
> - & UART_MSR_RI;
> -
> - /* Turn on interrupts */
> - outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
> -
> - spin_unlock_irqrestore(&(info->lock), flags);
> -
> - /* Timeout before it is safe to send the first HCI packet */
> - msleep(2000);
> -
> - /* Register HCI device */
> - if (hci_register_dev(hdev) < 0) {
> - BT_ERR("Can't register HCI device");
> - info->hdev = NULL;
> - hci_free_dev(hdev);
> - return -ENODEV;
> - }
> -
> - return 0;
> -}
> -
> -
> -static int dtl1_close(struct dtl1_info *info)
> -{
> - unsigned long flags;
> - unsigned int iobase = info->p_dev->resource[0]->start;
> - struct hci_dev *hdev = info->hdev;
> -
> - if (!hdev)
> - return -ENODEV;
> -
> - dtl1_hci_close(hdev);
> -
> - spin_lock_irqsave(&(info->lock), flags);
> -
> - /* Reset UART */
> - outb(0, iobase + UART_MCR);
> -
> - /* Turn off interrupts */
> - outb(0, iobase + UART_IER);
> -
> - spin_unlock_irqrestore(&(info->lock), flags);
> -
> - hci_unregister_dev(hdev);
> - hci_free_dev(hdev);
> -
> - return 0;
> -}
> -
> -static int dtl1_probe(struct pcmcia_device *link)
> -{
> - struct dtl1_info *info;
> -
> - /* Create new info device */
> - info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
> - if (!info)
> - return -ENOMEM;
> -
> - info->p_dev = link;
> - link->priv = info;
> -
> - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
> -
> - return dtl1_config(link);
> -}
> -
> -
> -static void dtl1_detach(struct pcmcia_device *link)
> -{
> - struct dtl1_info *info = link->priv;
> -
> - dtl1_close(info);
> - pcmcia_disable_device(link);
> -}
> -
> -static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
> -{
> - if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8))
> - return -ENODEV;
> -
> - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
> - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
> -
> - return pcmcia_request_io(p_dev);
> -}
> -
> -static int dtl1_config(struct pcmcia_device *link)
> -{
> - struct dtl1_info *info = link->priv;
> - int ret;
> -
> - /* Look for a generic full-sized window */
> - link->resource[0]->end = 8;
> - ret = pcmcia_loop_config(link, dtl1_confcheck, NULL);
> - if (ret)
> - goto failed;
> -
> - ret = pcmcia_request_irq(link, dtl1_interrupt);
> - if (ret)
> - goto failed;
> -
> - ret = pcmcia_enable_device(link);
> - if (ret)
> - goto failed;
> -
> - ret = dtl1_open(info);
> - if (ret)
> - goto failed;
> -
> - return 0;
> -
> -failed:
> - dtl1_detach(link);
> - return ret;
> -}
> -
> -static const struct pcmcia_device_id dtl1_ids[] = {
> - PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
> - PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
> - PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
> - PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
> - PCMCIA_DEVICE_NULL
> -};
> -MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
> -
> -static struct pcmcia_driver dtl1_driver = {
> - .owner = THIS_MODULE,
> - .name = "dtl1_cs",
> - .probe = dtl1_probe,
> - .remove = dtl1_detach,
> - .id_table = dtl1_ids,
> -};
> -module_pcmcia_driver(dtl1_driver);
prev parent reply other threads:[~2026-02-11 20:40 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-11 8:22 [RFC PATCH] bluetooth: remove all PCMCIA drivers Ethan Nelson-Moore
2026-02-11 10:02 ` Dominik Brodowski
2026-02-11 19:17 ` Luiz Augusto von Dentz
2026-02-11 11:04 ` [RFC] " bluez.test.bot
2026-02-11 20:40 ` Christophe Leroy (CS GROUP) [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9085df16-4de4-49d6-9b9b-ba27367619ee@kernel.org \
--to=chleroy@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=andre.draszik@linaro.org \
--cc=ardb@kernel.org \
--cc=casey@schaufler-ca.com \
--cc=chenhuacai@kernel.org \
--cc=ebiggers@kernel.org \
--cc=enelsonmoore@gmail.com \
--cc=hannes@cmpxchg.org \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kernel@xen0n.name \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-mips@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=linux@dominikbrodowski.net \
--cc=linux@rainbow-software.org \
--cc=luiz.dentz@gmail.com \
--cc=maddy@linux.ibm.com \
--cc=marcel@holtmann.org \
--cc=martin.petersen@oracle.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=paul@paul-moore.com \
--cc=tsbogend@alpha.franken.de \
--cc=tytso@mit.edu \
--cc=yosry.ahmed@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox